diff mbox

[APPS/PATCH] Added openvswitch with ODP support

Message ID 1409760211-13580-1-git-send-email-ciprian.barbu@linaro.org
State New
Headers show

Commit Message

Ciprian Barbu Sept. 3, 2014, 4:03 p.m. UTC
Signed-off-by: Ciprian Barbu <ciprian.barbu@linaro.org>
---
 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 mbox

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 <ciprian.barbu@linaro.org>
+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 <ciprian.barbu@linaro.org>
+---
+ 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 <ciprian.barbu@linaro.org>
+Date: Mon, 18 Aug 2014 20:09:24 +0300
+Subject: [PATCH 2/4] Config options for building with ODP
+
+Signed-off-by: Ciprian Barbu <ciprian.barbu@linaro.org>
+---
+ 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.h>],
++                            [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 <ciprian.barbu@linaro.org>
+Date: Tue, 19 Aug 2014 14:45:04 +0300
+Subject: [PATCH 3/4] dpif-netdev: Add ODP netdev
+
+Signed-off-by: Ciprian Barbu <ciprian.barbu@linaro.org>
+---
+ 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=<ODP_DIR>
++
++to specify a different ODP platform you can use:
++    ./configure --with-odp=<ODP_DIR> --with-odp-platform=<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 <config.h>
++
++#include <stdio.h>
++#include <string.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <pthread.h>
++#include <config.h>
++#include <errno.h>
++#include <sched.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdio.h>
++
++#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 = &params.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, &params);
++
++    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 <config.h>
++#include "ofpbuf.h"
++
++#ifdef ODP_NETDEV
++
++#include <odp.h>
++#include <helper/odp_eth.h>
++#include <helper/odp_ip.h>
++#include <helper/odp_packet_helper.h>
++
++/* 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 <string.h>
+ #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 <ciprian.barbu@linaro.org>
+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 <ciprian.barbu@linaro.org>
+---
+ 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
+