From patchwork Wed Sep 3 16:03:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ciprian Barbu X-Patchwork-Id: 36612 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qa0-f70.google.com (mail-qa0-f70.google.com [209.85.216.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 93C902039B for ; Wed, 3 Sep 2014 16:03:59 +0000 (UTC) Received: by mail-qa0-f70.google.com with SMTP id j7sf25170290qaq.9 for ; Wed, 03 Sep 2014 09:03:56 -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=rgRZaYwMNWxxKdatET0DSW4an3ttaIBL1Sakgnf8J1s=; b=JbZLOtGpAO8vZ8s/8CVrtCbTBZUaudfsqfLm1nbyKJemaSrQfzhwfxhpVmHBeTjFNO 61PetjJFTRIz2uWbfLlDqzTHaZ/Hf+C4R/IwmrJWJW1d4CfaSDktCErIhuzfuqtKjTSl ouUNoiw5Bs+rz9t23C3KiqHGx+0NZHaMq0PY9y/idwilhhLodyi0C/wa2qFbIVZIL4QI /3CpVpwCRkZJxM5LjOXE9oRNsKmQ2wQT+TA7IchFgmKAtJ8ePjGBmvEtGu8oBrSJh/yk Xw6rI0WXmxGhviEumDPjGk3txXQK14vyfYg8bNXfPGPtnpQ62uhPIJljMJ2F5TKfl0Oj 29tQ== X-Gm-Message-State: ALoCoQnIhCk/9CkZekZFCu/r/hGa2CTTWvLHo9QZbnvrrTf3Ovv7URC9ZiUderek/IDjFb2JMi7e X-Received: by 10.236.104.199 with SMTP id i47mr21652608yhg.33.1409760236077; Wed, 03 Sep 2014 09:03:56 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.20.41 with SMTP id 38ls2941412qgi.26.gmail; Wed, 03 Sep 2014 09:03:56 -0700 (PDT) X-Received: by 10.220.97.138 with SMTP id l10mr36066121vcn.25.1409760235895; Wed, 03 Sep 2014 09:03:55 -0700 (PDT) Received: from mail-vc0-f181.google.com (mail-vc0-f181.google.com [209.85.220.181]) by mx.google.com with ESMTPS id p4si3883190vcn.54.2014.09.03.09.03.55 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 03 Sep 2014 09:03:55 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.181 as permitted sender) client-ip=209.85.220.181; Received: by mail-vc0-f181.google.com with SMTP id ij19so8926617vcb.26 for ; Wed, 03 Sep 2014 09:03:55 -0700 (PDT) X-Received: by 10.220.169.72 with SMTP id x8mr1307745vcy.45.1409760235764; Wed, 03 Sep 2014 09:03:55 -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.221.45.67 with SMTP id uj3csp703071vcb; Wed, 3 Sep 2014 09:03:55 -0700 (PDT) X-Received: by 10.52.32.230 with SMTP id m6mr929854vdi.74.1409760234901; Wed, 03 Sep 2014 09:03:54 -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 6si9987562qar.91.2014.09.03.09.03.53 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Wed, 03 Sep 2014 09:03:54 -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 1XPD2G-00066N-73; Wed, 03 Sep 2014 16:03:52 +0000 Received: from mail-la0-f41.google.com ([209.85.215.41]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1XPD28-00066I-At for lng-odp@lists.linaro.org; Wed, 03 Sep 2014 16:03:44 +0000 Received: by mail-la0-f41.google.com with SMTP id gi9so10207589lab.0 for ; Wed, 03 Sep 2014 09:03:38 -0700 (PDT) X-Received: by 10.112.34.143 with SMTP id z15mr9927101lbi.86.1409760217686; Wed, 03 Sep 2014 09:03:37 -0700 (PDT) Received: from sestofb10.enea.se (sestofw01.enea.se. [192.36.1.252]) by mx.google.com with ESMTPSA id j3sm1326765lah.0.2014.09.03.09.03.36 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 03 Sep 2014 09:03:37 -0700 (PDT) From: Ciprian Barbu To: lng-odp@lists.linaro.org Date: Wed, 3 Sep 2014 18:03:31 +0200 Message-Id: <1409760211-13580-1-git-send-email-ciprian.barbu@linaro.org> X-Mailer: git-send-email 1.9.1 X-Topics: patch Subject: [lng-odp] [APPS/PATCH] Added openvswitch with ODP support 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: ciprian.barbu@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.181 as permitted sender) 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 Signed-off-by: Ciprian Barbu --- Makefile | 12 + openvswitch/Makefile | 41 + .../0001-ofpbuf-Added-OFPBUF_ODP-type.patch | 60 + ...0002-Config-options-for-building-with-ODP.patch | 172 +++ .../patches/0003-dpif-netdev-Add-ODP-netdev.patch | 1209 ++++++++++++++++++++ ...04-utilities-Add-option-to-start-with-ODP.patch | 38 + 6 files changed, 1532 insertions(+) create mode 100644 openvswitch/Makefile create mode 100644 openvswitch/patches/0001-ofpbuf-Added-OFPBUF_ODP-type.patch create mode 100644 openvswitch/patches/0002-Config-options-for-building-with-ODP.patch create mode 100644 openvswitch/patches/0003-dpif-netdev-Add-ODP-netdev.patch create mode 100644 openvswitch/patches/0004-utilities-Add-option-to-start-with-ODP.patch diff --git a/Makefile b/Makefile index 7f9b33f..faf794b 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ openvpn: odp snort: odp make -C snort +openvswitch: odp_for_ovs + make -C openvswitch + odp: if [ ! -d odp.git ]; \ then git clone http://git.linaro.org/git/lng/odp.git odp.git; \ @@ -19,7 +22,16 @@ odp: cd odp.git; patch -N -p1 < ../snort/odp-patches/0001-implement-odp_timer_disarm_all.patch cd odp.git; make libs_install CFLAGS="-fPIC" +odp_for_ovs: + if [ ! -d odp.git ]; \ + then git clone http://git.linaro.org/git/lng/odp.git odp_for_ovs; \ + fi + cd odp_for_ovs; git reset --hard 8e1bf298be449b8f91f25b96870732c433f4ddc0 + cd odp_for_ovs; ./bootstrap; ./configure CFLAGS="-fPIC"; make + distclean: rm -rf odp.git + rm -rf odp_for_ovs make -C libpcap distclean make -C openvpn distclean + make -C openvswitch distclean diff --git a/openvswitch/Makefile b/openvswitch/Makefile new file mode 100644 index 0000000..3edc664 --- /dev/null +++ b/openvswitch/Makefile @@ -0,0 +1,41 @@ +# Copyright (c) 2014, Linaro Limited +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +OPENVSWITCH_REPO=https://github.com/openvswitch/ovs.git +OPENVSWITCH_DIR=ovs +OPENVSWITCH_VERSION=1ef49150ab78f1f859bd875ce3ce7fcec778554c + +ODP_DIR ?= $(CURDIR)/../odp_for_ovs + + +.PHONY: all +all: openvswitch + +.PHONY: update +update: get_openvswitch + +.PHONY: install +install: install_openvswitch + +.PHONY: clean +clean: clean_openvswitch + +.PHONY: openvswitch +openvswitch: get_openvswitch + cd $(OPENVSWITCH_DIR) \ + && git checkout $(OPENVSWITCH_VERSION) \ + && git am ../patches/*.patch \ + && ./boot.sh \ + && ./configure --with-odp=$(ODP_DIR) \ + && make + +.PHONY: get_openvswitch +get_openvswitch: + if [ ! -d $(OPENVSWITCH_DIR) ]; then git clone $(OPENVSWITCH_REPO) $(OPENVSWITCH_DIR); \ + else cd $(OPENVSWITCH_DIR); git fetch --all; fi + +.PHONY: distclean +distclean: + rm -rf $(OPENVSWITCH_DIR) diff --git a/openvswitch/patches/0001-ofpbuf-Added-OFPBUF_ODP-type.patch b/openvswitch/patches/0001-ofpbuf-Added-OFPBUF_ODP-type.patch new file mode 100644 index 0000000..61c4e89 --- /dev/null +++ b/openvswitch/patches/0001-ofpbuf-Added-OFPBUF_ODP-type.patch @@ -0,0 +1,60 @@ +From 150d0dae780427865e6811c77169d7865530c22f Mon Sep 17 00:00:00 2001 +From: Ciprian Barbu +Date: Mon, 18 Aug 2014 17:49:56 +0300 +Subject: [PATCH 1/4] ofpbuf: Added OFPBUF_ODP type. + +This will be used by ODP for zero copy IO. + +Signed-off-by: Ciprian Barbu +--- + lib/ofpbuf.c | 6 ++++-- + lib/ofpbuf.h | 2 ++ + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c +index 198bbf6..28013d5 100644 +--- a/lib/ofpbuf.c ++++ b/lib/ofpbuf.c +@@ -251,6 +251,8 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom) + new_allocated = new_headroom + ofpbuf_size(b) + new_tailroom; + + switch (b->source) { ++ case OFPBUF_ODP: ++ OVS_NOT_REACHED(); + case OFPBUF_DPDK: + OVS_NOT_REACHED(); + +@@ -321,7 +323,7 @@ ofpbuf_prealloc_headroom(struct ofpbuf *b, size_t size) + void + ofpbuf_trim(struct ofpbuf *b) + { +- ovs_assert(b->source != OFPBUF_DPDK); ++ ovs_assert(b->source != OFPBUF_DPDK && b->source != OFPBUF_ODP); + + if (b->source == OFPBUF_MALLOC + && (ofpbuf_headroom(b) || ofpbuf_tailroom(b))) { +@@ -481,7 +483,7 @@ void * + ofpbuf_steal_data(struct ofpbuf *b) + { + void *p; +- ovs_assert(b->source != OFPBUF_DPDK); ++ ovs_assert(b->source != OFPBUF_DPDK && b->source != OFPBUF_ODP); + + if (b->source == OFPBUF_MALLOC && ofpbuf_data(b) == ofpbuf_base(b)) { + p = ofpbuf_data(b); +diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h +index adaf526..6af9c64 100644 +--- a/lib/ofpbuf.h ++++ b/lib/ofpbuf.h +@@ -34,6 +34,8 @@ enum OVS_PACKED_ENUM ofpbuf_source { + OFPBUF_STUB, /* Starts on stack, may expand into heap. */ + OFPBUF_DPDK, /* buffer data is from DPDK allocated memory. + ref to build_ofpbuf() in netdev-dpdk. */ ++ OFPBUF_ODP, /* buffer data is from DPDK allocated memory. ++ ref to build_ofpbuf() in netdev-odp. */ + }; + + /* Buffer for holding arbitrary data. An ofpbuf is automatically reallocated +-- +1.8.3.2 + diff --git a/openvswitch/patches/0002-Config-options-for-building-with-ODP.patch b/openvswitch/patches/0002-Config-options-for-building-with-ODP.patch new file mode 100644 index 0000000..57a4c87 --- /dev/null +++ b/openvswitch/patches/0002-Config-options-for-building-with-ODP.patch @@ -0,0 +1,172 @@ +From 90e50e6b09d1bc64572b3c4c450df4d9e7e80526 Mon Sep 17 00:00:00 2001 +From: Ciprian Barbu +Date: Mon, 18 Aug 2014 20:09:24 +0300 +Subject: [PATCH 2/4] Config options for building with ODP + +Signed-off-by: Ciprian Barbu +--- + Makefile.am | 1 + + acinclude.m4 | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + configure.ac | 2 ++ + lib/automake.mk | 6 ++++ + 4 files changed, 112 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index eb58101..8ac933d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -70,6 +70,7 @@ EXTRA_DIST = \ + INSTALL.KVM \ + INSTALL.Libvirt \ + INSTALL.NetBSD \ ++ INSTALL.ODP \ + INSTALL.RHEL \ + INSTALL.SSL \ + INSTALL.XenServer \ +diff --git a/acinclude.m4 b/acinclude.m4 +index 7e036e5..533ed98 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -218,6 +218,109 @@ AC_DEFUN([OVS_CHECK_DPDK], [ + AM_CONDITIONAL([DPDK_NETDEV], test -n "$RTE_SDK") + ]) + ++dnl OVS_CHECK_ODP_PLATFORM ++dnl ++dnl Configure ODP platform ++AC_DEFUN([OVS_CHECK_ODP_PLATFORM], [ ++ AC_MSG_CHECKING([for ODP Platform]) ++ ++ ODP_PLATFORM=linux-generic ++ ++ AC_ARG_WITH([odp-platform], ++ [AC_HELP_STRING([--with-odp-platform=[@<:@odp-platform@:>@]], ++ [ODP platform to use; default is linux-generic])], ++ [ ++ if test X"$withval" != X; then ++ ODP_PLATFORM=$withval ++ fi ++ ] ++ ) ++ AC_MSG_RESULT([$ODP_PLATFORM]) ++]) ++ ++dnl OVS_CHECK_ODP ++dnl ++dnl Configure ODP source tree ++AC_DEFUN([OVS_CHECK_ODP], [ ++ AC_MSG_CHECKING([for ODP]) ++ ++ AC_ARG_WITH([odp], ++ [AC_HELP_STRING([--with-odp=[@<:@DIR | yes | no@:>@]], ++ [Specify the ODP build directory or system default])], ++ [ ++ case "$withval" in ++ "" | n | no) ++ with_odp="" ++ ;; ++ y | ye | yes) ++ ODP=yes ++ ;; ++ *) ++ ODP=$withval ++ if test -f "$ODP/platform/linux-generic/include/api/odp.h" ; then ++ ODP_INCLUDE=$ODP/include ++ ODP_LINUX_GENERIC_INCLUDE=$ODP/platform/linux-generic/include/api ++ ODP_PLATFORM_INCLUDE=$ODP/platform/$ODP_PLATFORM/include/api ++ else ++ AC_MSG_ERROR([cannot find ODP headers]) ++ fi ++ ++ if test -f "${ODP}/lib/libodp.a" ; then ++ ODP_LIB_DIR="${ODP}/lib" ++ elif test -f "${ODP}/lib/.libs/libodp.a" ; then ++ ODP_LIB_DIR="${ODP}/lib/.libs" ++ else ++ AC_MSG_ERROR([cannot find ODP lib]) ++ fi ++ ++ AC_SUBST([ODP_INCLUDE]) ++ AC_SUBST([ODP_LINUX_GENERIC_INCLUDE]) ++ AC_SUBST([ODP_PLATFORM_INCLUDE]) ++ AC_SUBST([ODP_PLATFORM_INCLUDE_API]) ++ AC_SUBST([ODP_LIB_DIR]) ++ CFLAGS="$CFLAGS -I$ODP_PLATFORM_INCLUDE -I$ODP_LINUX_GENERIC_INCLUDE -I$ODP_INCLUDE" ++ LDFLAGS="$LDFLAGS -L$ODP_LIB_DIR" ++ ;; ++ esac ++ ] ++ ) ++ ++ if test X"$with_odp" != X; then ++ # On some systems we have to add -ldl to link with ODP ++ # ++ # This code, at first, tries to link without -ldl (""), ++ # then adds it and tries again. ++ # Before each attempt the search cache must be unset, ++ # otherwise autoconf will stick with the old result ++ ++ found=false ++ LIBS="$LIBS -lssl -lcrypto" ++ save_LIBS="$LIBS" ++ for extras in "" "-ldl"; do ++ LIBS="-lodp $extras $save_LIBS" ++ AC_LINK_IFELSE( ++ [AC_LANG_PROGRAM([#include ], ++ [odp_init_global();])], ++ [found=true]) ++ if $found; then ++ break ++ fi ++ done ++ if $found; then ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_ERROR([cannot link with ODP]) ++ fi ++ ++ AC_DEFINE([ODP_NETDEV], [1], [System uses the ODP module.]) ++ else ++ ODP= ++ AC_MSG_RESULT([no]) ++ fi ++ ++ AM_CONDITIONAL([ODP_NETDEV], test -n "$ODP") ++]) ++ + dnl OVS_GREP_IFELSE(FILE, REGEX, [IF-MATCH], [IF-NO-MATCH]) + dnl + dnl Greps FILE for REGEX. If it matches, runs IF-MATCH, otherwise IF-NO-MATCH. +diff --git a/configure.ac b/configure.ac +index 971c7b3..e7be627 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -120,6 +120,8 @@ AC_ARG_VAR(KARCH, [Kernel Architecture String]) + AC_SUBST(KARCH) + OVS_CHECK_LINUX + OVS_CHECK_DPDK ++OVS_CHECK_ODP_PLATFORM ++OVS_CHECK_ODP + + AC_CONFIG_FILES(Makefile) + AC_CONFIG_FILES(datapath/Makefile) +diff --git a/lib/automake.mk b/lib/automake.mk +index d46613f..a264b97 100644 +--- a/lib/automake.mk ++++ b/lib/automake.mk +@@ -324,6 +324,12 @@ lib_libopenvswitch_la_SOURCES += \ + lib/netdev-dpdk.h + endif + ++if ODP_NETDEV ++lib_libopenvswitch_la_SOURCES += \ ++ lib/netdev-odp.c \ ++ lib/netdev-odp.h ++endif ++ + if WIN32 + lib_libopenvswitch_la_SOURCES += \ + lib/netlink-notifier.c \ +-- +1.8.3.2 + diff --git a/openvswitch/patches/0003-dpif-netdev-Add-ODP-netdev.patch b/openvswitch/patches/0003-dpif-netdev-Add-ODP-netdev.patch new file mode 100644 index 0000000..36c6b17 --- /dev/null +++ b/openvswitch/patches/0003-dpif-netdev-Add-ODP-netdev.patch @@ -0,0 +1,1209 @@ +From 3278a5a0f99f2a738496e3194c30bd859f401aee Mon Sep 17 00:00:00 2001 +From: Ciprian Barbu +Date: Tue, 19 Aug 2014 14:45:04 +0300 +Subject: [PATCH 3/4] dpif-netdev: Add ODP netdev + +Signed-off-by: Ciprian Barbu +--- + INSTALL | 1 + + INSTALL.ODP | 143 ++++++++++ + lib/netdev-odp.c | 742 ++++++++++++++++++++++++++++++++++++++++++++++++ + lib/netdev-odp.h | 39 +++ + lib/netdev.c | 8 +- + lib/ofpbuf.c | 16 ++ + lib/ofpbuf.h | 51 ++++ + vswitchd/ovs-vswitchd.c | 11 + + 8 files changed, 1010 insertions(+), 1 deletion(-) + create mode 100644 INSTALL.ODP + create mode 100644 lib/netdev-odp.c + create mode 100644 lib/netdev-odp.h + +diff --git a/INSTALL b/INSTALL +index 7e0097b..7d0bcf3 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -11,6 +11,7 @@ on a specific platform, please see one of these files: + - INSTALL.XenServer + - INSTALL.NetBSD + - INSTALL.DPDK ++ - INSTALL.ODP + + Build Requirements + ------------------ +diff --git a/INSTALL.ODP b/INSTALL.ODP +new file mode 100644 +index 0000000..9c36dd1 +--- /dev/null ++++ b/INSTALL.ODP +@@ -0,0 +1,143 @@ ++ Using Open vSwitch with ODP ++ =========================== ++ ++ ++Open vSwitch can be used with the ODP project (http://www.opendataplane.org) ++The switch will function entirely in userspace. This file serves as a guide for ++building and installing Open vSwitch with ODP. ++ ++The ODP mode is considered experimental, it has not been thoroughly tested. ++ ++This version of Open vSwitch should be built manually with "configure" and ++"make". ++ ++ ++Building and Installing: ++------------------------ ++Below are a set of steps to help you build OVS on top of ODP for linux-generic ++using basic sockets. It should be possible to compile with ODP for other ++platforms but it hasn't been tested yet. ++ ++ODP: ++============= ++Get the code: ++ git clone http://git.linaro.org/git/lng/odp.git ++ cd odp ++ ./bootstrap.sh ++ ++it is recommended to disable building shared library because then launching ++ovs with sudo becomes a real pain ++ ./configure --enable-debug --enable-shared=no ++ ++to get debug symbols you can ++ ./configure --enable-debug CFLAGS="-g -O0" --enable-shared=no ++ ++ make ++ ++optionally: ++ make install ++ ++OVS: ++============= ++ ./boot.sh ++ ./configure --with-odp= ++ ++to specify a different ODP platform you can use: ++ ./configure --with-odp= --with-odp-platform= ++ ++if you installed ODP you can simply ++ ./configure --with-odp=yes ++ make ++ ++Refer to INSTALL.userspace for general requirements of building userspace OVS. ++ ++Alternatively go to https://wiki.linaro.org/LNG/Engineering/OVSDPDKOnUbuntu ++which explains how to run OVS with DPDK. Similar steps should work with ODP. ++ ++Using ODP with ovs-vswitchd: ++---------------------------- ++ ++Start ovsdb-server as discussed in INSTALL doc: ++ Summary e.g.: ++ First time only db creation (or clearing): ++ mkdir -p /usr/local/etc/openvswitch ++ mkdir -p /usr/local/var/run/openvswitch ++ rm /usr/local/etc/openvswitch/conf.db ++ cd $OVS_DIR ++ ./ovsdb/ovsdb-tool create /usr/local/etc/openvswitch/conf.db \ ++ ./vswitchd/vswitch.ovsschema ++ start ovsdb-server ++ cd $OVS_DIR ++ ./ovsdb/ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock \ ++ --remote=db:OpenOpen_vSwitch,manager_options \ ++ --private-key=db:Open_vSwitch,SSL,private_key \ ++ --certificate=dbitch,SSL,certificate \ ++ --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --pidfile --detach ++ First time after db creation, initialize: ++ cd $OVS_DIR ++ ./utilities/ovs-vsctl --no-wait init ++ ++Start vswitchd: ++ODP configuration arguments can be passed to vswitchd via `--odp`. ++For the moment no arguments are available, but is recommended to pass --odp. ++ ++ e.g. ++ export DB_SOCK=/usr/local/var/run/openvswitch/db.sock ++ ./vswitchd/ovs-vswitch --odp -- unix:$DB_SOCK --pidfile --detach ++ ++To use ovs-vswitchd with ODP, create a bridge with datapath_type ++"netdev" in the configuration database. For example: ++ ++ ovs-vsctl add-br br0 ++ ovs-vsctl set bridge br0 datapath_type=netdev ++ ++Now you can add ODP ports. OVS expect ODP port name to start with odp ++followed by a colon and then the interface name. ++ ++ ovs-vsctl add-port br0 odp:eth0 -- set Interface odp:eth0 type=odp ++ ++Simple test ++----------- ++A simple test would be to add one ODP virtual port and one internal port. ++To make sure that packets arrived on the the ODP virtual port don't come ++through the Linux interface as well you need to remove the IP address from ++the Linux interface. Also set the interface to promisc mode, in case packets ++get rejected otherwise: ++ ++ ifconfig eth0 0 promisc ++ ++Bring up the bridge internal port and assign some ip (DHCP should work too ++if present): ++ ++ ifconfig br0 up ++ dhcp br0 ++ ++Then run tests as usual, simple ping from another machine, iperf etc. ++Packets should arrive at the physical interface, then at the ODP virtual ++port then forwarded to the br0 internal port and then to the Linux stack. ++ ++You can also set up two ODP virtual ports and let the machine run like a ++regular switch, without involving the Linux IP stack. ++ ++Testing using flows ++------------------- ++For testing you can setup flows from an ODP virtual port to another port, ++an internal port for example. Using an internal port is preferred, because ++no other packets will be involed, only what comes from the ODP port. ++ ++First run ovs-ofctl to get the port ids: ++ ovs-ofctl show br0 ++ ++To remove all flows: ++ ovs-ofctl del-flows br0 ++ ++Then add a flow to direct packets comming at the ODP port to an internal port. ++ ovs-ofctl add-flow br0 in_port=1,action=output:LOCAL ++ ++Then you can use tcpdump / wireshark to sniff packets on the LOCAL port. ++You might need to bring the virtual interface up: ++ ifconfig br0 up ++ ++A simple test would be to use ping. In this case you should only see the ++ICMP requests showing up at the LOCAL port. Also delete the flow and check that ++packets are not forwarded anymore. +diff --git a/lib/netdev-odp.c b/lib/netdev-odp.c +new file mode 100644 +index 0000000..785dc06 +--- /dev/null ++++ b/lib/netdev-odp.c +@@ -0,0 +1,742 @@ ++/* ++ * Copyright (c) 2014 Nicira, Inc. ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dpif-netdev.h" ++#include "list.h" ++#include "netdev-odp.h" ++#include "netdev-provider.h" ++#include "netdev-vport.h" ++#include "odp-util.h" ++#include "ofp-print.h" ++#include "ofpbuf.h" ++#include "ovs-thread.h" ++#include "ovs-rcu.h" ++#include "packet-dpif.h" ++#include "packets.h" ++#include "shash.h" ++#include "sset.h" ++#include "unaligned.h" ++#include "timeval.h" ++#include "unixctl.h" ++#include "vlog.h" ++ ++VLOG_DEFINE_THIS_MODULE(odp); ++ ++#define SHM_PKT_POOL_SIZE (512*2048) ++#define SHM_PKT_POOL_BUF_SIZE 1856 ++ ++#define SHM_OFPBUF_POOL_SIZE (512*256) ++#define SHM_OFPBUF_POOL_BUF_SIZE sizeof(struct dpif_packet) ++ ++static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); ++ ++static odp_buffer_pool_t pool; ++static odp_buffer_pool_t ofpbuf_pool; ++static odp_buffer_pool_t struct_pool; ++ ++static int odp_initialized = 0; ++ ++struct netdev_odp { ++ struct netdev up; ++ odp_buffer_t odp_buf; /* odp_buffer_t that holds this struct */ ++ odp_pktio_t pktio; ++ odp_buffer_pool_t pkt_pool; ++ size_t frame_offset; ++ size_t max_frame_len; ++ ++ struct ovs_mutex mutex OVS_ACQ_AFTER(odp_mutex); ++ ++ uint8_t hwaddr[ETH_ADDR_LEN]; ++ enum netdev_flags flags; ++ ++ struct netdev_stats stats; ++}; ++ ++struct netdev_rxq_odp { ++ struct netdev_rxq up; ++ odp_buffer_t odp_buf; /* odp_buffer_t that holds this struct */ ++ odp_queue_t queue_id; ++}; ++ ++/* We need a pool of buffers that hold netdev and rxq structures */ ++#define STRUCTS_SIZE MAX(sizeof(struct netdev_odp), \ ++ sizeof(struct netdev_rxq_odp)) ++#define SHM_STRUCT_POOL_SIZE (512 * (STRUCTS_SIZE)) ++#define SHM_STRUCT_POOL_BUF_SIZE STRUCTS_SIZE ++ ++void ++free_odp_buf(struct ofpbuf *b) ++{ ++ odp_packet_free(b->odp_pkt); ++ odp_buffer_free(b->odp_ofpbuf); ++} ++ ++int ++odp_init(int argc, char *argv[]) ++{ ++ int result; ++ int thr_id; ++ ++ if (strcmp(argv[1], "--odp")) ++ return 0; ++ ++ argc--; ++ argv++; ++ ++ result = odp_init_global(); ++ if (result) { ++ ODP_ERR("Error: ODP global init failed\n"); ++ return result; ++ } ++ ++ thr_id = odp_thread_create(0); ++ odp_init_local(thr_id); ++ ++ odp_initialized = 1; ++ ++ return result; ++} ++ ++static int ++odp_class_init(void) ++{ ++ void *pool_base; ++ int result = 0; ++ ++ /* create packet pool */ ++ pool_base = odp_shm_reserve("shm_packet_pool", SHM_PKT_POOL_SIZE, ++ ODP_CACHE_LINE_SIZE); ++ ++ if (odp_unlikely(pool_base == NULL)) { ++ ODP_ERR("Error: ODP packet pool mem alloc failed\n"); ++ out_of_memory(); ++ return -1; ++ } ++ ++ 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"); ++ return -1; ++ } ++ odp_buffer_pool_print(pool); ++ ++ /* create ofpbuf pool */ ++ pool_base = odp_shm_reserve("shm_ofpbuf_pool", SHM_OFPBUF_POOL_SIZE, ++ ODP_CACHE_LINE_SIZE); ++ ++ if (odp_unlikely(pool_base == NULL)) { ++ ODP_ERR("Error: ODP packet pool mem alloc failed\n"); ++ out_of_memory(); ++ return -1; ++ } ++ ++ ofpbuf_pool = odp_buffer_pool_create("ofpbuf_packet_pool", pool_base, ++ SHM_OFPBUF_POOL_SIZE, ++ SHM_OFPBUF_POOL_BUF_SIZE, ++ ODP_CACHE_LINE_SIZE, ++ ODP_BUFFER_TYPE_RAW); ++ ++ if (ofpbuf_pool == ODP_BUFFER_POOL_INVALID) { ++ ODP_ERR("Error: ofpbuf pool create failed.\n"); ++ return -1; ++ } ++ odp_buffer_pool_print(ofpbuf_pool); ++ ++ /* create pool for structures */ ++ pool_base = odp_shm_reserve("shm_struct_pool", SHM_STRUCT_POOL_SIZE, ++ ODP_CACHE_LINE_SIZE); ++ ++ if (odp_unlikely(pool_base == NULL)) { ++ ODP_ERR("Error: ODP packet pool mem alloc failed\n"); ++ out_of_memory(); ++ return -1; ++ } ++ ++ struct_pool = odp_buffer_pool_create("packet_pool", pool_base, ++ SHM_STRUCT_POOL_SIZE, ++ SHM_STRUCT_POOL_BUF_SIZE, ++ ODP_CACHE_LINE_SIZE, ++ ODP_BUFFER_TYPE_RAW); ++ ++ if (struct_pool == ODP_BUFFER_POOL_INVALID) { ++ ODP_ERR("Error: packet pool create failed.\n"); ++ return -1; ++ } ++ odp_buffer_pool_print(struct_pool); ++ ++ return result; ++} ++ ++static struct netdev * ++netdev_odp_alloc(void) ++{ ++ struct netdev_odp *netdev; ++ odp_buffer_t buf; ++ buf = odp_buffer_alloc(struct_pool); ++ netdev = odp_buffer_addr(buf); ++ memset(netdev, 0, sizeof(*netdev)); ++ netdev->odp_buf = buf; ++ return &netdev->up; ++} ++ ++static struct netdev_odp * ++netdev_odp_cast(const struct netdev *netdev) ++{ ++ return CONTAINER_OF(netdev, struct netdev_odp, up); ++} ++ ++static int ++netdev_odp_construct(struct netdev *netdev_) ++{ ++ int err = 0; ++ char *odp_if; ++ odp_pktio_params_t params; ++ socket_params_t *sock_params = ¶ms.sock_params; ++ struct netdev_odp *netdev = netdev_odp_cast(netdev_); ++ odp_packet_t pkt; ++ ++ odp_if = netdev_->name + 4; /* Names always start with "odp:" */ ++ ++ if (strncmp(netdev_->name, "odp:", 4)) { ++ err = ENODEV; ++ goto out_err; ++ } ++ ++ sock_params->type = ODP_PKTIO_TYPE_SOCKET_BASIC; ++ ++ netdev->pktio = odp_pktio_open(odp_if, pool, ¶ms); ++ ++ if (netdev->pktio == ODP_PKTIO_INVALID) { ++ ODP_ERR("Error: odp pktio failed\n"); ++ err = ENODEV; ++ goto out_err; ++ } ++ ++ netdev->pkt_pool = pool; ++ pkt = odp_packet_alloc(netdev->pkt_pool); ++ if (!odp_packet_is_valid(pkt)) { ++ out_of_memory(); ++ goto out_err; ++ } ++ ++ netdev->max_frame_len = odp_packet_buf_size(pkt); ++ ++ odp_packet_free(pkt); ++ ++ ovs_mutex_init(&netdev->mutex); ++ ++out_err: ++ ++ return err; ++} ++ ++static void ++netdev_odp_destruct(struct netdev *netdev_) ++{ ++ struct netdev_odp *netdev = netdev_odp_cast(netdev_); ++ ++ odp_pktio_close(netdev->pktio); ++} ++ ++static void ++netdev_odp_dealloc(struct netdev *netdev_) ++{ ++ struct netdev_odp *netdev = netdev_odp_cast(netdev_); ++ odp_buffer_free(netdev->odp_buf); ++} ++ ++static int ++netdev_odp_get_config(const struct netdev *netdev_, struct smap *args) ++{ ++ struct netdev_odp *netdev = netdev_odp_cast(netdev_); ++ ++ ovs_mutex_lock(&netdev->mutex); ++ ++ /* TODO: Allow to configure number of queues. */ ++ smap_add_format(args, "configured_rx_queues", "%u", netdev_->n_rxq); ++ smap_add_format(args, "configured_tx_queues", "%u", netdev_->n_rxq); ++ ovs_mutex_unlock(&netdev->mutex); ++ ++ return 0; ++} ++ ++static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) ++{ ++ odp_packet_t pkt; ++ unsigned pkt_cnt = len; ++ unsigned i, j; ++ ++ for (i = 0, j = 0; i < len; ++i) { ++ pkt = pkt_tbl[i]; ++ ++ if (odp_unlikely(odp_packet_error(pkt))) { ++ odp_packet_free(pkt); /* Drop */ ++ pkt_cnt--; ++ } else if (odp_unlikely(i != j++)) { ++ pkt_tbl[j-1] = pkt; ++ } ++ } ++ ++ return pkt_cnt; ++} ++ ++static int ++clone_pkts(struct netdev_odp *dev, struct dpif_packet **pkts, ++ odp_packet_t odp_pkts[], int cnt) ++{ ++ int dropped = 0; ++ int newcnt = 0; ++ int pkts_ok = 0; ++ int i; ++ ++ for (i = 0; i < cnt; i++) { ++ size_t size = ofpbuf_size(&pkts[i]->ofpbuf); ++ odp_packet_t pkt; ++ ++ if (OVS_UNLIKELY(size > dev->max_frame_len)) { ++ VLOG_WARN_RL(&rl, "Too big size %u max_packet_len %u", ++ (unsigned)size, ++ (unsigned)dev->max_frame_len); ++ dropped++; ++ continue; ++ } ++ pkt = odp_packet_alloc(dev->pkt_pool); ++ ++ if (OVS_UNLIKELY(!odp_packet_is_valid(pkt))) { ++ VLOG_WARN_RL(&rl, "Could not allocate packet"); ++ dropped += cnt -i; ++ break; ++ } ++ ++ odp_packet_init(pkt); ++ odp_packet_set_l2_offset(pkt, 0); ++ ++ memcpy(odp_packet_l2(pkt), ofpbuf_data(&pkts[i]->ofpbuf), size); ++ odp_packet_parse(pkt, size, 0); ++ ++ odp_pkts[newcnt] = pkt; ++ newcnt++; ++ } ++ ++ /* Drop packets with errors */ ++ pkts_ok = drop_err_pkts(odp_pkts, newcnt); ++ ++ if (OVS_UNLIKELY(dropped)) { ++ ovs_mutex_lock(&dev->mutex); ++ dev->stats.tx_dropped += dropped; ++ ovs_mutex_unlock(&dev->mutex); ++ } ++ ++ return pkts_ok; ++} ++ ++static int ++netdev_odp_send(struct netdev *netdev, struct dpif_packet **pkts, int cnt, ++ bool may_steal) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ odp_packet_t odp_pkts[NETDEV_MAX_RX_BATCH]; ++ int pkts_ok, i; ++ ++ /* Normally NETDEV_MAX_RX_BATCH should be the limit and VLA ar nasty */ ++ ovs_assert(cnt <= NETDEV_MAX_RX_BATCH); ++ ++ if (!may_steal || pkts[0]->ofpbuf.source != OFPBUF_ODP) { ++ pkts_ok = clone_pkts(dev, pkts, odp_pkts, cnt); ++ ++ if (may_steal) { ++ for (i = 0; i < cnt; i++) { ++ dpif_packet_delete(pkts[i]); ++ } ++ } ++ } else { ++ for (i = 0; i < cnt; i++) { ++ odp_pkts[i] = pkts[i]->ofpbuf.odp_pkt; ++ odp_packet_free(pkts[i]->ofpbuf.odp_ofpbuf); ++ } ++ pkts_ok = cnt; ++ } ++ ++ odp_pktio_send(dev->pktio, odp_pkts, pkts_ok); ++ ++ ovs_mutex_lock(&dev->mutex); ++ dev->stats.tx_packets += pkts_ok; ++ for (i = 0; i < pkts_ok; i++) { ++ dev->stats.tx_bytes += odp_packet_get_len(odp_pkts[i]); ++ } ++ ovs_mutex_unlock(&dev->mutex); ++ ++ return 0; ++} ++ ++static int ++netdev_odp_set_etheraddr(struct netdev *netdev, ++ const uint8_t mac[ETH_ADDR_LEN]) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ ovs_mutex_lock(&dev->mutex); ++ if (!eth_addr_equals(dev->hwaddr, mac)) { ++ memcpy(dev->hwaddr, mac, ETH_ADDR_LEN); ++ netdev_change_seq_changed(netdev); ++ } ++ ovs_mutex_unlock(&dev->mutex); ++ ++ return 0; ++} ++ ++static int ++netdev_odp_get_etheraddr(const struct netdev *netdev, ++ uint8_t mac[ETH_ADDR_LEN]) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ ovs_mutex_lock(&dev->mutex); ++ memcpy(mac, dev->hwaddr, ETH_ADDR_LEN); ++ ovs_mutex_unlock(&dev->mutex); ++ ++ return 0; ++} ++ ++static int ++netdev_odp_get_mtu(const struct netdev *netdev, int *mtup) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) mtup; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_set_mtu(const struct netdev *netdev, int mtu) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) mtu; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_get_ifindex(const struct netdev *netdev) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_get_carrier(const struct netdev *netdev, bool *carrier) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) carrier; ++ ++ return ENOTSUP; ++} ++ ++static long long int ++netdev_odp_get_carrier_resets(const struct netdev *netdev) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_set_miimon(struct netdev *netdev_ OVS_UNUSED, ++ long long int interval OVS_UNUSED) ++{ ++ return 0; ++} ++ ++static int ++netdev_odp_get_stats(const struct netdev *netdev, struct netdev_stats *stats) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ ovs_mutex_lock(&dev->mutex); ++ *stats = dev->stats; ++ ovs_mutex_unlock(&dev->mutex); ++ ++ return 0; ++} ++ ++static int ++netdev_odp_set_stats(struct netdev *netdev, const struct netdev_stats *stats) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ ovs_mutex_lock(&dev->mutex); ++ dev->stats = *stats; ++ ovs_mutex_unlock(&dev->mutex); ++ ++ return 0; ++} ++ ++static int ++netdev_odp_get_features(const struct netdev *netdev, ++ enum netdev_features *current, ++ enum netdev_features *advertised OVS_UNUSED, ++ enum netdev_features *supported OVS_UNUSED, ++ enum netdev_features *peer OVS_UNUSED) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) current; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_get_status(const struct netdev *netdev, struct smap *args) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) args; ++ ++ return ENOTSUP; ++} ++ ++static int ++netdev_odp_update_flags(struct netdev *netdev, ++ enum netdev_flags off, enum netdev_flags on, ++ enum netdev_flags *old_flagsp) ++{ ++ struct netdev_odp *dev = netdev_odp_cast(netdev); ++ ++ (void) dev; ++ (void) off; ++ (void) on; ++ (void) old_flagsp; ++ ++ if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) { ++ return EINVAL; ++ } ++ ++ *old_flagsp = dev->flags; ++ dev->flags |= on; ++ dev->flags &= ~off; ++ ++ if (dev->flags == *old_flagsp) { ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static struct netdev_rxq * ++netdev_odp_rxq_alloc(void) ++{ ++ struct netdev_rxq_odp *rx; ++ odp_buffer_t buf; ++ buf = odp_buffer_alloc(struct_pool); ++ rx = odp_buffer_addr(buf); ++ memset(rx, 0, sizeof(*rx)); ++ rx->odp_buf = buf; ++ return &rx->up; ++} ++ ++static struct netdev_rxq_odp * ++netdev_rxq_odp_cast(const struct netdev_rxq *rx) ++{ ++ return CONTAINER_OF(rx, struct netdev_rxq_odp, up); ++} ++ ++static int ++netdev_odp_rxq_construct(struct netdev_rxq *rxq_) ++{ ++ struct netdev_rxq_odp *rx = netdev_rxq_odp_cast(rxq_); ++ struct netdev_odp *netdev = netdev_odp_cast(rx->up.netdev); ++ ++ rx->queue_id = odp_pktio_inq_getdef(netdev->pktio); ++ ++ return 0; ++} ++ ++static void ++netdev_odp_rxq_destruct(struct netdev_rxq *rxq_ OVS_UNUSED) ++{ ++} ++ ++static void ++netdev_odp_rxq_dealloc(struct netdev_rxq *rxq_) ++{ ++ struct netdev_rxq_odp *rxq = netdev_rxq_odp_cast(rxq_); ++ odp_buffer_free(rxq->odp_buf); ++} ++ ++static int ++netdev_odp_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **packets, ++ int *c) ++{ ++ struct netdev_rxq_odp *rx = netdev_rxq_odp_cast(rxq_); ++ struct netdev_odp *netdev = netdev_odp_cast(rx->up.netdev); ++ int pkts, pkts_ok, ret = 0; ++ size_t rx_bytes = 0; ++ unsigned long err_cnt = 0; ++ int i; ++ odp_pktio_t pkt_tbl[NETDEV_MAX_RX_BATCH]; ++ ++ pkts = odp_pktio_recv(netdev->pktio, pkt_tbl, NETDEV_MAX_RX_BATCH); ++ if (pkts < 0) { ++ return EINVAL; ++ } ++ if (!pkts) { ++ return EAGAIN; ++ } ++ ++ if (pkts > 0) { ++ pkts_ok = drop_err_pkts(pkt_tbl, pkts); ++ if (odp_unlikely(pkts_ok != pkts)) ++ ODP_ERR("Dropped frames:%u - err_cnt:%lu\n", ++ pkts-pkts_ok, ++err_cnt); ++ if (!pkts_ok) { ++ ret = EAGAIN; ++ goto out_stats; ++ } ++ } ++ ++ /* Allocate an ofpbuf for each valid packet */ ++ for (i = 0; i < pkts_ok; i++) { ++ odp_buffer_t buf; ++ buf = odp_buffer_alloc(ofpbuf_pool); ++ if (buf == ODP_BUFFER_INVALID) { ++ out_of_memory(); ++ } ++ packets[i] = (struct dpif_packet*) odp_buffer_addr(buf); ++ ofpbuf_init_odp(&packets[i]->ofpbuf, odp_packet_buf_size(pkt_tbl[i])); ++ packets[i]->ofpbuf.odp_pkt = pkt_tbl[i]; ++ packets[i]->ofpbuf.odp_ofpbuf = buf; ++ rx_bytes += odp_packet_get_len(pkt_tbl[i]); ++ } ++ ++ *c = pkts_ok; ++ ++ printf("ODP: received %d packets\n", pkts_ok); ++ ++out_stats: ++ ovs_mutex_lock(&netdev->mutex); ++ netdev->stats.rx_packets += pkts_ok; ++ netdev->stats.rx_bytes += rx_bytes; ++ netdev->stats.rx_dropped += pkts - pkts_ok; ++ ovs_mutex_unlock(&netdev->mutex); ++ ++ return ret; ++} ++ ++static struct netdev_class netdev_odp_class = { ++ "odp", ++ odp_class_init, /* init */ ++ NULL, /* netdev_odp_run */ ++ NULL, /* netdev_odp_wait */ ++ ++ netdev_odp_alloc, ++ netdev_odp_construct, ++ netdev_odp_destruct, ++ netdev_odp_dealloc, ++ netdev_odp_get_config, ++ NULL, /* netdev_odp_set_config */ ++ NULL, /* get_tunnel_config */ ++ ++ netdev_odp_send, /* send */ ++ NULL, /* send_wait */ ++ ++ netdev_odp_set_etheraddr, ++ netdev_odp_get_etheraddr, ++ netdev_odp_get_mtu, ++ netdev_odp_set_mtu, ++ netdev_odp_get_ifindex, ++ netdev_odp_get_carrier, ++ netdev_odp_get_carrier_resets, ++ netdev_odp_set_miimon, ++ netdev_odp_get_stats, ++ netdev_odp_set_stats, ++ netdev_odp_get_features, ++ NULL, /* set_advertisements */ ++ ++ NULL, /* set_policing */ ++ NULL, /* get_qos_types */ ++ NULL, /* get_qos_capabilities */ ++ NULL, /* get_qos */ ++ NULL, /* set_qos */ ++ NULL, /* get_queue */ ++ NULL, /* set_queue */ ++ NULL, /* delete_queue */ ++ NULL, /* get_queue_stats */ ++ NULL, /* queue_dump_start */ ++ NULL, /* queue_dump_next */ ++ NULL, /* queue_dump_done */ ++ NULL, /* dump_queue_stats */ ++ ++ NULL, /* get_in4 */ ++ NULL, /* set_in4 */ ++ NULL, /* get_in6 */ ++ NULL, /* add_router */ ++ NULL, /* get_next_hop */ ++ netdev_odp_get_status, ++ NULL, /* arp_lookup */ ++ ++ netdev_odp_update_flags, ++ ++ netdev_odp_rxq_alloc, ++ netdev_odp_rxq_construct, ++ netdev_odp_rxq_destruct, ++ netdev_odp_rxq_dealloc, ++ netdev_odp_rxq_recv, ++ NULL, /* rxq_wait */ ++ NULL, /* rxq_drain */ ++}; ++ ++void ++netdev_odp_register(void) ++{ ++ if (!odp_initialized) { ++ VLOG_INFO("Not running in ODP mode\n"); ++ return; ++ } ++ ++ netdev_register_provider(&netdev_odp_class); ++} +diff --git a/lib/netdev-odp.h b/lib/netdev-odp.h +new file mode 100644 +index 0000000..a0a2594 +--- /dev/null ++++ b/lib/netdev-odp.h +@@ -0,0 +1,39 @@ ++#ifndef NETDEV_ODP_H ++#define NETDEV_ODP_H ++ ++#include ++#include "ofpbuf.h" ++ ++#ifdef ODP_NETDEV ++ ++#include ++#include ++#include ++#include ++ ++/* This function is not exported, we need another way to deal with ++ creating a packet from an ofpbuf */ ++extern void odp_packet_parse(odp_packet_t pkt, size_t len, size_t l2_offset); ++ ++ ++void netdev_odp_register(void); ++void free_odp_buf(struct ofpbuf *); ++int odp_init(int argc, char *argv[]); ++ ++#else ++ ++static inline void ++netdev_odp_register(void) ++{ ++ /* Nothing */ ++} ++ ++static inline void ++free_odp_buf(struct ofpbuf *buf OVS_UNUSED) ++{ ++ /* Nothing */ ++} ++ ++ ++#endif /* ODP_NETDEV */ ++#endif +diff --git a/lib/netdev.c b/lib/netdev.c +index ea16ccb..787b4b3 100644 +--- a/lib/netdev.c ++++ b/lib/netdev.c +@@ -31,6 +31,7 @@ + #include "hash.h" + #include "list.h" + #include "netdev-dpdk.h" ++#include "netdev-odp.h" + #include "netdev-provider.h" + #include "netdev-vport.h" + #include "ofpbuf.h" +@@ -99,7 +100,8 @@ bool + netdev_is_pmd(const struct netdev *netdev) + { + return (!strcmp(netdev->netdev_class->type, "dpdk") || +- !strcmp(netdev->netdev_class->type, "dpdkr")); ++ !strcmp(netdev->netdev_class->type, "dpdkr") || ++ !strcmp(netdev->netdev_class->type, "odp")); + } + + static void +@@ -138,6 +140,10 @@ netdev_initialize(void) + #endif + netdev_dpdk_register(); + ++#ifdef ODP_NETDEV ++ netdev_odp_register(); ++#endif ++ + ovsthread_once_done(&once); + } + } +diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c +index 28013d5..55c59e0 100644 +--- a/lib/ofpbuf.c ++++ b/lib/ofpbuf.c +@@ -20,6 +20,7 @@ + #include + #include "dynamic-string.h" + #include "netdev-dpdk.h" ++#include "netdev-odp.h" + #include "util.h" + + static void +@@ -119,6 +120,14 @@ ofpbuf_init_dpdk(struct ofpbuf *b, size_t allocated) + ofpbuf_init__(b, allocated, OFPBUF_DPDK); + } + ++#ifdef ODP_NETDEV ++void ++ofpbuf_init_odp(struct ofpbuf *b, size_t allocated) ++{ ++ ofpbuf_init__(b, allocated, OFPBUF_ODP); ++} ++#endif ++ + /* Initializes 'b' as an empty ofpbuf with an initial capacity of 'size' + * bytes. */ + void +@@ -142,6 +151,13 @@ ofpbuf_uninit(struct ofpbuf *b) + #else + ovs_assert(b->source != OFPBUF_DPDK); + #endif ++ } else if (b->source == OFPBUF_ODP) { ++#ifdef ODP_NETDEV ++ odp_packet_free(b->odp_pkt); ++ odp_buffer_free(b->odp_ofpbuf); ++#else ++ ovs_assert(b->source != OFPBUF_ODP); ++#endif + } + } + } +diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h +index 6af9c64..653efc6 100644 +--- a/lib/ofpbuf.h ++++ b/lib/ofpbuf.h +@@ -23,6 +23,7 @@ + #include "packets.h" + #include "util.h" + #include "netdev-dpdk.h" ++#include "netdev-odp.h" + + #ifdef __cplusplus + extern "C" { +@@ -62,6 +63,10 @@ struct ofpbuf { + #ifdef DPDK_NETDEV + struct rte_mbuf mbuf; /* DPDK mbuf */ + #else ++# ifdef ODP_NETDEV ++ odp_buffer_t odp_ofpbuf; /* ODP buffer containig this struct ofpbuf */ ++ odp_packet_t odp_pkt; /* ODP packet containing actual payload */ ++# endif + void *base_; /* First byte of allocated space. */ + void *data_; /* First byte actually in use. */ + uint32_t size_; /* Number of bytes in use. */ +@@ -109,6 +114,9 @@ void ofpbuf_use_stub(struct ofpbuf *, void *, size_t); + void ofpbuf_use_const(struct ofpbuf *, const void *, size_t); + + void ofpbuf_init_dpdk(struct ofpbuf *b, size_t allocated); ++#ifdef ODP_NETDEV ++void ofpbuf_init_odp(struct ofpbuf *b, size_t allocated); ++#endif + + void ofpbuf_init(struct ofpbuf *, size_t); + void ofpbuf_uninit(struct ofpbuf *); +@@ -183,6 +191,11 @@ static inline void ofpbuf_delete(struct ofpbuf *b) + return; + } + ++ if (b->source == OFPBUF_ODP) { ++ free_odp_buf(b); ++ return; ++ } ++ + ofpbuf_uninit(b); + free(b); + } +@@ -395,31 +408,69 @@ static inline void ofpbuf_set_size(struct ofpbuf *b, uint32_t v) + #else + static inline void * ofpbuf_data(const struct ofpbuf *b) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) ++ return odp_packet_l2(b->odp_pkt); ++#endif ++ + return b->data_; + } + + static inline void ofpbuf_set_data(struct ofpbuf *b, void *d) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) { ++ ODP_ERR("ODP: Invalid use of ofpbuf_set_data\n"); ++ ovs_abort(0, "Invalid function call\n"); ++ } ++#endif ++ + b->data_ = d; + } + + static inline void * ofpbuf_base(const struct ofpbuf *b) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) { ++ ODP_ERR("ODP: Invalid use of ofpbuf_base\n"); ++ ovs_abort(0, "Invalid function call\n"); ++ } ++#endif ++ + return b->base_; + } + + static inline void ofpbuf_set_base(struct ofpbuf *b, void *d) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) { ++ ODP_ERR("ODP: Invalid use of ofpbuf_set_base\n"); ++ ovs_abort(0, "Invalid function call\n"); ++ } ++#endif ++ + b->base_ = d; + } + + static inline uint32_t ofpbuf_size(const struct ofpbuf *b) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) ++ return odp_packet_get_len(b->odp_pkt); ++#endif ++ + return b->size_; + } + + static inline void ofpbuf_set_size(struct ofpbuf *b, uint32_t v) + { ++#ifdef ODP_NETDEV ++ if (b->source == OFPBUF_ODP) { ++ ODP_ERR("ODP: Invalid use of ofpbuf_set_size\n"); ++ ovs_abort(0, "Invalid function call\n"); ++ } ++#endif ++ + b->size_ = v; + } + #endif +diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c +index 4d7e4f0..ba4635f 100644 +--- a/vswitchd/ovs-vswitchd.c ++++ b/vswitchd/ovs-vswitchd.c +@@ -75,6 +75,12 @@ main(int argc, char *argv[]) + argc -= retval; + argv += retval; + ++#ifdef ODP_NETDEV ++ retval = odp_init(argc, argv); ++ argc -= retval; ++ argv += retval; ++#endif ++ + proctitle_init(argc, argv); + service_start(&argc, &argv); + remote = parse_options(argc, argv, &unixctl_path); +@@ -149,6 +155,7 @@ parse_options(int argc, char *argv[], char **unixctl_pathp) + OPT_DISABLE_SYSTEM, + DAEMON_OPTION_ENUMS, + OPT_DPDK, ++ OPT_ODP, + }; + static const struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, +@@ -163,6 +170,7 @@ parse_options(int argc, char *argv[], char **unixctl_pathp) + {"enable-dummy", optional_argument, NULL, OPT_ENABLE_DUMMY}, + {"disable-system", no_argument, NULL, OPT_DISABLE_SYSTEM}, + {"dpdk", required_argument, NULL, OPT_DPDK}, ++ {"odp", required_argument, NULL, OPT_ODP}, + {NULL, 0, NULL, 0}, + }; + char *short_options = long_options_to_short_options(long_options); +@@ -217,6 +225,9 @@ parse_options(int argc, char *argv[], char **unixctl_pathp) + case OPT_DPDK: + break; + ++ case OPT_ODP: ++ break; ++ + default: + abort(); + } +-- +1.8.3.2 + diff --git a/openvswitch/patches/0004-utilities-Add-option-to-start-with-ODP.patch b/openvswitch/patches/0004-utilities-Add-option-to-start-with-ODP.patch new file mode 100644 index 0000000..4424078 --- /dev/null +++ b/openvswitch/patches/0004-utilities-Add-option-to-start-with-ODP.patch @@ -0,0 +1,38 @@ +From 6e06aba36bd9373a7e9e77483baa4ca994360d0c Mon Sep 17 00:00:00 2001 +From: Ciprian Barbu +Date: Tue, 19 Aug 2014 20:57:30 +0300 +Subject: [PATCH 4/4] utilities: Add option to start with ODP + +Signed-off-by: Ciprian Barbu +--- + utilities/ovs-ctl.in | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/utilities/ovs-ctl.in b/utilities/ovs-ctl.in +index 6d2e938..8914b58 100755 +--- a/utilities/ovs-ctl.in ++++ b/utilities/ovs-ctl.in +@@ -240,7 +240,11 @@ start_forwarding () { + fi + + # Start ovs-vswitchd. +- set ovs-vswitchd unix:"$DB_SOCK" ++ if test X"$USE_ODP" != Xno; then ++ set ovs-vswitchd --odp -- unix:"$DB_SOCK" ++ else ++ set ovs-vswitchd unix:"$DB_SOCK" ++ fi + set "$@" -vconsole:emer -vsyslog:err -vfile:info + if test X"$MLOCKALL" != Xno; then + set "$@" --mlockall +@@ -529,6 +533,7 @@ set_defaults () { + PROTOCOL=gre + DPORT= + SPORT= ++ USE_ODP=no + + type_file=$etcdir/system-type.conf + version_file=$etcdir/system-version.conf +-- +1.8.3.2 +