aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitreview2
-rw-r--r--README.vppodp170
-rw-r--r--build-data/packages/vpp.mk7
-rw-r--r--build-data/platforms/odp.mk57
-rw-r--r--src/configure.ac11
-rw-r--r--src/plugins/Makefile.am4
-rw-r--r--src/plugins/odp.am25
-rwxr-xr-xsrc/plugins/odp/cli.c147
-rwxr-xr-xsrc/plugins/odp/device.c226
-rwxr-xr-xsrc/plugins/odp/node.c334
-rwxr-xr-xsrc/plugins/odp/odp_packet.c363
-rwxr-xr-xsrc/plugins/odp/odp_packet.h74
12 files changed, 1418 insertions, 2 deletions
diff --git a/.gitreview b/.gitreview
index 1db08df2..48da0b61 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,4 +1,4 @@
[gerrit]
host=gerrit.fd.io
port=29418
-project=vpp
+project=odp4vpp
diff --git a/README.vppodp b/README.vppodp
new file mode 100644
index 00000000..7ff3c865
--- /dev/null
+++ b/README.vppodp
@@ -0,0 +1,170 @@
+
+##odp4vpp:
+
+#Introduction:
+--------------
+odp4vpp project aims to provide VPP with an additional vnet device based on OpenDataPlane (ODP is similar yet different from DPDK), with provisions for hardwareacceleration of packet paths. It envisions three deployment scenarios:
+
+-Server + NICs
+-Systems on a Chip
+-SmartNIC with low to very high core count
+
+#Build Procedure:
+----------------
+The source code add support to build VPP with either odp-linux or odp-dpdk.
+
+1)Build vpp with odp-linux:
+---------------------------
+Build the odp linux package by compiling odp from odp git repository:
+
+git clone https://git.linaro.org/lng/odp.git
+
+Follow the README steps for complete build.
+
+cd odp
+./bootstrap
+./configure --prefix= <odp-install-path>
+make install
+
+Set the environment variables with ODP config:
+
+export PLATFORM=odp
+export ODP_INST_PATH=<odp-install-path>
+
+Build vpp:
+Follow the README steps for complete build.
+
+cd vpp
+make install-dep
+make build
+make run
+
+2)Build vpp with odp-dpdk:
+--------------------------
+Build the odp-dpdk package by compiling odp-dpdk from odp-dpdk git repository:
+
+git clone https://git.linaro.org/lng/odp-dpdk.git
+
+Follow the README.DPDK steps for complete build with dpdk.
+
+cd odp-dpdk
+./bootstrap
+./configure --prefix= <odp-dpdk-install-path> --with-sdk-install-path=<dpdk-dir>/x86_64-native-linuxapp-gcc
+make install
+
+Set the environment variables with ODP config:
+
+export PLATFORM=odp
+export ODP_INST_PATH=<odp-dpdk-install-path>
+
+Note : Also check and copy dpdk/odp-dpdk libraries to default /usr/lib path for linking with vpp.
+
+Build vpp:
+Follow the README steps for complete build.
+
+cd vpp
+make install-dep
+make build
+make run
+
+#Test Steps:
+------------
+Below is a basic verification test.
+
+Note :For odp-dpdk the port has to bound with dpdk driver prior to test and interface name is passed as 0,1..etc.
+
+1)Configure odp packet interface with mode ie (0-burst,1-queue,2-schedule) default mode is 0.
+
+-create pktio-interface name <int name> hw-addr <mac> mode <0/1/2>
+-set int ip address odp-<int name> X.X.X.X/24
+-set int state odp-<int name> up
+
+2)Check the interface state:
+-sh int
+
+3)Ping the configured interface from host machine and check the ARP and ipv4 FIB table:
+-sh ip arp
+-sh ip fib
+
+4)Check the interface counters:
+-sh int
+
+5)Check the statistics:
+-show run
+
+6)Packet trace can be enabled using :
+-trace add odp-packet-input 10
+-show trace
+
+7)Delete the interface:
+-delete pktio-interface name <int name>
+
+
+Example:
+--------
+Below is example config logs:
+
+with odp-linux:
+
+DBGvpp# create pktio-interface name enp0s8 hw-addr 08:00:27:1b:5e:48
+odp-enp0s8
+DBGvpp# set int ip address odp-enp0s8 192.168.1.4/24
+DBGvpp# set int state odp-enp0s8 up
+DBGvpp# sh int
+ Name Idx State Counter Count
+local0 0 down
+odp-enp0s8 1 up rx packets 1
+ rx bytes 60
+ drops 1
+DBGvpp# sh int addr
+local0 (dn):
+odp-enp0s8 (up):
+ 192.168.1.4/24
+DBGvpp# sh int
+ Name Idx State Counter Count
+local0 0 down drops 1
+odp-enp0s8 1 up rx packets 12
+ rx bytes 902
+ tx packets 5
+ tx bytes 324
+ drops 4
+ punts 3
+ ip4 7
+DBGvpp# sh ip arp
+ Time IP4 Flags Ethernet Interface
+ 171.7151 192.168.1.1 D c8:3a:35:19:ea:f0 odp-enp0s8
+ 185.0099 192.168.1.3 D 48:45:20:11:41:ad odp-enp0s8
+DBGvpp#
+
+with odp-dpdk:
+
+sreejith@sreejith-VirtualBox:~/vppdodp/vpp_odp_dpdk/dpdk$ sudo ./usertools/dpdk-devbind.py --status
+
+Network devices using DPDK-compatible driver
+============================================
+0000:00:08.0 '82540EM Gigabit Ethernet Controller' drv=igb_uio unused=e1000
+0000:00:09.0 '82540EM Gigabit Ethernet Controller' drv=igb_uio unused=e1000
+
+
+DBGvpp# create pktio-interface name 0 hw-addr 08:00:27:1b:5e:48
+odp-0
+DBGvpp# sh int
+ Name Idx State Counter Count
+local0 0 down
+odp-0 1 down
+
+DBGvpp# set int ip address odp-0 192.168.1.4/24
+DBGvpp# set int state odp-0 up
+DBGvpp# sh int
+ Name Idx State Counter Count
+local0 0 down
+odp-0 1 up rx packets 13
+ rx bytes 1960
+ tx packets 1
+ tx bytes 42
+ drops 13
+ ip4 7
+ ip6 4
+
+
+
diff --git a/build-data/packages/vpp.mk b/build-data/packages/vpp.mk
index 1acc59b2..3ff971c7 100644
--- a/build-data/packages/vpp.mk
+++ b/build-data/packages/vpp.mk
@@ -13,6 +13,13 @@ vpp_configure_args += $(vpp_configure_args_$(PLATFORM))
vpp_CPPFLAGS =
vpp_LDFLAGS =
+#Include ODP library only if ODP is being used.
+ifeq ($($(PLATFORM)_uses_odp),yes)
+vpp_CPPFLAGS += -I$($(PLATFORM)_odp_inc_dir)
+vpp_LDFLAGS += -L$($(PLATFORM)_odp_lib_dir)
+export ODP_LIBS= $($(PLATFORM)_odp_libs)
+endif
+
ifneq ($($(PLATFORM)_uses_dpdk),no)
ifeq ($($(PLATFORM)_uses_external_dpdk),yes)
vpp_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir)
diff --git a/build-data/platforms/odp.mk b/build-data/platforms/odp.mk
new file mode 100644
index 00000000..d60c54cd
--- /dev/null
+++ b/build-data/platforms/odp.mk
@@ -0,0 +1,57 @@
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# 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.
+
+# vector packet processor
+odp_arch = native
+ifeq ($(shell uname -m),x86_64)
+odp_march = corei7 # Nehalem Instruction set
+odp_mtune = corei7-avx # Optimize for Sandy Bridge
+else
+odp_march = native
+odp_mtune = generic
+endif
+odp_native_tools = vppapigen
+
+odp_uses_dpdk = no
+
+# Uncoment to enable building unit tests
+#odp_enable_tests = yes
+
+odp_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \
+ vpp-api gmod
+
+vlib_configure_args_odp = --with-pre-data=128
+
+#ODP configuration parameters
+odp_uses_odp=yes
+odp_odp_libs = -lodp-dpdk -ldpdk -lpcap
+odp_odp_inc_dir=$(ODP_INST_PATH)/include
+odp_odp_lib_dir=$(ODP_INST_PATH)/lib
+
+vpp_configure_args_odp = --with-odplib --disable-dpdk-plugin --disable-acl-plugin
+vnet_configure_args_odp = --disable-dpdk-plugin --disable-acl-plugin
+
+odp_debug_TAG_CFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+ -fstack-protector-all -fPIC -Werror
+odp_debug_TAG_LDFLAGS = -g -O0 -DCLIB_DEBUG -DFORTIFY_SOURCE=2 -march=$(MARCH) \
+ -fstack-protector-all -fPIC -Werror
+
+odp_TAG_CFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
+ -fstack-protector -fPIC -Werror
+odp_TAG_LDFLAGS = -g -O2 -DFORTIFY_SOURCE=2 -march=$(MARCH) -mtune=$(MTUNE) \
+ -fstack-protector -fPIC -Werror
+
+odp_gcov_TAG_CFLAGS = -g -O0 -DCLIB_DEBUG -march=$(MARCH) \
+ -fPIC -Werror -fprofile-arcs -ftest-coverage
+odp_gcov_TAG_LDFLAGS = -g -O0 -DCLIB_DEBUG -march=$(MARCH) \
+ -fPIC -Werror -coverage
diff --git a/src/configure.ac b/src/configure.ac
index 173b3153..d1f8b9fa 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -104,13 +104,20 @@ WITH_ARG(dpdk_mlx5_pmd, [Use DPDK with mlx5 PMD])
WITHOUT_ARG(libssl, [Disable libssl])
WITHOUT_ARG(apicli, [Disable binary api CLI])
+AC_ARG_WITH(odplib,
+ AC_HELP_STRING([--with-odplib],[Use odplib]),
+ [with_odplib=1],
+ [with_odplib=0])
+
+AM_CONDITIONAL(WITH_ODPLIB, test $with_odplib = 1)
+
AC_ARG_WITH(unix,
AC_HELP_STRING([--with-unix],[Compile unix version of clib]),
[],
[case $host_os in
darwin* | linux*) with_unix=yes;;
*) with_unix=no;;
- esac])
+ esac])
AM_CONDITIONAL(WITH_UNIX, test "$with_unix" = "yes")
@@ -155,6 +162,8 @@ PLUGIN_ENABLED(lb)
PLUGIN_ENABLED(memif)
PLUGIN_ENABLED(sixrd)
PLUGIN_ENABLED(snat)
+AM_COND_IF([WITH_ODPLIB],
+[PLUGIN_ENABLED(odp)],[PLUGIN_DISABLED(odp)])
###############################################################################
# Dependency checks
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index f26d0fd2..44b2085c 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -74,6 +74,10 @@ if ENABLE_SNAT_PLUGIN
include snat.am
endif
+if ENABLE_ODP_PLUGIN
+include odp.am
+endif
+
include ../suffix-rules.mk
# Remove *.la files
diff --git a/src/plugins/odp.am b/src/plugins/odp.am
new file mode 100644
index 00000000..5de071ee
--- /dev/null
+++ b/src/plugins/odp.am
@@ -0,0 +1,25 @@
+# Copyright (c) 2017 Cisco Systems, 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.
+
+vppplugins_LTLIBRARIES += odp_plugin.la
+
+odp_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(ODP_LIBS)
+
+odp_plugin_la_SOURCES = odp/cli.c \
+ odp/node.c \
+ odp/odp_packet.c \
+ odp/device.c
+
+noinst_HEADERS += odp/odp_packet.h
+
+# vi:syntax=automake
diff --git a/src/plugins/odp/cli.c b/src/plugins/odp/cli.c
new file mode 100755
index 00000000..b7d846b7
--- /dev/null
+++ b/src/plugins/odp/cli.c
@@ -0,0 +1,147 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * 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 <fcntl.h> /* for open */
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h> /* for iovec */
+#include <netinet/in.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <odp/odp_packet.h>
+
+static clib_error_t *
+odp_packet_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u8 *host_if_name = NULL;
+ u8 hwaddr[6];
+ u8 *hw_addr_ptr = 0;
+ u32 sw_if_index;
+ u32 mode=0;
+ int r;
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "name %s", &host_if_name))
+ ;
+ else
+ if (unformat
+ (line_input, "hw-addr %U", unformat_ethernet_address, hwaddr))
+ hw_addr_ptr = hwaddr;
+ else
+ if (unformat
+ (line_input, "mode %d", &mode))
+ ;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ unformat_free (line_input);
+
+ if (host_if_name == NULL)
+ return clib_error_return (0, "missing host interface name");
+
+ r = odp_packet_create_if (vm, host_if_name, hw_addr_ptr, &sw_if_index, mode);
+ vec_free (host_if_name);
+
+ if (r == VNET_API_ERROR_SYSCALL_ERROR_1)
+ return clib_error_return (0, "%s (errno %d)", strerror (errno), errno);
+
+ if (r == VNET_API_ERROR_INVALID_INTERFACE)
+ return clib_error_return (0, "Invalid interface name");
+
+ if (r == VNET_API_ERROR_SUBIF_ALREADY_EXISTS)
+ return clib_error_return (0, "Interface elready exists");
+
+ vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
+ sw_if_index);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (odp_packet_create_command, static) = {
+ .path = "create pktio-interface",
+ .short_help = "create pktio-interface name <interface name> [hw-addr <mac>]",
+ .function = odp_packet_create_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+odp_packet_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u8 *host_if_name = NULL;
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "name %s", &host_if_name))
+ ;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ unformat_free (line_input);
+
+
+ if (host_if_name == NULL)
+ return clib_error_return (0, "missing host interface name");
+
+
+ odp_packet_delete_if (vm, host_if_name);
+ vec_free(host_if_name);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (odp_packet_delete_command, static) = {
+ .path = "delete pktio-interface",
+ .short_help = "delete pktio-interface name <interface name>",
+ .function = odp_packet_delete_command_fn,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+odp_packet_cli_init (vlib_main_t * vm)
+{
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (odp_packet_cli_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/device.c b/src/plugins/odp/device.c
new file mode 100755
index 00000000..6acc5ac7
--- /dev/null
+++ b/src/plugins/odp/device.c
@@ -0,0 +1,226 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * 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 <linux/if_packet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <odp/odp_packet.h>
+
+#define foreach_odp_packet_tx_func_error \
+_(FRAME_NOT_READY, "tx frame not ready") \
+_(TXRING_EAGAIN, "tx sendto temporary failure") \
+_(TXRING_FATAL, "tx sendto fatal failure") \
+_(TXRING_OVERRUN, "tx ring overrun")
+
+typedef enum
+{
+#define _(f,s) ODP_PACKET_TX_ERROR_##f,
+ foreach_odp_packet_tx_func_error
+#undef _
+ ODP_PACKET_TX_N_ERROR,
+} odp_packet_tx_func_error_t;
+
+static char *odp_packet_tx_func_error_strings[] = {
+#define _(n,s) s,
+ foreach_odp_packet_tx_func_error
+#undef _
+};
+
+
+static u8 *
+format_odp_packet_device_name (u8 * s, va_list * args)
+{
+ u32 i = va_arg (*args, u32);
+ odp_packet_main_t *om = &odp_packet_main;
+ odp_packet_if_t *oif = vec_elt_at_index (om->interfaces, i);
+
+ s = format (s, "odp-%s", oif->host_if_name);
+ return s;
+}
+
+static u8 *
+format_odp_packet_device (u8 * s, va_list * args)
+{
+ s = format (s, "odp interface");
+ return s;
+}
+
+static u8 *
+format_odp_packet_tx_trace (u8 * s, va_list * args)
+{
+ s = format (s, "Unimplemented...");
+ return s;
+}
+
+static uword
+odp_packet_interface_tx (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+
+ odp_packet_main_t *om = &odp_packet_main;
+ u32 *buffers = vlib_frame_args (frame);
+ u32 n_left = frame->n_vectors;
+ vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
+ odp_packet_if_t *oif =pool_elt_at_index (om->interfaces, rd->dev_instance);
+ odp_pktout_queue_t pktout;
+ odp_packet_t pkt_tbl[VLIB_FRAME_SIZE];
+ u32 sent=0, count=0;
+
+ if (PREDICT_FALSE (oif->lockp != 0))
+ {
+ while (__sync_lock_test_and_set (oif->lockp, 1))
+ ;
+ }
+
+ if (odp_pktout_queue(oif->pktio, &pktout, 1) != 1)
+ {
+ return -1;
+ }
+
+ while (n_left > 0)
+ {
+ u32 len;
+ vlib_buffer_t *b0;
+ n_left--;
+ u32 bi = buffers[0];
+ buffers++;
+
+ do
+ {
+ b0 = vlib_get_buffer (vm, bi);
+ len = b0->current_length;
+ pkt_tbl[count] = odp_packet_alloc(om->pool, len);
+
+ if (pkt_tbl[count] == ODP_PACKET_INVALID)
+ {
+ clib_warning("odp packet alloc failed");
+ }
+
+ clib_memcpy ((u8 *) (odp_packet_data(pkt_tbl[count])),
+ vlib_buffer_get_current (b0), len);
+ count++;
+ }
+ while ((bi = b0->next_buffer) && (count < VLIB_FRAME_SIZE));
+ }
+
+ CLIB_MEMORY_BARRIER ();
+
+ sent = odp_pktout_send(pktout, pkt_tbl, count);
+ sent= sent > 0 ? sent : 0;
+
+ if (odp_unlikely( sent < count ))
+ {
+ do
+ {
+ odp_packet_free(pkt_tbl[sent]);
+ }
+ while(++sent < count );
+ }
+
+ if (PREDICT_FALSE (oif->lockp != 0))
+ *oif->lockp = 0;
+
+ vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
+
+ return frame->n_vectors;
+}
+
+static void
+odp_packet_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
+ u32 node_index)
+{
+ odp_packet_main_t *om = &odp_packet_main;
+ vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
+ odp_packet_if_t *oif = pool_elt_at_index (om->interfaces, hw->dev_instance);
+
+ if (node_index == ~0)
+ {
+ oif->per_interface_next_index = node_index;
+ return;
+ }
+
+ oif->per_interface_next_index =
+ vlib_node_add_next (vlib_get_main (), odp_packet_input_node.index,
+ node_index);
+
+}
+
+static void
+odp_packet_clear_hw_interface_counters (u32 instance)
+{
+ /* Nothing for now */
+}
+
+static clib_error_t *
+odp_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
+ u32 flags)
+{
+ odp_packet_main_t *om = &odp_packet_main;
+ vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
+ odp_packet_if_t *oif =
+ pool_elt_at_index (om->interfaces, hw->dev_instance);
+ u32 hw_flags;
+
+ oif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
+
+ if (oif->is_admin_up)
+ hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP;
+ else
+ hw_flags = 0;
+
+ vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
+
+ return 0;
+}
+
+static clib_error_t *
+odp_packet_subif_add_del_function (vnet_main_t * vnm,
+ u32 hw_if_index,
+ struct vnet_sw_interface_t *st, int is_add)
+{
+/* Nothing for now */
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VNET_DEVICE_CLASS (odp_packet_device_class) = {
+ .name = "odp-packet",
+ .tx_function = odp_packet_interface_tx,
+ .format_device_name = format_odp_packet_device_name,
+ .format_device = format_odp_packet_device,
+ .format_tx_trace = format_odp_packet_tx_trace,
+ .tx_function_n_errors = ODP_PACKET_TX_N_ERROR,
+ .tx_function_error_strings = odp_packet_tx_func_error_strings,
+ .rx_redirect_to_node = odp_packet_set_interface_next_node,
+ .clear_counters = odp_packet_clear_hw_interface_counters,
+ .admin_up_down_function = odp_packet_interface_admin_up_down,
+ .subif_add_del_function = odp_packet_subif_add_del_function,
+};
+
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (odp_packet_device_class,
+ odp_packet_interface_tx)
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/node.c b/src/plugins/odp/node.c
new file mode 100755
index 00000000..79892ce3
--- /dev/null
+++ b/src/plugins/odp/node.c
@@ -0,0 +1,334 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * 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 <linux/if_packet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/devices/devices.h>
+#include <vnet/feature/feature.h>
+#include <odp/odp_packet.h>
+
+#define foreach_odp_packet_input_error
+
+typedef enum
+{
+#define _(f,s) ODP_PACKET_INPUT_ERROR_##f,
+ foreach_odp_packet_input_error
+#undef _
+ ODP_PACKET_INPUT_N_ERROR,
+} odp_packet_input_error_t;
+
+static char *odp_packet_input_error_strings[] = {
+#define _(n,s) s,
+ foreach_odp_packet_input_error
+#undef _
+};
+
+typedef struct
+{
+ u32 next_index;
+ u32 hw_if_index;
+ odp_packet_t pkt;
+} odp_packet_input_trace_t;
+
+static u8 *
+format_odp_packet_input_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ odp_packet_input_trace_t *t = va_arg (*args, odp_packet_input_trace_t *);
+
+ s = format (s, "odp_packet: hw_if_index %d next-index %d",
+ t->hw_if_index, t->next_index);
+
+ return s;
+}
+
+always_inline void
+buffer_add_to_chain (vlib_main_t * vm, u32 bi, u32 first_bi, u32 prev_bi)
+{
+ vlib_buffer_t *b = vlib_get_buffer (vm, bi);
+ vlib_buffer_t *first_b = vlib_get_buffer (vm, first_bi);
+ vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_bi);
+
+ /* update first buffer */
+ first_b->total_length_not_including_first_buffer += b->current_length;
+
+ /* update previous buffer */
+ prev_b->next_buffer = bi;
+ prev_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
+
+ /* update current buffer */
+ b->next_buffer = 0;
+
+
+}
+
+always_inline int
+odp_packet_queue_mode (odp_pktio_t pktio, u32 mode, odp_packet_t pkt_tbl[])
+{
+ u32 num_evts = 0, num_pkts = 0, i = 0;
+ odp_queue_t inq;
+ odp_event_t evt_tbl[VLIB_FRAME_SIZE];
+ u64 sched_wait = odp_schedule_wait_time(ODP_TIME_MSEC_IN_NS * 100);
+
+ if (pktio == ODP_PKTIO_INVALID)
+ {
+ clib_warning("odp_pktio_lookup() failed");
+ return -1;
+ }
+
+ inq = ODP_QUEUE_INVALID;
+ if ((mode == APPL_MODE_PKT_QUEUE) &&
+ (odp_pktin_event_queue(pktio, &inq, 1) != 1))
+ {
+ clib_warning("Error:no input queue");
+ return -1;
+ }
+
+ if (inq != ODP_QUEUE_INVALID)
+ num_evts = odp_queue_deq_multi(inq, evt_tbl, VLIB_FRAME_SIZE);
+ else
+ num_evts = odp_schedule_multi(NULL, sched_wait, evt_tbl, VLIB_FRAME_SIZE);
+
+ /* convert events to packets, discarding any non-packet events */
+ for (i = 0; i < num_evts; ++i)
+ {
+ if (odp_event_type(evt_tbl[i]) == ODP_EVENT_PACKET)
+ pkt_tbl[num_pkts++] = odp_packet_from_event(evt_tbl[i]);
+ else
+ odp_event_free(evt_tbl[i]);
+ }
+
+ return num_pkts;
+
+}
+
+always_inline int
+odp_packet_burst_mode (odp_pktio_t pktio, odp_pktin_queue_t pktin, odp_packet_t pkt_tbl[])
+{
+ u32 num_pkts;
+
+ if (odp_pktin_queue(pktio, &pktin, 1) != 1)
+ {
+ clib_warning("odp_pktio_open() failed: no pktin queue");
+ return -1;
+ }
+
+ num_pkts = odp_pktin_recv(pktin, pkt_tbl, VLIB_FRAME_SIZE);
+
+ return num_pkts;
+
+}
+
+always_inline uword
+odp_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame, odp_packet_if_t *oif)
+{
+ u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
+ uword n_trace = vlib_get_trace_count (vm, node);
+ odp_packet_main_t *om = &odp_packet_main;
+ u32 n_rx_packets = 0;
+ u32 n_rx_bytes = 0;
+ u32 *to_next = 0;
+ u32 n_free_bufs;
+ u32 thread_index = vlib_get_thread_index();
+ odp_pktin_queue_t pktin = { 0 };
+ odp_packet_t pkt,pkt_tbl[VLIB_FRAME_SIZE];
+ u32 pkts = 0, pkts_ok = 0;
+ u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm,
+ VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
+
+ if (oif->per_interface_next_index != ~0)
+ next_index = oif->per_interface_next_index;
+
+ n_free_bufs = vec_len (om->rx_buffers[thread_index]);
+ if (PREDICT_FALSE (n_free_bufs < VLIB_FRAME_SIZE))
+ {
+ vec_validate (om->rx_buffers[thread_index],
+ VLIB_FRAME_SIZE + n_free_bufs - 1);
+ n_free_bufs +=
+ vlib_buffer_alloc (vm, &om->rx_buffers[thread_index][n_free_bufs],
+ VLIB_FRAME_SIZE);
+ _vec_len (om->rx_buffers[thread_index]) = n_free_bufs;
+
+ }
+
+ if ((oif->mode ==( APPL_MODE_PKT_QUEUE)) ||
+ (oif->mode ==(APPL_MODE_PKT_SCHED)))
+ {
+ pkts = odp_packet_queue_mode(oif->pktio, oif->mode, pkt_tbl);
+ }
+ else
+ {
+ pkts = odp_packet_burst_mode(oif->pktio, pktin, pkt_tbl);
+ }
+
+ if (pkts > 0)
+ {
+ u32 n_left_to_next,i = 0;
+ u32 next0 = next_index;
+ pkts_ok = drop_err_pkts(pkt_tbl, pkts);
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while((i < pkts_ok) && (n_left_to_next) && (n_free_bufs))
+ {
+ vlib_buffer_t *first_b0 = 0;
+ u32 offset = 0;
+ u32 bi0 = 0, first_bi0 = 0, prev_bi0;
+ uint8_t *data_buf;
+ pkt = pkt_tbl[i];
+ u32 data_len = odp_packet_len(pkt);
+ data_buf = malloc(data_len);
+ memset(data_buf, 0, data_len);
+ odp_packet_copy_to_mem(pkt, 0, data_len, data_buf);
+
+ while (data_len && n_free_bufs)
+ {
+ vlib_buffer_t *b0;
+ /* grab free buffer */
+ u32 last_empty_buffer =
+ vec_len (om->rx_buffers[thread_index]) - 1;
+ prev_bi0 = bi0;
+ bi0 = om->rx_buffers[thread_index][last_empty_buffer];
+ b0 = vlib_get_buffer (vm, bi0);
+ _vec_len (om->rx_buffers[thread_index]) = last_empty_buffer;
+ n_free_bufs--;
+ /* copy data */
+ u32 bytes_to_copy =
+ data_len > n_buffer_bytes ? n_buffer_bytes : data_len;
+ b0->current_data = 0;
+ clib_memcpy (vlib_buffer_get_current (b0),
+ (u8 *) data_buf + offset,
+ bytes_to_copy);
+
+ /* fill buffer header */
+ b0->current_length = bytes_to_copy;
+
+ if (offset == 0)
+ {
+ b0->total_length_not_including_first_buffer = 0;
+ b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
+ vnet_buffer (b0)->sw_if_index[VLIB_RX] =
+ oif->sw_if_index;
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
+ first_bi0 = bi0;
+ first_b0 = vlib_get_buffer (vm, first_bi0);
+ }
+ else
+ {
+ buffer_add_to_chain (vm, bi0, first_bi0, prev_bi0);
+ }
+
+ offset += bytes_to_copy;
+ data_len -= bytes_to_copy;
+ }
+ /* trace */
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (first_b0);
+ if (PREDICT_FALSE (n_trace > 0))
+ {
+ odp_packet_input_trace_t *tr;
+ vlib_trace_buffer (vm, node, next0, first_b0, 0);
+ vlib_set_trace_count (vm, node, --n_trace);
+ tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr));
+ tr->next_index = next0;
+ tr->hw_if_index = oif->hw_if_index;
+ }
+
+ /* redirect if feature path enabled */
+ vnet_feature_start_device_input_x1 (oif->sw_if_index, &next0,
+ first_b0);
+
+ /* enque and take next packet */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, first_bi0,
+ next0);
+
+ /* next packet */
+ n_rx_packets++;
+ n_rx_bytes += odp_packet_len(pkt);
+ to_next[0] = first_bi0;
+ to_next += 1;
+ n_left_to_next--;
+ free(data_buf);
+ odp_packet_free(pkt_tbl[i]);
+ i++;
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+
+ }
+
+ vlib_increment_combined_counter(vnet_get_main ()->interface_main.combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_RX,
+ vlib_get_thread_index (), oif->hw_if_index, n_rx_packets, n_rx_bytes);
+
+ return n_rx_packets;
+
+}
+
+static uword
+odp_packet_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+
+ int i;
+ u32 n_rx_packets = 0;
+ u32 thread_index = vlib_get_thread_index ();
+ odp_packet_main_t *om = &odp_packet_main;
+ odp_packet_if_t *oif;
+
+ for (i = 0; i < vec_len (om->interfaces); i++)
+ {
+ oif = vec_elt_at_index (om->interfaces, i);
+
+ if (oif->is_admin_up &&
+ (i % om->input_cpu_count) ==
+ (thread_index - om->input_cpu_first_index))
+ {
+ n_rx_packets += odp_packet_device_input_fn (vm, node, frame, oif);
+ }
+ }
+
+ return n_rx_packets;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (odp_packet_input_node) = {
+ .function = odp_packet_input_fn,
+ .name = "odp-packet-input",
+ .sibling_of = "device-input",
+ .format_trace = format_odp_packet_input_trace,
+ .type = VLIB_NODE_TYPE_INPUT,
+ .state = VLIB_NODE_STATE_DISABLED,
+ .n_errors = ODP_PACKET_INPUT_N_ERROR,
+ .error_strings = odp_packet_input_error_strings,
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (odp_packet_input_node, odp_packet_input_fn)
+/* *INDENT-ON* */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/odp_packet.c b/src/plugins/odp/odp_packet.c
new file mode 100755
index 00000000..a8c606d8
--- /dev/null
+++ b/src/plugins/odp/odp_packet.c
@@ -0,0 +1,363 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * 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 <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+#include <odp/odp_packet.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+static u32
+odp_packet_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
+ u32 flags)
+{
+ /* nothing for now */
+ return 0;
+}
+
+/**
+ * Drop packets which input parsing marked as containing errors.
+ *
+ * Frees packets with error and modifies pkt_tbl[] to only contain packets with
+ * no detected errors.
+ *
+ * @param pkt_tbl Array of packet
+ * @param len Length of pkt_tbl[]
+ *
+ * @return Number of packets with no detected error
+ */
+u32
+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_has_error(pkt)))
+ {
+ odp_packet_free(pkt); /* Drop */
+ pkt_cnt--;
+ }
+ else if (odp_unlikely(i != j++))
+ {
+ pkt_tbl[j-1] = pkt;
+ }
+ }
+
+ return pkt_cnt;
+}
+
+static odp_pktio_t
+create_pktio(const char *dev, odp_pool_t pool, u32 mode)
+{
+ odp_pktio_t pktio;
+ int ret;
+ odp_pktio_param_t pktio_param;
+ odp_pktin_queue_param_t pktin_param;
+
+ odp_pktio_param_init(&pktio_param);
+
+ switch(mode)
+ {
+ case APPL_MODE_PKT_BURST:
+ pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT;
+ break;
+ case APPL_MODE_PKT_QUEUE:
+ pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE;
+ break;
+ case APPL_MODE_PKT_SCHED:
+ pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
+ break;
+ default:
+ clib_warning("Invalid mode\n");
+ }
+
+ /* Open a packet IO instance */
+ pktio = odp_pktio_open(dev, pool, &pktio_param);
+
+ if (pktio == ODP_PKTIO_INVALID)
+ {
+ clib_warning("Error: pktio create failed for %s",dev);
+ }
+
+ odp_pktin_queue_param_init(&pktin_param);
+
+ if (mode == APPL_MODE_PKT_SCHED)
+ pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC;
+
+ if (odp_pktin_queue_config(pktio, &pktin_param))
+ {
+ clib_warning("Error: pktin config failed");
+ }
+
+ if (odp_pktout_queue_config(pktio, NULL))
+ {
+ clib_warning("Error: pktout config failed");
+ }
+
+ ret = odp_pktio_start(pktio);
+ if (ret != 0)
+ {
+ clib_warning("Error: unable to start");
+ }
+
+ return pktio;
+}
+
+int
+odp_worker_thread_enable ()
+{
+
+ /*If worker threads are enabled, switch to polling mode */
+ foreach_vlib_main ((
+ {
+ vlib_node_set_state (this_vlib_main,
+ odp_packet_input_node.index,
+ VLIB_NODE_STATE_POLLING);
+ }));
+ return 0;
+}
+
+int
+odp_worker_thread_disable ()
+{
+ foreach_vlib_main ((
+ {
+ vlib_node_set_state (this_vlib_main,
+ odp_packet_input_node.index,
+ VLIB_NODE_STATE_DISABLED);
+ }));
+
+ return 0;
+}
+
+u32
+odp_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set,
+ u32 * sw_if_index , u32 mode)
+{
+ odp_packet_main_t *om = &odp_packet_main;
+ int ret = 0;
+ odp_packet_if_t *oif = 0;
+ u8 hw_addr[6];
+ clib_error_t *error = 0;
+ vnet_sw_interface_t *sw;
+ vnet_main_t *vnm = vnet_get_main ();
+ uword *p;
+ u8 *host_if_name_dup=vec_dup(host_if_name);
+ vlib_thread_main_t *tm= vlib_get_thread_main();
+
+ p = mhash_get (&om->if_index_by_host_if_name, host_if_name);
+ if (p)
+ return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
+
+ pool_get (om->interfaces, oif);
+ oif->if_index = oif - om->interfaces;
+ oif->host_if_name = host_if_name_dup;
+ oif->per_interface_next_index= ~0;
+
+ /* Create a pktio instance */
+ oif->pktio=create_pktio((char*)host_if_name, om->pool, mode);
+ oif->mode=mode;
+ om->if_count++;
+
+ if (tm->n_vlib_mains > 1)
+ {
+ oif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES);
+ memset ((void *) oif->lockp, 0, CLIB_CACHE_LINE_BYTES);
+ }
+
+ /*use configured or generate random MAC address */
+ if (hw_addr_set)
+ clib_memcpy (hw_addr, hw_addr_set, 6);
+ else
+ {
+ f64 now = vlib_time_now (vm);
+ u32 rnd;
+ rnd = (u32) (now * 1e6);
+ rnd = random_u32 (&rnd);
+
+ clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
+ hw_addr[0] = 2;
+ hw_addr[1] = 0xfe;
+ }
+
+ error = ethernet_register_interface (vnm, odp_packet_device_class.index,
+ oif->if_index, hw_addr, &oif->hw_if_index, odp_packet_eth_flag_change);
+
+ if (error)
+ {
+ memset (oif, 0, sizeof (*oif));
+ pool_put (om->interfaces, oif);
+ clib_error_report (error);
+ ret = VNET_API_ERROR_SYSCALL_ERROR_1;
+ goto error;
+ }
+
+ sw = vnet_get_hw_sw_interface (vnm, oif->hw_if_index);
+ oif->sw_if_index = sw->sw_if_index;
+
+ vnet_hw_interface_set_flags (vnm, oif->hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+
+ mhash_set_mem (&om->if_index_by_host_if_name, host_if_name_dup, &oif->if_index,
+ 0);
+ if (sw_if_index)
+ *sw_if_index = oif->sw_if_index;
+
+ if (tm->n_vlib_mains > 1 && pool_elts (om->interfaces) == 1)
+ {
+ /*Fixme :Workers support commented for now as vlib_buffer not thread safe*/
+ //odp_worker_thread_enable ();
+ }
+ else
+ {
+ vlib_node_set_state (vm, odp_packet_input_node.index,
+ VLIB_NODE_STATE_POLLING);
+ }
+ return 0;
+
+ error:
+ vec_free (host_if_name_dup);
+
+ return ret;
+}
+
+u32
+odp_packet_delete_if (vlib_main_t * vm, u8 * host_if_name)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ odp_packet_main_t *om = &odp_packet_main;
+ odp_packet_if_t *oif = 0;
+ uword *p;
+ vlib_thread_main_t *tm= vlib_get_thread_main();
+
+ p = mhash_get (&om->if_index_by_host_if_name, host_if_name);
+
+ if (p == NULL)
+ {
+ clib_warning ("Host interface %s does not exist", host_if_name);
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
+ }
+
+ oif = pool_elt_at_index (om->interfaces, p[0]);
+ vnet_hw_interface_set_flags (vnm, oif->hw_if_index, 0);
+
+ om->if_count--;
+
+ odp_pktio_stop(odp_pktio_lookup((char*)host_if_name));
+ odp_pktio_close(odp_pktio_lookup((char*)host_if_name));
+
+ vec_free (oif->host_if_name);
+ oif->host_if_name = NULL;
+
+ mhash_unset (&om->if_index_by_host_if_name, host_if_name, &oif->if_index);
+ ethernet_delete_interface (vnm, oif->hw_if_index);
+
+ pool_put(om->interfaces, oif);
+
+ if (tm->n_vlib_mains > 1 && pool_elts (om->interfaces) == 0)
+ {
+ odp_pool_destroy(om->pool);
+ /*Fixme :Workers support commented for now*/
+ // odp_worker_thread_disable ();
+ }
+
+ return 0;
+
+}
+
+static clib_error_t *
+odp_packet_init (vlib_main_t * vm)
+{
+ odp_packet_main_t *om = &odp_packet_main;
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
+ vlib_thread_registration_t *tr;
+ uword *p;
+ odp_platform_init_t platform_params;
+ odp_pool_param_t params;
+
+ memset(om, 0, sizeof(odp_packet_main_t));
+ om->input_cpu_first_index = 0;
+ om->input_cpu_count = 1;
+ om->if_count = 0;
+ memset(&platform_params, 0, sizeof(platform_params));
+
+ if (odp_init_global(&om->instance, NULL, &platform_params))
+ clib_warning("Error:ODP global init failed");
+
+ if (odp_init_local(om->instance, ODP_THREAD_CONTROL) != 0)
+ {
+ clib_warning("Error: ODP local init failed");
+ odp_term_global(om->instance);
+
+ }
+ /* Create packet pool */
+ odp_pool_param_init(&params);
+ params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE;
+ params.pkt.len = SHM_PKT_POOL_BUF_SIZE;
+ params.type = ODP_POOL_PACKET;
+ params.pkt.num = SHM_PKT_POOL_NB_PKTS;
+
+ om->pool = odp_pool_create(SHM_PKT_POOL_NAME, &params);
+
+ if (om->pool == ODP_POOL_INVALID)
+ {
+ clib_warning("Error: packet pool create failed");
+ }
+
+ /* find out which cpus will be used for input */
+ p = hash_get_mem (tm->thread_registrations_by_name, "workers");
+ tr = p ? (vlib_thread_registration_t *) p[0] : 0;
+
+ if (tr && tr->count > 0)
+ {
+ om->input_cpu_first_index = tr->first_index;
+ om->input_cpu_count = tr->count;
+ }
+
+ mhash_init_vec_string (&om->if_index_by_host_if_name, sizeof (uword));
+
+ vec_validate_aligned (om->rx_buffers, tm->n_vlib_mains - 1,
+ CLIB_CACHE_LINE_BYTES);
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (odp_packet_init);
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER () = {
+ .version = VPP_BUILD_VER,
+ .description = "ODP",
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/odp_packet.h b/src/plugins/odp/odp_packet.h
new file mode 100755
index 00000000..3ece9627
--- /dev/null
+++ b/src/plugins/odp/odp_packet.h
@@ -0,0 +1,74 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * 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 <odp_api.h>
+
+#define SHM_PKT_POOL_BUF_SIZE 1856
+#define SHM_PKT_POOL_NB_PKTS 10240
+#define SHM_PKT_POOL_NAME "packet_pool"
+#define APPL_MODE_PKT_BURST 0
+#define APPL_MODE_PKT_QUEUE 1
+#define APPL_MODE_PKT_SCHED 2
+
+typedef struct
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ u8 *host_if_name;
+ volatile u32 *lockp;
+ uword if_index;
+ odp_pktio_t pktio;
+ u32 hw_if_index;
+ u32 sw_if_index;
+ u32 next_rx_frame;
+ u32 next_tx_frame;
+ u32 per_interface_next_index;
+ u8 is_admin_up;
+ u32 mode;
+} odp_packet_if_t;
+
+typedef struct
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ odp_packet_if_t *interfaces;
+ /* rx buffer cache */
+ u32 **rx_buffers;
+ u32 input_cpu_first_index;
+ u32 input_cpu_count;
+ /* hash of host interface names */
+ mhash_t if_index_by_host_if_name;
+ odp_instance_t instance;
+ odp_pool_t pool;
+ u32 if_count;
+} odp_packet_main_t;
+
+odp_packet_main_t odp_packet_main;
+extern vnet_device_class_t odp_packet_device_class;
+extern vlib_node_registration_t odp_packet_input_node;
+
+u32 odp_packet_create_if (vlib_main_t * vm, u8 * host_if_name,
+ u8 * hw_addr_set, u32 * sw_if_index, u32 mode);
+u32 odp_packet_delete_if (vlib_main_t * vm, u8 * host_if_name);
+
+u32 drop_err_pkts(odp_packet_t pkt_tbl[], u32 len);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */