DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample
@ 2015-04-16  3:55 Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 01/10] examples/tep_termination:initialize the VXLAN example Jijiang Liu
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

This VXLAN example simulates a VXLAN Tunnel endpoint(VTEP) termination in DPDK, which is used to demonstrate the offload and filtering capabilities of i40 NIC for VXLAN packet.

And this example uses the basic virtio devices management function from vHost example, and it uses us-Vhost interface and tunnel filtering mechanism to direct the traffic to/from a specific VM.

In addition, this sample is also designed to show how tunneling protocols can be handled. For the vHost interface, we do not need to support zero copy/inter VM packet transfer etc. The approach that we take would be of benefit to you in that we put a pluggable structure in place so that the application could be easily extended to support a new tunneling protocol.

The software framework is as follows:

       |-------------------|   |-------------------|
       | VM-1(VNI:100)     |   |  VM-2(VNI:200)    |
       | |------| |------| |   | |------| |------| |
       | |vport0| |vport1| |   | |vport0| |vport1| |
       |-|------|-|------|-|   |-|------|-|------|-|      Guests
                    	\           /      
         |-------------\-------/--------|
         |     us-vHost interface       |
         |          |-|----|--|         |
         |     decap| | TEP|  | encap   |       DPDK App
         |          |-|----|--|         |
         |            |    |            |
         |------------|----|------------|
                      	|    |     
        |-------------|----|---------------|
        |tunnel filter|    | IP/L4 Tx csum |
        |IP/L4 csum   |    | TSO           |
        |packet type  |    |               |               NIC
        |CRC strip    |    |               |
        |-------------|----|---------------|
                      	|    |   
                      	|    |   
                      	|    |   
                      	/-------\  
                      	VXLAN Tunnel  

The sample will support the followings:
1> Tunneling packet recognition.

2> The port of UDP tunneling is configurable

3> Directing of incoming traffic to the correct queue based on the tunnel filter type such as inner MAC address and VNI.
	The VNI will be assigned from a static internal table based on the us-vhost device ID. Each device will receive a unique device ID. The inner MAC will be learned from the first packet transmitted from a device.

4> Decapsulation of Rx VXLAN traffic. This is a software only operation(will use HW header split instead later)

5> Encapsulation of Tx VXLAN traffic. This is a software only operation

6> Tx outer IP, inner IP and L4 checksum offload

7> TSO support for tunneling packet

Limitations:
1. No ARP support
2. There are some duplicated source codes because of using the basic virtio device management function from vhost sample, but consider that current vhost sample is quite complicated and huge enough, and I think we shall have a separate sample for tunneling packet processing.
3. Currently, only the i40e NIC is supported in the sample, but other types of NICs also can be supported later if those NICs are able to support tunneling packet filter.
   

Jijiang Liu (10):
  create VXLAN sample framework using virtio device management function 
  add basic VXLAN structures 
  add VXLAN operation APIs
  support overlay operations
  Add encapsulation and decapsulation function
  add udp port configuration
  add filter type configuration
  add tx checksum offload configuration
  add TSO offload configuration
  add encapsulation and decapsulation flags

 examples/Makefile                      |    1 +
 examples/tep_termination/Makefile      |   58 ++
 examples/tep_termination/main.c        | 1117 ++++++++++++++++++++++++++++++++
 examples/tep_termination/main.h        |  113 ++++
 examples/tep_termination/vxlan.c       |  242 +++++++
 examples/tep_termination/vxlan.h       |   81 +++
 examples/tep_termination/vxlan_setup.c |  453 +++++++++++++
 examples/tep_termination/vxlan_setup.h |   76 +++
 8 files changed, 2141 insertions(+), 0 deletions(-)
 create mode 100644 examples/tep_termination/Makefile
 create mode 100644 examples/tep_termination/main.c
 create mode 100644 examples/tep_termination/main.h
 create mode 100644 examples/tep_termination/vxlan.c
 create mode 100644 examples/tep_termination/vxlan.h
 create mode 100644 examples/tep_termination/vxlan_setup.c
 create mode 100644 examples/tep_termination/vxlan_setup.h

-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 01/10] examples/tep_termination:initialize the VXLAN example
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 02/10] examples/tep_termination:define VXLAN device information and APIs Jijiang Liu
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

This example uses the basic virtio devices management function from the vHost example, which includes virtio device creation, destroying and maintenance.

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/Makefile                 |    1 +
 examples/tep_termination/Makefile |   58 +++
 examples/tep_termination/main.c   |  998 +++++++++++++++++++++++++++++++++++++
 examples/tep_termination/main.h   |  113 +++++
 4 files changed, 1170 insertions(+), 0 deletions(-)
 create mode 100644 examples/tep_termination/Makefile
 create mode 100644 examples/tep_termination/main.c
 create mode 100644 examples/tep_termination/main.h

diff --git a/examples/Makefile b/examples/Makefile
index d549026..3f08954 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -73,5 +73,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += vhost_xen
 DIRS-y += vmdq
 DIRS-y += vmdq_dcb
 DIRS-y += vm_power_manager
+DIRS-y += tep_termination 
 
 include $(RTE_SDK)/mk/rte.extsubdir.mk
diff --git a/examples/tep_termination/Makefile b/examples/tep_termination/Makefile
new file mode 100644
index 0000000..23fb647
--- /dev/null
+++ b/examples/tep_termination/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp")
+$(info This application can only operate in a linuxapp environment, \
+please change the definition of the RTE_TARGET environment variable)
+all:
+else
+
+# binary name
+APP = tep_termination
+
+# all source are stored in SRCS-y
+SRCS-y :=  main.c
+
+CFLAGS += -O2 -D_FILE_OFFSET_BITS=64
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
+
+endif
diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
new file mode 100644
index 0000000..2e36ad0
--- /dev/null
+++ b/examples/tep_termination/main.c
@@ -0,0 +1,998 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_ring.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/eventfd.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_string_fns.h>
+#include <rte_malloc.h>
+#include <rte_virtio_net.h>
+
+#include "main.h"
+
+/* the maximum number of external ports supported */
+#define MAX_SUP_PORTS 1
+
+/*
+ * Calculate the number of buffers needed per port
+ */
+#define NUM_MBUFS_PER_PORT ((MAX_QUEUES*RTE_TEST_RX_DESC_DEFAULT) +  	\
+					(num_switching_cores*MAX_PKT_BURST) + 	\
+					(num_switching_cores*RTE_TEST_TX_DESC_DEFAULT) +\
+					(num_switching_cores*MBUF_CACHE_SIZE))
+
+#define MBUF_CACHE_SIZE 128
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+
+#define MAX_PKT_BURST 32 	/* Max burst size for RX/TX */
+#define BURST_TX_DRAIN_US 100 	/* TX drain every ~100us */
+
+#define BURST_RX_RETRIES 4/* Number of retries on RX. */
+
+#define JUMBO_FRAME_MAX_SIZE    0x2600
+
+/* Config_core_flag status definitions. */
+#define REQUEST_DEV_REMOVAL 	1
+#define ACK_DEV_REMOVAL 	0
+
+#define INVALID_PORT_ID 0xFF
+
+/* Max number of virtIO device */
+#define MAX_DEVICES    64 
+
+/* Maximum character device basename size. */
+#define MAX_BASENAME_SZ 10
+
+/* Maximum long option length for option parsing. */
+#define MAX_LONG_OPT_SZ 64
+
+/* ethernet addresses of ports */
+struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
+
+uint8_t ports[RTE_MAX_ETHPORTS];
+
+static unsigned lcore_ids[RTE_MAX_LCORE];
+
+/* mask of enabled ports */
+static uint32_t enabled_port_mask = 0;
+
+/*Number of switching cores enabled*/
+static uint32_t num_switching_cores = 0;
+
+struct vpool {
+	struct rte_mempool *pool;
+	struct rte_ring *ring;
+	uint32_t buf_size;
+} vpool_array[MAX_QUEUES+MAX_QUEUES];
+
+/* number of devices */
+uint16_t num_devices;
+
+/* Enable stats. */
+static uint32_t enable_stats = 0;
+
+/* Character device basename. Can be set by user. */
+static char dev_basename[MAX_BASENAME_SZ] = "vhost-net";
+
+static unsigned num_ports = 0; /**< The number of ports specified in command line */
+
+/* heads for the main used and free linked lists for the data path. */
+struct virtio_net_data_ll *ll_root_used = NULL;
+struct virtio_net_data_ll *ll_root_free = NULL;
+
+/**
+ * Array of data core structures containing information
+ * on individual core linked lists.
+ */
+static struct lcore_info lcore_info[RTE_MAX_LCORE];
+
+/* Used for queueing bursts of TX packets. */
+struct mbuf_table {
+	unsigned len;
+	unsigned txq_id;
+	struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+/* TX queue for each data core. */
+struct mbuf_table lcore_tx_queue[RTE_MAX_LCORE];
+
+/* Per-device statistics struct */
+struct device_statistics {
+	uint64_t tx_total;
+	rte_atomic64_t rx_total_atomic;
+	uint64_t rx_total;
+	uint64_t tx;
+	rte_atomic64_t rx_atomic;
+	uint64_t rx;
+} __rte_cache_aligned;
+
+struct device_statistics dev_statistics[MAX_DEVICES];
+
+/*
+ * Set character device basename.
+ */
+static int
+tep_parse_basename(const char *q_arg)
+{
+	/* parse number string */
+
+	if (strnlen(q_arg, MAX_BASENAME_SZ) > MAX_BASENAME_SZ)
+		return -1;
+	else
+		snprintf((char*)&dev_basename, MAX_BASENAME_SZ, "%s", q_arg);
+
+	return 0;
+}
+
+/*
+ * Parse the portmask provided at run time.
+ */
+static int
+parse_portmask(const char *portmask)
+{
+	char *end = NULL;
+	unsigned long pm;
+
+	errno = 0;
+
+	/* parse hexadecimal string */
+	pm = strtoul(portmask, &end, 16);
+	if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0))
+		return -1;
+
+	if (pm == 0)
+		return -1;
+
+	return pm;
+}
+
+/*
+ * Parse num options at run time.
+ */
+static int
+parse_num_opt(const char *q_arg, uint32_t max_valid_value)
+{
+	char *end = NULL;
+	unsigned long num;
+
+	errno = 0;
+
+	/* parse unsigned int string */
+	num = strtoul(q_arg, &end, 10);
+	if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0') || (errno != 0))
+		return -1;
+
+	if (num > max_valid_value)
+		return -1;
+
+	return num;
+
+}
+
+/*
+ * Display usage
+ */
+static void
+vep_termination_usage(const char *prgname)
+{
+	RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
+	"		--nb-devices: number of virtIO device\n"
+	"		--dev-basename <name>\n"
+	"		-p PORTMASK: Set mask for ports to be used by application\n"
+	"		--stats [0-N]: 0: Disable stats, N: Time in seconds to print stats\n"
+	"		--dev-basename: The basename to be used for the character device.\n",
+	       prgname);
+}
+
+/*
+ * Parse the arguments given in the command line of the application.
+ */
+static int
+tep_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	int option_index;
+	unsigned i;
+	const char *prgname = argv[0];
+	static struct option long_option[] = {
+		{"nb-devices", required_argument, NULL, 0},
+		{"stats", required_argument, NULL, 0},
+		{"dev-basename", required_argument, NULL, 0},
+		{NULL, 0, 0, 0},
+	};
+
+	/* Parse command line */
+	while ((opt = getopt_long(argc, argv, "p:P",
+			long_option, &option_index)) != EOF) {
+		switch (opt) {
+		/* Portmask */
+		case 'p':
+			enabled_port_mask = parse_portmask(optarg);
+			if (enabled_port_mask == 0) {
+				RTE_LOG(INFO, VHOST_CONFIG, "Invalid portmask\n");
+				vep_termination_usage(prgname);
+				return -1;
+			}
+			break;
+
+		case 0:
+			if (!strncmp(long_option[option_index].name, "nb-devices", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, MAX_DEVICES);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for nb-devices [0-%d]\n", MAX_DEVICES);
+					vep_termination_usage(prgname);
+					return -1;
+				} else 
+					num_devices = ret;
+			}
+
+			/* Enable/disable stats. */
+			if (!strncmp(long_option[option_index].name, "stats", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, INT32_MAX);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for stats [0..N]\n");
+					vep_termination_usage(prgname);
+					return -1;
+				} else
+					enable_stats = ret;
+			}
+
+			/* Set character device basename. */
+			if (!strncmp(long_option[option_index].name, "dev-basename", MAX_LONG_OPT_SZ)) {
+				if (tep_parse_basename(optarg) == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for character device "
+							 "basename (Max %d characters)\n", MAX_BASENAME_SZ);
+					vep_termination_usage(prgname);
+					return -1;
+				}
+			}
+
+			break;
+
+			/* Invalid option - print options. */
+		default:
+			vep_termination_usage(prgname);
+			return -1;
+		}
+	}
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (enabled_port_mask & (1 << i))
+			ports[num_ports++] = (uint8_t)i;
+	}
+
+	if ((num_ports ==  0) || (num_ports > MAX_SUP_PORTS)) {
+		RTE_LOG(INFO, VHOST_PORT, "Current enabled port number is %u,"
+			"but only %u port can be enabled\n",num_ports, MAX_SUP_PORTS);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Update the global var NUM_PORTS and array PORTS according to system ports number
+ * and return valid ports number
+ */
+static unsigned check_ports_num(unsigned nb_ports)
+{
+	unsigned valid_num_ports = num_ports;
+	unsigned portid;
+
+	if (num_ports > nb_ports) {
+		RTE_LOG(INFO, VHOST_PORT, "\nSpecified port number(%u) exceeds total system port number(%u)\n",
+			num_ports, nb_ports);
+		num_ports = nb_ports;
+	}
+
+	for (portid = 0; portid < num_ports; portid ++) {
+		if (ports[portid] >= nb_ports) {
+			RTE_LOG(INFO, VHOST_PORT, "\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
+				ports[portid], (nb_ports - 1));
+			ports[portid] = INVALID_PORT_ID;
+			valid_num_ports--;
+		}
+	}
+	return valid_num_ports;
+}
+
+/*
+ * This function routes the TX packet to the correct interface. This may be a local device
+ * or the physical port.
+ */
+static inline void __attribute__((always_inline))
+virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m, __attribute__((unused)) uint16_t vlan_tag)
+{
+	struct mbuf_table *tx_q;
+	struct rte_mbuf **m_table;
+	unsigned len, ret = 0;
+
+	const uint16_t lcore_id = rte_lcore_id();
+	struct virtio_net *dev = vdev->dev;
+	
+	LOG_DEBUG(VHOST_DATA, "(%"PRIu64") TX: MAC address is external\n", dev->device_fh);
+
+	/*Add packet to the port tx queue*/
+	tx_q = &lcore_tx_queue[lcore_id];
+	len = tx_q->len;
+	tx_q->m_table[len] = m;
+	len++;
+	if (enable_stats) {
+		dev_statistics[dev->device_fh].tx_total++;
+		dev_statistics[dev->device_fh].tx++;
+	}
+
+	if (unlikely(len == MAX_PKT_BURST)) {
+		m_table = (struct rte_mbuf **)tx_q->m_table;
+		/* Free any buffers not handled by TX and update the port stats. */
+		if (unlikely(ret < len)) {
+			do {
+				rte_pktmbuf_free(m_table[ret]);
+			} while (++ret < len);
+		}
+
+		len = 0;
+	}
+
+	tx_q->len = len;
+	return;
+}
+
+/*
+ * This function is called by each data core. It handles all RX/TX registered with the
+ * core. For TX the specific lcore linked list is used. For RX, MAC addresses are compared
+ * with all devices in the main linked list.
+ */
+static int
+switch_worker(__attribute__((unused)) void *arg)
+{
+	struct rte_mempool *mbuf_pool = arg;
+	struct virtio_net *dev = NULL;
+	struct vhost_dev *vdev = NULL;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *mbuf_tmp = NULL;
+	struct virtio_net_data_ll *dev_ll;
+	struct mbuf_table *tx_q;
+	volatile struct lcore_ll_info *lcore_ll;
+	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+	uint64_t prev_tsc, diff_tsc, cur_tsc, ret_count = 0;
+	unsigned ret = 0, i;
+	const uint16_t lcore_id = rte_lcore_id();
+	const uint16_t num_cores = (uint16_t)rte_lcore_count();
+	uint16_t rx_count = 0;
+	uint16_t tx_count;
+
+	RTE_LOG(INFO, VHOST_DATA, "Procesing on Core %u started\n", lcore_id);
+	lcore_ll = lcore_info[lcore_id].lcore_ll;
+	prev_tsc = 0;
+
+	tx_q = &lcore_tx_queue[lcore_id];
+	for (i = 0; i < num_cores; i ++) {
+		if (lcore_ids[i] == lcore_id) {
+			tx_q->txq_id = i;
+			break;
+		}
+	}
+
+	while(1) {
+		cur_tsc = rte_rdtsc();
+		/*
+		 * TX burst queue drain
+		 */
+		diff_tsc = cur_tsc - prev_tsc;
+		if (unlikely(diff_tsc > drain_tsc)) {
+
+			if (tx_q->len) {
+				LOG_DEBUG(VHOST_DATA, "TX queue drained after timeout with burst size %u \n", tx_q->len);
+				if (unlikely(ret < tx_q->len)) {
+					do {
+						rte_pktmbuf_free(tx_q->m_table[ret]);
+					} while (++ret < tx_q->len);
+				}
+
+				tx_q->len = 0;
+			}
+
+			prev_tsc = cur_tsc;
+
+		}
+
+		rte_prefetch0(lcore_ll->ll_root_used);
+		/*
+		 * Inform the configuration core that we have exited the linked list and that no devices are
+		 * in use if requested.
+		 */
+		if (lcore_ll->dev_removal_flag == REQUEST_DEV_REMOVAL)
+			lcore_ll->dev_removal_flag = ACK_DEV_REMOVAL;
+
+		/*
+		 * Process devices
+		 */
+		dev_ll = lcore_ll->ll_root_used;
+
+		while (dev_ll != NULL) {
+			/*get virtio device ID*/
+			vdev = dev_ll->vdev;
+			dev = vdev->dev;
+
+			if (unlikely(vdev->remove)) {
+				dev_ll = dev_ll->next;
+				vdev->ready = DEVICE_SAFE_REMOVE;
+				continue;
+			}
+
+			if (likely(vdev->ready == DEVICE_RX)) {
+				/*Handle guest RX*/
+				rx_count = rte_eth_rx_burst(ports[0],
+					vdev->rx_q, pkts_burst, MAX_PKT_BURST);
+
+				if (rx_count) {
+					if (enable_stats) {
+						rte_atomic64_add(
+						&dev_statistics[dev_ll->vdev->dev->device_fh].rx_total_atomic,
+						rx_count);
+						rte_atomic64_add(
+						&dev_statistics[dev_ll->vdev->dev->device_fh].rx_atomic, ret_count);
+					}
+					while (likely(rx_count)) {
+						rx_count--;
+						rte_pktmbuf_free(pkts_burst[rx_count]);
+					}
+
+				}
+			}
+
+			if (likely(!vdev->remove)) {
+				/* Handle guest TX*/
+				tx_count = rte_vhost_dequeue_burst(dev, VIRTIO_TXQ, mbuf_pool, pkts_burst, MAX_PKT_BURST);
+				/* If this is the first received packet we need to learn the MAC */
+				if (unlikely(vdev->ready == DEVICE_MAC_LEARNING) && tx_count) {
+					if (vdev->remove) {
+						while (tx_count) {
+							mbuf_tmp = pkts_burst[--tx_count];
+							if (mbuf_tmp)
+								rte_pktmbuf_free(mbuf_tmp);
+						}
+					}
+				}
+				while (tx_count) {
+					mbuf_tmp = pkts_burst[--tx_count];
+					if (mbuf_tmp)
+						virtio_tx_route(vdev, mbuf_tmp, (uint16_t)dev->device_fh);
+				}
+			}
+
+			/*move to the next device in the list*/
+			dev_ll = dev_ll->next;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Add an entry to a used linked list. A free entry must first be found
+ * in the free linked list using get_data_ll_free_entry();
+ */
+static void
+add_data_ll_entry(struct virtio_net_data_ll **ll_root_addr,
+	struct virtio_net_data_ll *ll_dev)
+{
+	struct virtio_net_data_ll *ll = *ll_root_addr;
+
+	/* Set next as NULL and use a compiler barrier to avoid reordering. */
+	ll_dev->next = NULL;
+	rte_compiler_barrier();
+
+	/* If ll == NULL then this is the first device. */
+	if (ll) {
+		/* Increment to the tail of the linked list. */
+		while ((ll->next != NULL) )
+			ll = ll->next;
+
+		ll->next = ll_dev;
+	} else {
+		*ll_root_addr = ll_dev;
+	}
+}
+
+/*
+ * Remove an entry from a used linked list. The entry must then be added to
+ * the free linked list using put_data_ll_free_entry().
+ */
+static void
+rm_data_ll_entry(struct virtio_net_data_ll **ll_root_addr,
+	struct virtio_net_data_ll *ll_dev,
+	struct virtio_net_data_ll *ll_dev_last)
+{
+	struct virtio_net_data_ll *ll = *ll_root_addr;
+
+	if (unlikely((ll == NULL) || (ll_dev == NULL)))
+		return;
+
+	if (ll_dev == ll)
+		*ll_root_addr = ll_dev->next;
+	else
+		if (likely(ll_dev_last != NULL))
+			ll_dev_last->next = ll_dev->next;
+		else
+			RTE_LOG(ERR, VHOST_CONFIG, "Remove entry form ll failed.\n");
+}
+
+/*
+ * Find and return an entry from the free linked list.
+ */
+static struct virtio_net_data_ll *
+get_data_ll_free_entry(struct virtio_net_data_ll **ll_root_addr)
+{
+	struct virtio_net_data_ll *ll_free = *ll_root_addr;
+	struct virtio_net_data_ll *ll_dev;
+
+	if (ll_free == NULL)
+		return NULL;
+
+	ll_dev = ll_free;
+	*ll_root_addr = ll_free->next;
+
+	return ll_dev;
+}
+
+/*
+ * Place an entry back on to the free linked list.
+ */
+static void
+put_data_ll_free_entry(struct virtio_net_data_ll **ll_root_addr,
+	struct virtio_net_data_ll *ll_dev)
+{
+	struct virtio_net_data_ll *ll_free = *ll_root_addr;
+
+	if (ll_dev == NULL)
+		return;
+
+	ll_dev->next = ll_free;
+	*ll_root_addr = ll_dev;
+}
+
+/*
+ * Creates a linked list of a given size.
+ */
+static struct virtio_net_data_ll *
+alloc_data_ll(uint32_t size)
+{
+	struct virtio_net_data_ll *ll_new;
+	uint32_t i;
+
+	/* Malloc and then chain the linked list. */
+	ll_new = malloc(size * sizeof(struct virtio_net_data_ll));
+	if (ll_new == NULL) {
+		RTE_LOG(ERR, VHOST_CONFIG, "Failed to allocate memory for ll_new.\n");
+		return NULL;
+	}
+
+	for (i = 0; i < size - 1; i++) {
+		ll_new[i].vdev = NULL;
+		ll_new[i].next = &ll_new[i+1];
+	}
+	ll_new[i].next = NULL;
+
+	return (ll_new);
+}
+
+/*
+ * Create the main linked list along with each individual cores linked list. A used and a free list
+ * are created to manage entries.
+ */
+static int
+init_data_ll (void)
+{
+	int lcore;
+
+	RTE_LCORE_FOREACH_SLAVE(lcore) {
+		lcore_info[lcore].lcore_ll = malloc(sizeof(struct lcore_ll_info));
+		if (lcore_info[lcore].lcore_ll == NULL) {
+			RTE_LOG(ERR, VHOST_CONFIG, "Failed to allocate memory for lcore_ll.\n");
+			return -1;
+		}
+
+		lcore_info[lcore].lcore_ll->device_num = 0;
+		lcore_info[lcore].lcore_ll->dev_removal_flag = ACK_DEV_REMOVAL;
+		lcore_info[lcore].lcore_ll->ll_root_used = NULL;
+		if (num_devices % num_switching_cores)
+			lcore_info[lcore].lcore_ll->ll_root_free = alloc_data_ll((num_devices / num_switching_cores) + 1);
+		else
+			lcore_info[lcore].lcore_ll->ll_root_free = alloc_data_ll(num_devices / num_switching_cores);
+	}
+
+	/* Allocate devices up to a maximum of MAX_DEVICES. */
+	ll_root_free = alloc_data_ll(MIN((num_devices), MAX_DEVICES));
+
+	return 0;
+}
+
+/*
+ * Remove a device from the specific data core linked list and from the main linked list. Synchonization
+ * occurs through the use of the lcore dev_removal_flag. Device is made volatile here to avoid re-ordering
+ * of dev->remove=1 which can cause an infinite loop in the rte_pause loop.
+ */
+static void
+destroy_device (volatile struct virtio_net *dev)
+{
+	struct virtio_net_data_ll *ll_lcore_dev_cur;
+	struct virtio_net_data_ll *ll_main_dev_cur;
+	struct virtio_net_data_ll *ll_lcore_dev_last = NULL;
+	struct virtio_net_data_ll *ll_main_dev_last = NULL;
+	struct vhost_dev *vdev;
+	int lcore;
+
+	dev->flags &= ~VIRTIO_DEV_RUNNING;
+
+	vdev = (struct vhost_dev *)dev->priv;
+	/*set the remove flag. */
+	vdev->remove = 1;
+	while(vdev->ready != DEVICE_SAFE_REMOVE) {
+		rte_pause();
+	}
+
+	/* Search for entry to be removed from lcore ll */
+	ll_lcore_dev_cur = lcore_info[vdev->coreid].lcore_ll->ll_root_used;
+	while (ll_lcore_dev_cur != NULL) {
+		if (ll_lcore_dev_cur->vdev == vdev) {
+			break;
+		} else {
+			ll_lcore_dev_last = ll_lcore_dev_cur;
+			ll_lcore_dev_cur = ll_lcore_dev_cur->next;
+		}
+	}
+
+	if (ll_lcore_dev_cur == NULL) {
+		RTE_LOG(ERR, VHOST_CONFIG,
+			"(%"PRIu64") Failed to find the dev to be destroy.\n",
+			dev->device_fh);
+		return;
+	}
+
+	/* Search for entry to be removed from main ll */
+	ll_main_dev_cur = ll_root_used;
+	ll_main_dev_last = NULL;
+	while (ll_main_dev_cur != NULL) {
+		if (ll_main_dev_cur->vdev == vdev) {
+			break;
+		} else {
+			ll_main_dev_last = ll_main_dev_cur;
+			ll_main_dev_cur = ll_main_dev_cur->next;
+		}
+	}
+
+	/* Remove entries from the lcore and main ll. */
+	rm_data_ll_entry(&lcore_info[vdev->coreid].lcore_ll->ll_root_used, ll_lcore_dev_cur, ll_lcore_dev_last);
+	rm_data_ll_entry(&ll_root_used, ll_main_dev_cur, ll_main_dev_last);
+
+	/* Set the dev_removal_flag on each lcore. */
+	RTE_LCORE_FOREACH_SLAVE(lcore) {
+		lcore_info[lcore].lcore_ll->dev_removal_flag = REQUEST_DEV_REMOVAL;
+	}
+
+	/*
+	 * Once each core has set the dev_removal_flag to ACK_DEV_REMOVAL we can be sure that
+	 * they can no longer access the device removed from the linked lists and that the devices
+	 * are no longer in use.
+	 */
+	RTE_LCORE_FOREACH_SLAVE(lcore) {
+		while (lcore_info[lcore].lcore_ll->dev_removal_flag != ACK_DEV_REMOVAL) {
+			rte_pause();
+		}
+	}
+
+	/* Add the entries back to the lcore and main free ll.*/
+	put_data_ll_free_entry(&lcore_info[vdev->coreid].lcore_ll->ll_root_free, ll_lcore_dev_cur);
+	put_data_ll_free_entry(&ll_root_free, ll_main_dev_cur);
+
+	/* Decrement number of device on the lcore. */
+	lcore_info[vdev->coreid].lcore_ll->device_num--;
+
+	RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") Device has been removed from data core\n", dev->device_fh);
+
+	rte_free(vdev);
+
+}
+
+/*
+ * A new device is added to a data core. First the device is added to the main linked list
+ * and the allocated to a specific data core.
+ */
+static int
+new_device (struct virtio_net *dev)
+{
+	struct virtio_net_data_ll *ll_dev;
+	int lcore, core_add = 0;
+	uint32_t device_num_min = num_devices;
+	struct vhost_dev *vdev;
+
+	vdev = rte_zmalloc("vhost device", sizeof(*vdev), RTE_CACHE_LINE_SIZE);
+	if (vdev == NULL) {
+		RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") Couldn't allocate memory for vhost dev\n",
+			dev->device_fh);
+		return -1;
+	}
+	vdev->dev = dev;
+	dev->priv = vdev;
+
+	/* Add device to main ll */
+	ll_dev = get_data_ll_free_entry(&ll_root_free);
+	if (ll_dev == NULL) {
+		RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") No free entry found in linked list. Device limit "
+			"of %d devices per core has been reached\n",
+			dev->device_fh, num_devices);
+		if (vdev->regions_hpa)
+			rte_free(vdev->regions_hpa);
+		rte_free(vdev);
+		return -1;
+	}
+	ll_dev->vdev = vdev;
+	add_data_ll_entry(&ll_root_used, ll_dev);
+	vdev->rx_q = dev->device_fh; 
+	
+	/*reset ready flag*/
+	vdev->ready = DEVICE_MAC_LEARNING;
+	vdev->remove = 0;
+
+	/* Find a suitable lcore to add the device. */
+	RTE_LCORE_FOREACH_SLAVE(lcore) {
+		if (lcore_info[lcore].lcore_ll->device_num < device_num_min) {
+			device_num_min = lcore_info[lcore].lcore_ll->device_num;
+			core_add = lcore;
+		}
+	}
+	/* Add device to lcore ll */
+	ll_dev = get_data_ll_free_entry(&lcore_info[core_add].lcore_ll->ll_root_free);
+	if (ll_dev == NULL) {
+		RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") Failed to add device to data core\n", dev->device_fh);
+		vdev->ready = DEVICE_SAFE_REMOVE;
+		destroy_device(dev);
+		if (vdev->regions_hpa)
+			rte_free(vdev->regions_hpa);
+		rte_free(vdev);
+		return -1;
+	}
+	ll_dev->vdev = vdev;
+	vdev->coreid = core_add;
+
+	add_data_ll_entry(&lcore_info[vdev->coreid].lcore_ll->ll_root_used, ll_dev);
+
+	/* Initialize device stats */
+	memset(&dev_statistics[dev->device_fh], 0, sizeof(struct device_statistics));
+
+	/* Disable notifications. */
+	rte_vhost_enable_guest_notification(dev, VIRTIO_RXQ, 0);
+	rte_vhost_enable_guest_notification(dev, VIRTIO_TXQ, 0);
+	lcore_info[vdev->coreid].lcore_ll->device_num++;
+	dev->flags |= VIRTIO_DEV_RUNNING;
+
+	RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") Device has been added to data core %d\n", dev->device_fh, vdev->coreid);
+
+	return 0;
+}
+
+/*
+ * These callback allow devices to be added to the data core when configuration
+ * has been fully complete.
+ */
+static const struct virtio_net_device_ops virtio_net_device_ops =
+{
+	.new_device =  new_device,
+	.destroy_device = destroy_device,
+};
+
+/*
+ * This is a thread will wake up after a period to print stats if the user has
+ * enabled them.
+ */
+static void
+print_stats(void)
+{
+	struct virtio_net_data_ll *dev_ll;
+	uint64_t tx_dropped, rx_dropped;
+	uint64_t tx, tx_total, rx, rx_total;
+	uint32_t device_fh;
+	const char clr[] = { 27, '[', '2', 'J', '\0' };
+	const char top_left[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+	while(1) {
+		sleep(enable_stats);
+
+		/* Clear screen and move to top left */
+		printf("%s%s", clr, top_left);
+
+		printf("\nDevice statistics ====================================");
+
+		dev_ll = ll_root_used;
+		while (dev_ll != NULL) {
+			device_fh = (uint32_t)dev_ll->vdev->dev->device_fh;
+			tx_total = dev_statistics[device_fh].tx_total;
+			tx = dev_statistics[device_fh].tx;
+			tx_dropped = tx_total - tx;
+			rx_total = rte_atomic64_read(
+				&dev_statistics[device_fh].rx_total_atomic);
+			rx = rte_atomic64_read(
+				&dev_statistics[device_fh].rx_atomic);
+			rx_dropped = rx_total - rx;
+
+			printf("\nStatistics for device %"PRIu32" ------------------------------"
+					"\nTX total: 		%"PRIu64""
+					"\nTX dropped: 		%"PRIu64""
+					"\nTX successful: 		%"PRIu64""
+					"\nRX total: 		%"PRIu64""
+					"\nRX dropped: 		%"PRIu64""
+					"\nRX successful: 		%"PRIu64"",
+					device_fh,
+					tx_total,
+					tx_dropped,
+					tx,
+					rx_total,
+					rx_dropped,
+					rx);
+
+			dev_ll = dev_ll->next;
+		}
+		printf("\n======================================================\n");
+	}
+}
+
+/*
+ * Main function, does initialisation and calls the per-lcore functions. The CUSE
+ * device is also registered here to handle the IOCTLs.
+ */
+int
+main(int argc, char *argv[])
+{
+	struct rte_mempool *mbuf_pool = NULL;
+	unsigned lcore_id, core_id = 0;
+	unsigned nb_ports, valid_num_ports;
+	int ret;
+	uint8_t portid;
+	uint16_t queue_id;
+	static pthread_t tid;
+
+	/* init EAL */
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+	argc -= ret;
+	argv += ret;
+
+	/* parse app arguments */
+	ret = tep_parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid argument\n");
+
+	for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
+		if (rte_lcore_is_enabled(lcore_id))
+			lcore_ids[core_id ++] = lcore_id;
+
+	if (rte_lcore_count() > RTE_MAX_LCORE)
+		rte_exit(EXIT_FAILURE,"Not enough cores\n");
+
+	/*set the number of swithcing cores available*/
+	num_switching_cores = rte_lcore_count()-1;
+
+	/* Get the number of physical ports. */
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports > RTE_MAX_ETHPORTS)
+		nb_ports = RTE_MAX_ETHPORTS;
+
+
+	/*
+	 * Update the global var NUM_PORTS and global array PORTS
+	 * and get value of var VALID_NUM_PORTS according to system ports number
+	 */
+	valid_num_ports = check_ports_num(nb_ports);
+
+	if ((valid_num_ports ==  0) || (valid_num_ports > MAX_SUP_PORTS)) {
+		RTE_LOG(INFO, VHOST_PORT, "Current enabled port number is %u,"
+			"but only %u port can be enabled\n",num_ports, MAX_SUP_PORTS);
+		return -1;
+	}
+
+
+	/* Create the mbuf pool. */
+	mbuf_pool = rte_mempool_create(
+			"MBUF_POOL",
+			NUM_MBUFS_PER_PORT
+			* valid_num_ports,
+			MBUF_SIZE, MBUF_CACHE_SIZE,
+			sizeof(struct rte_pktmbuf_pool_private),
+			rte_pktmbuf_pool_init, NULL,
+			rte_pktmbuf_init, NULL,
+			rte_socket_id(), 0);
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+	for (queue_id = 0; queue_id < MAX_QUEUES + 1; queue_id++)
+		vpool_array[queue_id].pool = mbuf_pool;
+
+	/* Set log level. */
+	rte_set_log_level(LOG_LEVEL);
+
+	/* initialize all ports */
+	for (portid = 0; portid < nb_ports; portid++) {
+		/* skip ports that are not enabled */
+		if ((enabled_port_mask & (1 << portid)) == 0) {
+			RTE_LOG(INFO, VHOST_PORT,
+				"Skipping disabled port %d\n", portid);
+			continue;
+		}
+	}
+
+	/* Initialise all linked lists. */
+	if (init_data_ll() == -1)
+		rte_exit(EXIT_FAILURE, "Failed to initialize linked list\n");
+
+	/* Initialize device stats */
+	memset(&dev_statistics, 0, sizeof(dev_statistics));
+
+	/* Enable stats if the user option is set. */
+	if (enable_stats)
+		pthread_create(&tid, NULL, (void*)print_stats, NULL );
+
+	/* Launch all data cores. */
+	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+		rte_eal_remote_launch(switch_worker,
+			mbuf_pool, lcore_id);
+	}
+
+	rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_MRG_RXBUF);
+
+	/* Register CUSE device to handle IOCTLs. */
+	ret = rte_vhost_driver_register((char *)&dev_basename);
+	if (ret != 0)
+		rte_exit(EXIT_FAILURE,"CUSE device setup failure.\n");
+
+	rte_vhost_driver_callback_register(&virtio_net_device_ops);
+
+	/* Start CUSE session. */
+	rte_vhost_driver_session_start();
+	return 0;
+}
diff --git a/examples/tep_termination/main.h b/examples/tep_termination/main.h
new file mode 100644
index 0000000..8fb4d5d
--- /dev/null
+++ b/examples/tep_termination/main.h
@@ -0,0 +1,113 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+#ifdef DEBUG
+#define LOG_LEVEL RTE_LOG_DEBUG
+#define LOG_DEBUG(log_type, fmt, args...) do {	\
+	RTE_LOG(DEBUG, log_type, fmt, ##args);		\
+} while (0)
+#else
+#define LOG_LEVEL RTE_LOG_INFO
+#define LOG_DEBUG(log_type, fmt, args...) do{} while(0)
+#endif
+
+/* Macros for printing using RTE_LOG */
+#define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1
+#define RTE_LOGTYPE_VHOST_DATA   RTE_LOGTYPE_USER2
+#define RTE_LOGTYPE_VHOST_PORT   RTE_LOGTYPE_USER3
+
+/* State of virtio device. */
+#define DEVICE_MAC_LEARNING 	0
+#define DEVICE_RX 		1
+#define DEVICE_SAFE_REMOVE	2
+
+#define MAX_QUEUES  512
+
+/* Max burst size for RX/TX */
+#define MAX_PKT_BURST 32
+
+/* Configurable number of RX/TX ring descriptors */
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 512
+
+/* *
+ * Device linked list structure for data path.
+ */
+struct vhost_dev {
+	/**< Pointer to device created by vhost lib. */
+	struct virtio_net      *dev;
+	/**< Number of memory regions for gpa to hpa translation. */
+	uint32_t nregions_hpa;
+	/**< Memory region information for gpa to hpa translation. */
+	struct virtio_memory_regions_hpa *regions_hpa;
+	/**< Device MAC address (Obtained on first TX packet). */
+	struct ether_addr mac_address;
+	/**< RX queue number. */
+	uint16_t rx_q;
+	/**< Data core that the device is added to. */
+	uint16_t coreid;
+	/**< A device is set as ready if the MAC address has been set. */
+	volatile uint8_t ready;
+	/**< Device is marked for removal from the data core. */
+	volatile uint8_t remove;
+} __rte_cache_aligned;
+
+/* *
+ * Structure containing data core specific information.
+ */
+struct lcore_ll_info
+{
+	struct virtio_net_data_ll *ll_root_free; /* Pointer to head in free linked list. */
+	struct virtio_net_data_ll *ll_root_used; /* Pointer to head of used linked list. */
+	uint32_t device_num; /* Number of devices on lcore. */
+	volatile uint8_t dev_removal_flag; /* Flag to synchronize device removal. */
+};
+
+struct lcore_info
+{
+	struct lcore_ll_info	*lcore_ll; /* Pointer to data core specific lcore_ll_info struct */
+};
+
+struct virtio_net_data_ll
+{
+	struct vhost_dev            *vdev;  /* Pointer to device created by configuration core. */
+	struct virtio_net_data_ll   *next;  /* Pointer to next device in linked list. */
+};
+
+uint32_t
+virtio_dev_rx(struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count);
+
+#endif /* _MAIN_H_ */
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 02/10] examples/tep_termination:define VXLAN device information and APIs
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 01/10] examples/tep_termination:initialize the VXLAN example Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 03/10] examples/tep_termination:add the pluggable structures for VXLAN packet processing Jijiang Liu
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

Some basic VXLAN definations and APIs are added in this file, which include VXLAN device structure and the APIs for encapsulation and decapsulation.

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Signed-off-by: Thomas Long <thomas.long@intel.com>

---
 examples/tep_termination/main.c  |    1 +
 examples/tep_termination/vxlan.h |   81 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+), 0 deletions(-)
 create mode 100644 examples/tep_termination/vxlan.h

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 2e36ad0..e58726f 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -52,6 +52,7 @@
 #include <rte_virtio_net.h>
 
 #include "main.h"
+#include "vxlan.h"
 
 /* the maximum number of external ports supported */
 #define MAX_SUP_PORTS 1
diff --git a/examples/tep_termination/vxlan.h b/examples/tep_termination/vxlan.h
new file mode 100644
index 0000000..96c68fb
--- /dev/null
+++ b/examples/tep_termination/vxlan.h
@@ -0,0 +1,81 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VXLAN_H_
+#define _VXLAN_H_
+
+#define PORT_MIN 	49152
+#define PORT_MAX 	65535
+#define PORT_RANGE (PORT_MAX - PORT_MIN) + 1
+
+#define VXLAN_N_PORTS  2
+#define VXLAN_FLAGS 0x00000008
+#define OUTER_VLAN_ID  100
+
+struct vxlan_port
+{
+	uint32_t portid;            /* VirtIO port id */
+	uint32_t peerip;            /* remote VTEP IP address */
+	struct ether_addr peermac;  /* remote VTEP MAC address */
+	struct ether_addr portmac;  /* VM MAC address */
+};
+
+struct vxlan_conf
+{
+	uint16_t vxport;        /* VXLAN UDP destination port */
+	uint32_t portip;        /* DPDK port IP address*/
+	uint32_t in_key;        /* VLAN  ID */
+	uint32_t out_key;       /* VXLAN VNI */
+	uint32_t portid;        /* DPDK port id */
+	struct vxlan_port port[VXLAN_N_PORTS]; /* VXLAN configuration */
+} __rte_cache_aligned;
+
+/* structure that caches offload info for the current packet */
+struct offload_info
+{
+	uint16_t ethertype; 
+	uint8_t l2_len;
+	uint16_t l3_len;
+	uint8_t l4_len;
+	uint8_t l4_proto;
+	uint16_t outer_ethertype;
+	uint8_t outer_l2_len;
+	uint16_t outer_l3_len;
+	uint8_t outer_l4_len;
+	uint8_t outer_l4_proto;
+}__rte_cache_aligned;
+
+int decapsulation(struct rte_mbuf *pkt);
+int encapsulation(struct rte_mbuf *m, uint8_t portid);
+
+#endif /* _MAIN_H_ */
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 03/10] examples/tep_termination:add the pluggable structures for VXLAN packet processing
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 01/10] examples/tep_termination:initialize the VXLAN example Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 02/10] examples/tep_termination:define VXLAN device information and APIs Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 04/10] examples/tep_termination:implement " Jijiang Liu
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

We are trying to create a framework for tunneling packet processing, so some common APIs are added here, which include 
1> tunnel port configuration

2> tunnel setup

3> tunnel destroying

4> tunneling packet processing for Rx side

5> tunneling packet processing for Tx side

6> tunnel parameter processing

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Signed-off-by: Thomas Long <thomas.long@intel.com>

---
 examples/tep_termination/vxlan_setup.h |   76 ++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)
 create mode 100644 examples/tep_termination/vxlan_setup.h

diff --git a/examples/tep_termination/vxlan_setup.h b/examples/tep_termination/vxlan_setup.h
new file mode 100644
index 0000000..b79a987
--- /dev/null
+++ b/examples/tep_termination/vxlan_setup.h
@@ -0,0 +1,76 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VXLAN_SETUP_H_
+#define VXLAN_SETUP_H_
+
+typedef int (*ol_port_configure_t)(uint8_t port, struct rte_mempool *mbuf_pool);
+
+typedef int (*ol_tunnel_setup_t)(struct vhost_dev *vdev, struct rte_mbuf *m);
+
+typedef void (*ol_tunnel_destroy_t)(struct vhost_dev *vdev);
+
+typedef int (*ol_tx_handle_t)(uint8_t port_id, uint16_t queue_id,
+                                  struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+
+typedef int (*ol_rx_handle_t)(struct virtio_net *dev, struct rte_mbuf **pkts,
+				uint32_t count);
+
+typedef int (*ol_param_handle)(struct virtio_net *dev);
+
+struct ol_switch_ops {
+	ol_port_configure_t        port_configure;
+	ol_tunnel_setup_t          tunnel_setup;
+	ol_tunnel_destroy_t        tunnel_destroy;
+	ol_tx_handle_t             tx_handle;
+	ol_rx_handle_t             rx_handle;
+	ol_param_handle            param_handle;
+};
+
+int
+vxlan_port_init(uint8_t port, struct rte_mempool *mbuf_pool);
+
+int
+vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m);
+
+void
+vxlan_unlink(struct vhost_dev *vdev);
+
+int 
+vxlan_tx_pkts (uint8_t port_id, uint16_t queue_id,
+			struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+int
+vxlan_rx_pkts (struct virtio_net *dev, struct rte_mbuf **pkts, uint32_t count);
+
+#endif /* VXLAN_SETUP_H_ */
+
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 04/10] examples/tep_termination:implement VXLAN packet processing
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (2 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 03/10] examples/tep_termination:add the pluggable structures for VXLAN packet processing Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 05/10] examples/tep_termination:implement the APIs of encapsulation and decapsulation for VXLAN Jijiang Liu
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

Implement the following functions:

1> VXLAN port configuration
 
2> VXLAN tunnel setup
 
3> VXLAN tunnel destroying
 
4> VXLAN packet processing for Rx side
 
5> VXLAN packet processing for Tx side
 

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Signed-off-by: Thomas Long <thomas.long@intel.com>
---
 examples/tep_termination/Makefile      |    2 +-
 examples/tep_termination/main.c        |   26 ++-
 examples/tep_termination/vxlan_setup.c |  391 ++++++++++++++++++++++++++++++++
 3 files changed, 415 insertions(+), 4 deletions(-)
 create mode 100644 examples/tep_termination/vxlan_setup.c

diff --git a/examples/tep_termination/Makefile b/examples/tep_termination/Makefile
index 23fb647..ed4fab2 100644
--- a/examples/tep_termination/Makefile
+++ b/examples/tep_termination/Makefile
@@ -48,7 +48,7 @@ else
 APP = tep_termination
 
 # all source are stored in SRCS-y
-SRCS-y :=  main.c
+SRCS-y :=  main.c vxlan_setup.c
 
 CFLAGS += -O2 -D_FILE_OFFSET_BITS=64
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index f846053..60a825e 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -113,6 +113,16 @@ struct vpool {
 /* number of devices */
 uint16_t num_devices;
 
+/* overlay packet operation */
+struct ol_switch_ops overlay_options = {
+	.port_configure = vxlan_port_init,
+	.tunnel_setup = vxlan_link,
+	.tunnel_destroy = vxlan_unlink,
+	.tx_handle = vxlan_tx_pkts,
+	.rx_handle = vxlan_rx_pkts,
+	.param_handle = NULL,
+};
+
 /* Enable stats. */
 static uint32_t enable_stats = 0;
 
@@ -350,7 +360,7 @@ virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m, __attribute__((unuse
 {
 	struct mbuf_table *tx_q;
 	struct rte_mbuf **m_table;
-	unsigned len, ret = 0;
+	unsigned len, ret;
 
 	const uint16_t lcore_id = rte_lcore_id();
 	struct virtio_net *dev = vdev->dev;
@@ -369,6 +379,8 @@ virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m, __attribute__((unuse
 
 	if (unlikely(len == MAX_PKT_BURST)) {
 		m_table = (struct rte_mbuf **)tx_q->m_table;
+		ret = overlay_options.tx_handle(ports[0], (uint16_t)tx_q->txq_id,
+			(struct rte_mbuf **)tx_q->m_table, (uint16_t)tx_q->len);
 		/* Free any buffers not handled by TX and update the port stats. */
 		if (unlikely(ret < len)) {
 			do {
@@ -401,7 +413,7 @@ switch_worker(__attribute__((unused)) void *arg)
 	volatile struct lcore_ll_info *lcore_ll;
 	const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
 	uint64_t prev_tsc, diff_tsc, cur_tsc, ret_count = 0;
-	unsigned ret = 0, i;
+	unsigned ret, i;
 	const uint16_t lcore_id = rte_lcore_id();
 	const uint16_t num_cores = (uint16_t)rte_lcore_count();
 	uint16_t rx_count = 0;
@@ -429,6 +441,9 @@ switch_worker(__attribute__((unused)) void *arg)
 
 			if (tx_q->len) {
 				LOG_DEBUG(VHOST_DATA, "TX queue drained after timeout with burst size %u \n", tx_q->len);
+				ret = overlay_options.tx_handle(ports[0], (uint16_t)tx_q->txq_id,
+									   (struct rte_mbuf **)tx_q->m_table,
+									   (uint16_t)tx_q->len);
 				if (unlikely(ret < tx_q->len)) {
 					do {
 						rte_pktmbuf_free(tx_q->m_table[ret]);
@@ -462,6 +477,7 @@ switch_worker(__attribute__((unused)) void *arg)
 
 			if (unlikely(vdev->remove)) {
 				dev_ll = dev_ll->next;
+				overlay_options.tunnel_destroy(vdev);
 				vdev->ready = DEVICE_SAFE_REMOVE;
 				continue;
 			}
@@ -472,6 +488,7 @@ switch_worker(__attribute__((unused)) void *arg)
 					vdev->rx_q, pkts_burst, MAX_PKT_BURST);
 
 				if (rx_count) {
+					ret_count = overlay_options.rx_handle(dev, pkts_burst, rx_count);
 					if (enable_stats) {
 						rte_atomic64_add(
 						&dev_statistics[dev_ll->vdev->dev->device_fh].rx_total_atomic,
@@ -492,7 +509,7 @@ switch_worker(__attribute__((unused)) void *arg)
 				tx_count = rte_vhost_dequeue_burst(dev, VIRTIO_TXQ, mbuf_pool, pkts_burst, MAX_PKT_BURST);
 				/* If this is the first received packet we need to learn the MAC */
 				if (unlikely(vdev->ready == DEVICE_MAC_LEARNING) && tx_count) {
-					if (vdev->remove) {
+					if (vdev->remove || (overlay_options.tunnel_setup(vdev, pkts_burst[0]) == -1)) {
 						while (tx_count) {
 							mbuf_tmp = pkts_burst[--tx_count];
 							if (mbuf_tmp)
@@ -966,6 +983,9 @@ main(int argc, char *argv[])
 				"Skipping disabled port %d\n", portid);
 			continue;
 		}
+
+		if (overlay_options.port_configure(portid, mbuf_pool) != 0)
+			rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
 	}
 
 	/* Initialise all linked lists. */
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
new file mode 100644
index 0000000..874c502
--- /dev/null
+++ b/examples/tep_termination/vxlan_setup.c
@@ -0,0 +1,391 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <getopt.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_ring.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/eventfd.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_ethdev.h>
+#include <rte_log.h>
+#include <rte_string_fns.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+
+#include "main.h"
+#include "rte_virtio_net.h"
+#include "vxlan.h"
+#include "vxlan_setup.h"
+
+#define VXLAN_ENCAP_HDR_SIZE (sizeof(struct ether_hdr)  + IPV4_HEADER_LEN + \
+                UDP_HEADER_LEN + VXLAN_HEADER_LEN)
+
+#define IPV4_HEADER_LEN 20
+#define UDP_HEADER_LEN  8
+#define VXLAN_HEADER_LEN 8
+
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+#define IP_DN_FRAGMENT_FLAG 0x0040
+
+/* Used to compare MAC addresses. */
+#define MAC_ADDR_CMP 0xFFFFFFFFFFFFULL
+
+/* Configurable number of RX/TX ring descriptors */
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 512
+
+extern uint16_t num_devices;
+extern uint8_t ports[RTE_MAX_ETHPORTS];
+
+/* ethernet addresses of ports */
+extern struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* heads for the main used and free linked lists for the data path. */
+static struct virtio_net_data_ll *ll_root_used = NULL;
+
+/* VXLAN device */
+struct vxlan_conf vxdev;
+
+struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
+struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
+
+/* local VTEP IP address */
+static uint8_t vxlan_multicast_ips[2][4] = {{239, 1, 1, 1}, {239, 1, 2, 1}};
+
+/* remote VTEP IP address */
+static uint8_t vxlan_overlay_ips[2][4] = {{192, 168, 10, 1}, {192, 168, 30, 1}};
+
+/* remote VTEP MAC address */
+static uint8_t peer_mac[6] = {0x00, 0x11, 0x01, 0x00, 0x00, 0x01};
+
+/* VXLAN termination filter type */
+uint8_t tep_filter_type[] = {RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID,
+			     RTE_TUNNEL_FILTER_IMAC_TENID,
+			     RTE_TUNNEL_FILTER_OMAC_TENID_IMAC,};
+
+/* Options for configuring ethernet port */
+static const struct rte_eth_conf port_conf = {
+	.rxmode = {
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload disabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+};
+
+const uint16_t tenant_id_conf[] = {
+	1000, 1000, 1001, 1001, 1002, 1002, 1003, 1003,
+	1004, 1004, 1005, 1005, 1006, 1006, 1007, 1007,
+	1008, 1008, 1009, 1009, 1010, 1010, 1011, 1011,
+	1012, 1012, 1013, 1013, 1014, 1014, 1015, 1015,
+	1016, 1016, 1017, 1017, 1018, 1018, 1019, 1019,
+	1020, 1020, 1021, 1021, 1022, 1022, 1023, 1023,
+	1024, 1024, 1025, 1025, 1026, 1026, 1027, 1027,
+	1028, 1028, 1029, 1029, 1030, 1030, 1031, 1031,
+};
+
+/* *
+ * Compares a packet destination MAC address to a device MAC address.
+ */
+static inline int __attribute__((always_inline))
+ether_addr_cmp(struct ether_addr *ea, struct ether_addr *eb)
+{
+	return (((*(uint64_t *)ea ^ *(uint64_t *)eb) & MAC_ADDR_CMP) == 0);
+}
+
+/*
+ * Initialises a given port using global settings and with the rx buffers
+ * coming from the mbuf_pool passed as parameter
+ */
+int
+vxlan_port_init(uint8_t port, struct rte_mempool *mbuf_pool)
+{
+	struct rte_eth_dev_info dev_info;
+	uint16_t rx_rings, tx_rings = (uint16_t)rte_lcore_count();
+	const uint16_t rx_ring_size = RTE_TEST_RX_DESC_DEFAULT;
+	const uint16_t tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;
+	int retval;
+	uint16_t num_queues, q;
+        //struct vxlan_conf *pconf = &vxdev;
+	struct rte_eth_rxconf *rxconf;
+	struct rte_eth_txconf *txconf;
+
+	rte_eth_dev_info_get (port, &dev_info);
+
+	dev_info.max_rx_queues = num_devices;
+
+	if (dev_info.max_rx_queues > MAX_QUEUES) {
+		rte_exit(EXIT_FAILURE,
+			"please define MAX_QUEUES no less than %u in %s\n",
+			dev_info.max_rx_queues, __FILE__);
+	}
+
+	rxconf = &dev_info.default_rxconf;
+	txconf = &dev_info.default_txconf;
+	
+	txconf->txq_flags = 0;
+	num_queues = num_devices;
+
+	if (port >= rte_eth_dev_count()) return -1;
+
+	rx_rings = (uint16_t)num_queues;
+
+	/* Configure ethernet device. */
+	retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
+	if (retval != 0)
+		return retval;
+	/* Setup the queues. */
+	for (q = 0; q < rx_rings; q ++) {
+		retval = rte_eth_rx_queue_setup(port, q, rx_ring_size,
+						rte_eth_dev_socket_id(port), rxconf,
+						mbuf_pool);
+		if (retval < 0)
+			return retval;
+	}
+	for (q = 0; q < tx_rings; q ++) {
+		retval = rte_eth_tx_queue_setup(port, q, tx_ring_size,
+						rte_eth_dev_socket_id(port), txconf);
+		if (retval < 0)
+			return retval;
+	}
+
+	/* Start the device. */
+	retval  = rte_eth_dev_start(port);
+	if (retval < 0)
+		return retval;
+
+	rte_eth_macaddr_get(port, &ports_eth_addr[port]);
+	RTE_LOG(INFO, PORT, "Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+			(unsigned)port,
+			ports_eth_addr[port].addr_bytes[0],
+			ports_eth_addr[port].addr_bytes[1],
+			ports_eth_addr[port].addr_bytes[2],
+			ports_eth_addr[port].addr_bytes[3],
+			ports_eth_addr[port].addr_bytes[4],
+			ports_eth_addr[port].addr_bytes[5]);
+
+	return 0;
+}
+
+static int
+vxlan_rx_process(struct rte_mbuf *pkt)
+{
+	int ret = 0;
+	if ((pkt->ol_flags & (PKT_RX_TUNNEL_IPV4_HDR
+		| PKT_RX_TUNNEL_IPV6_HDR)) == 0)
+		return -1;
+
+	return ret;
+}
+
+static int 
+vxlan_tx_process(struct rte_mbuf *pkt)
+{
+	int ret = 0;
+
+	if ((pkt->pkt_len + VXLAN_ENCAP_HDR_SIZE) > ETHER_MAX_LEN ){
+		rte_pktmbuf_free(pkt);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * This function learns the MAC address of the device
+ */
+int
+vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m)
+{
+	int i;
+	struct ether_hdr *pkt_hdr;
+	struct virtio_net_data_ll *dev_ll;
+	struct virtio_net *dev = vdev->dev;
+	uint64_t portid = dev->device_fh;
+
+	dev_ll = ll_root_used;
+
+	if (unlikely(portid > VXLAN_N_PORTS)){
+		RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") WARNING: Not configuring device,"
+			"as already have %d ports for VXLAN.", dev->device_fh, VXLAN_N_PORTS);
+		return -1;
+	}
+
+	/* Learn MAC address of guest device from packet */
+	pkt_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	while (dev_ll != NULL) {
+		if (ether_addr_cmp(&(pkt_hdr->s_addr), &dev_ll->vdev->mac_address)) {
+		RTE_LOG(INFO, VHOST_DATA, "(%"PRIu64") WARNING: This device is using an existing"
+				" MAC address and has not been registered.\n", dev->device_fh);
+			return -1;
+		}
+		dev_ll = dev_ll->next;
+	}
+
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
+		vxdev.port[portid].portmac.addr_bytes[i] = pkt_hdr->s_addr.addr_bytes[i];
+		vxdev.port[portid].peermac.addr_bytes[i] = peer_mac[i];
+	}
+
+	/* Print out inner MAC and VNI info. */
+	RTE_LOG(INFO, VHOST_DATA, "(%d) MAC_ADDRESS %02x:%02x:%02x:%02x:%02x:%02x and VNI %d registered\n",
+		vdev->rx_q,
+		vdev->mac_address.addr_bytes[0], vdev->mac_address.addr_bytes[1],
+		vdev->mac_address.addr_bytes[2], vdev->mac_address.addr_bytes[3],
+		vdev->mac_address.addr_bytes[4], vdev->mac_address.addr_bytes[5],
+		tenant_id_conf[vdev->rx_q]);
+
+	vxdev.port[portid].portid = portid;
+
+	for (i = 0; i < 4; i++) {
+		/*Local VTEP IP */
+		vxdev.portip |= vxlan_multicast_ips[portid][i] << (8 * i);
+		/* remote VTEP IP */
+		vxdev.port[portid].peerip |= vxlan_overlay_ips[portid][i] << (8 * i);
+	}
+	
+	vxdev.out_key = tenant_id_conf[vdev->rx_q];
+	ether_addr_copy(&vxdev.port[portid].peermac, &app_l2_hdr[portid].d_addr);
+	ether_addr_copy(&ports_eth_addr[0], &app_l2_hdr[portid].s_addr);
+	app_l2_hdr[portid].ether_type = rte_cpu_to_be_32(ETHER_TYPE_IPv4);
+
+	struct ipv4_hdr *ip;
+	ip = &app_ip_hdr[portid];
+	ip->version_ihl = IP_VHL_DEF;
+	ip->type_of_service = 0;
+	ip->total_length = 0;
+	ip->packet_id = 0;
+	ip->fragment_offset = IP_DN_FRAGMENT_FLAG;
+	ip->time_to_live = IP_DEFTTL;
+	ip->next_proto_id = IPPROTO_UDP;
+	ip->hdr_checksum = 0;
+	ip->src_addr = vxdev.portip;
+	ip->dst_addr = vxdev.port[portid].peerip;
+	/* Set device as ready for RX. */
+
+	vdev->ready = DEVICE_RX;
+
+	return 0;
+}
+
+/*
+ * Removes cloud filter. Ensures that nothing is adding buffers to the RX
+ * queue before disabling RX on the device.
+ */
+void
+vxlan_unlink(struct vhost_dev *vdev)
+{
+	int ret = 1;
+	unsigned i = 0, rx_count;
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+
+	if (vdev->ready == DEVICE_RX) {
+		for (i = 0; i < ETHER_ADDR_LEN; i++)
+			vdev->mac_address.addr_bytes[i] = 0;
+
+		/*Clear out the receive buffers*/
+		rx_count = rte_eth_rx_burst(ports[0],
+					(uint16_t)vdev->rx_q, pkts_burst, MAX_PKT_BURST);
+
+		while (rx_count) {
+		if (ret < 0)
+			continue;
+
+			for (i = 0; i < rx_count; i++)
+				rte_pktmbuf_free(pkts_burst[i]);
+
+			rx_count = rte_eth_rx_burst(ports[0],
+					(uint16_t)vdev->rx_q, pkts_burst, MAX_PKT_BURST);
+		}
+		vdev->ready = DEVICE_MAC_LEARNING;
+	}
+}
+
+/*transmit packets after encapsulating*/
+int
+vxlan_tx_pkts (uint8_t port_id, uint16_t queue_id,
+			struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
+	int ret = 0;
+	uint16_t count = nb_pkts, i;
+
+	for (i = 0; i < count; i++){
+		ret = vxlan_tx_process(tx_pkts[i]);
+	}
+
+	ret = rte_eth_tx_burst(port_id, queue_id, tx_pkts, nb_pkts);
+
+	return ret;
+
+}
+
+/*Check for decapsulation and pass packets directly to VIRTIO device*/
+int
+vxlan_rx_pkts (struct virtio_net *dev, struct rte_mbuf **pkts_burst, uint32_t rx_count)
+{
+
+	uint32_t i = 0, count = 0;
+	int ret;
+	struct rte_mbuf *pkts_valid[rx_count];
+	for(i = 0; i < rx_count; i++) {
+		ret = vxlan_rx_process(pkts_burst[i]);
+		if(unlikely(ret < 0)){
+			continue;
+		}
+		pkts_valid[count] = pkts_burst[i];
+			count++;
+	}
+
+	ret = rte_vhost_enqueue_burst(dev, VIRTIO_RXQ, pkts_valid, rx_count);
+	return ret;
+}
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 05/10] examples/tep_termination:implement the APIs of encapsulation and decapsulation for VXLAN
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (3 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 04/10] examples/tep_termination:implement " Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 06/10] examples/tep_termination:add UDP port configuration for UDP tunneling packet Jijiang Liu
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

Fill the APIs of encapsulation and decapsulation for VXLAN packet; for the encapsulation operation, IPv6 is not supported now.
 
Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Signed-off-by: Thomas Long <thomas.long@intel.com>
---
 examples/tep_termination/Makefile      |    4 +-
 examples/tep_termination/vxlan.c       |  160 ++++++++++++++++++++++++++++++++
 examples/tep_termination/vxlan_setup.c |    7 +-
 3 files changed, 167 insertions(+), 4 deletions(-)
 create mode 100644 examples/tep_termination/vxlan.c

diff --git a/examples/tep_termination/Makefile b/examples/tep_termination/Makefile
index ed4fab2..03ba865 100644
--- a/examples/tep_termination/Makefile
+++ b/examples/tep_termination/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@ else
 APP = tep_termination
 
 # all source are stored in SRCS-y
-SRCS-y :=  main.c vxlan_setup.c
+SRCS-y :=  main.c vxlan_setup.c vxlan.c
 
 CFLAGS += -O2 -D_FILE_OFFSET_BITS=64
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/tep_termination/vxlan.c b/examples/tep_termination/vxlan.c
new file mode 100644
index 0000000..9d86616
--- /dev/null
+++ b/examples/tep_termination/vxlan.c
@@ -0,0 +1,160 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdint.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_hash_crc.h>
+#include <rte_byteorder.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+#include <rte_sctp.h>
+#include <rte_ip.h>
+
+#include "main.h"
+#include "vxlan.h"
+
+extern struct vxlan_conf vxdev;
+extern struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
+extern struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
+
+/*
+ * Parse an ethernet header to fill the ethertype, l2_len, l3_len and
+ * ipproto. This function is able to recognize IPv4/IPv6 with one optional vlan
+ * header. 
+ */
+static void
+parse_ethernet(struct ether_hdr *eth_hdr, struct offload_info *info)
+{
+        struct ipv4_hdr *ipv4_hdr;
+        struct ipv6_hdr *ipv6_hdr;
+ 
+        info->outer_l2_len = sizeof(struct ether_hdr);
+        info->ethertype = eth_hdr->ether_type;
+ 
+        if (info->ethertype == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+                struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+                info->outer_l2_len  += sizeof(struct vlan_hdr);
+                info->ethertype = vlan_hdr->eth_proto;
+        }
+ 
+        switch (rte_cpu_to_be_16(info->ethertype)) {
+        case ETHER_TYPE_IPv4:
+                ipv4_hdr = (struct ipv4_hdr *) ((char *)eth_hdr + info->l2_len);
+                info->outer_l3_len = sizeof(struct ipv4_hdr);
+                info->l4_proto = ipv4_hdr->next_proto_id;
+                break;
+        case ETHER_TYPE_IPv6:
+                ipv6_hdr = (struct ipv6_hdr *) ((char *)eth_hdr + info->l2_len);
+                info->outer_l3_len = sizeof(struct ipv6_hdr);
+                info->l4_proto = ipv6_hdr->proto;
+                break;
+        default:
+                info->outer_l2_len = 0;
+                info->outer_l3_len = 0;
+                info->l4_proto = 0;
+                break;
+	}
+                
+}
+
+int decapsulation(struct rte_mbuf *pkt)
+{
+	struct offload_info info;
+	uint16_t outer_header_len;
+	
+	memset(&info, 0, sizeof(struct offload_info));
+
+	struct ether_hdr *phdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
+	parse_ethernet(phdr, &info);
+	if (info.l4_proto == IPPROTO_UDP) {
+		struct udp_hdr *udp_hdr;
+		udp_hdr = (struct udp_hdr *)((char *)phdr +
+			info.outer_l2_len + info.outer_l3_len);
+		if (udp_hdr->dst_port != rte_cpu_to_be_16(4789))
+			return -1;
+	}
+	outer_header_len = info.outer_l2_len + info.outer_l3_len
+		+ sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr);
+
+	rte_pktmbuf_adj(pkt, outer_header_len);
+	return 0;
+}
+
+int encapsulation(struct rte_mbuf *m, uint8_t vport_id)
+{
+	struct offload_info info;
+	uint64_t ol_flags = 0;
+	uint32_t old_len = m->pkt_len, hash;
+	struct ether_hdr *phdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+	/*Allocate space for new ethernet, IPv4, UDP and VXLAN headers*/
+	struct ether_hdr *pneth = (struct ether_hdr *) rte_pktmbuf_prepend(m,
+		sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr)
+		+ sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr));
+
+	struct ipv4_hdr *ip = (struct ipv4_hdr *) &pneth[1];
+	struct udp_hdr *udp = (struct udp_hdr *) &ip[1];
+	struct vxlan_hdr *vxlan = (struct vxlan_hdr *) &udp[1];
+
+	memset(&info, 0, sizeof(struct offload_info));
+	/* replace original Ethernet header with ours */
+	pneth = rte_memcpy(pneth, &app_l2_hdr[vport_id], sizeof(struct ether_hdr));
+	/* copy in IP header */
+	ip = rte_memcpy(ip, &app_ip_hdr[vport_id], sizeof(struct ipv4_hdr));
+	ip->total_length = rte_cpu_to_be_16(m->data_len - sizeof(struct ether_hdr));
+
+	/* outer IP checksum */
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	ip->hdr_checksum = 0;
+
+	m->outer_l2_len = sizeof(struct ether_hdr);
+	m->outer_l3_len = sizeof(struct ipv4_hdr);
+
+	m->ol_flags |= ol_flags;
+
+	/*VXLAN HEADER*/
+	vxlan->vx_flags = VXLAN_FLAGS;
+	vxlan->vx_vni = rte_cpu_to_be_32(vxdev.out_key << 8);
+
+	/*UDP HEADER*/
+	udp->dgram_cksum = 0;
+	udp->dgram_len = rte_cpu_to_be_16(old_len
+				+ sizeof(struct udp_hdr) + sizeof(struct vxlan_hdr));
+
+	udp->dst_port = rte_cpu_to_be_16(vxdev.vxport);
+	hash = rte_hash_crc(phdr, 2 * ETHER_ADDR_LEN, phdr->ether_type);
+	udp->src_port = rte_cpu_to_be_16((((uint64_t) hash * PORT_RANGE) >> 32)+ PORT_MIN);
+
+	return 0;
+}
+
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
index 874c502..7cb2660 100644
--- a/examples/tep_termination/vxlan_setup.c
+++ b/examples/tep_termination/vxlan_setup.c
@@ -226,11 +226,12 @@ vxlan_rx_process(struct rte_mbuf *pkt)
 		| PKT_RX_TUNNEL_IPV6_HDR)) == 0)
 		return -1;
 
+	ret = decapsulation(pkt);
 	return ret;
 }
 
 static int 
-vxlan_tx_process(struct rte_mbuf *pkt)
+vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 {
 	int ret = 0;
 
@@ -239,6 +240,7 @@ vxlan_tx_process(struct rte_mbuf *pkt)
 		return -1;
 	}
 
+	ret = encapsulation(pkt, vport_id);
 	return ret;
 }
 
@@ -358,9 +360,10 @@ vxlan_tx_pkts (uint8_t port_id, uint16_t queue_id,
 			struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
 	int ret = 0;
 	uint16_t count = nb_pkts, i;
+	uint16_t vport_id = queue_id;
 
 	for (i = 0; i < count; i++){
-		ret = vxlan_tx_process(tx_pkts[i]);
+		ret = vxlan_tx_process(vport_id, tx_pkts[i]);
 	}
 
 	ret = rte_eth_tx_burst(port_id, queue_id, tx_pkts, nb_pkts);
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 06/10] examples/tep_termination:add UDP port configuration for UDP tunneling packet
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (4 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 05/10] examples/tep_termination:implement the APIs of encapsulation and decapsulation for VXLAN Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 07/10] examples/tep_termination:add tunnel filter type configuration Jijiang Liu
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

The port number of UDP tunneling packet is configurable, which has 16 entries in total for i40e.

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/tep_termination/main.c        |   14 ++++++++++++++
 examples/tep_termination/vxlan.c       |    3 ++-
 examples/tep_termination/vxlan_setup.c |   17 +++++++++++++----
 3 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 60a825e..68d1706 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -113,6 +113,9 @@ struct vpool {
 /* number of devices */
 uint16_t num_devices;
 
+/* VXLAN UDP destination port */
+uint16_t udp_port;
+
 /* overlay packet operation */
 struct ol_switch_ops overlay_options = {
 	.port_configure = vxlan_port_init,
@@ -231,6 +234,7 @@ static void
 vep_termination_usage(const char *prgname)
 {
 	RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
+	"		--udp-port: UDP destination port for VXLAN packet\n"
 	"		--nb-devices: number of virtIO device\n"
 	"		--dev-basename <name>\n"
 	"		-p PORTMASK: Set mask for ports to be used by application\n"
@@ -250,6 +254,7 @@ tep_parse_args(int argc, char **argv)
 	unsigned i;
 	const char *prgname = argv[0];
 	static struct option long_option[] = {
+		{"udp-port", required_argument, NULL, 0},
 		{"nb-devices", required_argument, NULL, 0},
 		{"stats", required_argument, NULL, 0},
 		{"dev-basename", required_argument, NULL, 0},
@@ -280,6 +285,15 @@ tep_parse_args(int argc, char **argv)
 				} else 
 					num_devices = ret;
 			}
+	
+			if (!strncmp(long_option[option_index].name, "udp-port", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, INT16_MAX);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for UDP port [0-N]\n");
+						vep_termination_usage(prgname);
+					return -1;
+				}
+			}
 
 			/* Enable/disable stats. */
 			if (!strncmp(long_option[option_index].name, "stats", MAX_LONG_OPT_SZ)) {
diff --git a/examples/tep_termination/vxlan.c b/examples/tep_termination/vxlan.c
index 9d86616..942eb10 100644
--- a/examples/tep_termination/vxlan.c
+++ b/examples/tep_termination/vxlan.c
@@ -46,6 +46,7 @@
 extern struct vxlan_conf vxdev;
 extern struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
 extern struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
+extern uint16_t udp_port;
 
 /*
  * Parse an ethernet header to fill the ethertype, l2_len, l3_len and
@@ -100,7 +101,7 @@ int decapsulation(struct rte_mbuf *pkt)
 		struct udp_hdr *udp_hdr;
 		udp_hdr = (struct udp_hdr *)((char *)phdr +
 			info.outer_l2_len + info.outer_l3_len);
-		if (udp_hdr->dst_port != rte_cpu_to_be_16(4789))
+		if (udp_hdr->dst_port != rte_cpu_to_be_16(udp_port))
 			return -1;
 	}
 	outer_header_len = info.outer_l2_len + info.outer_l3_len
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
index 7cb2660..fbffbc8 100644
--- a/examples/tep_termination/vxlan_setup.c
+++ b/examples/tep_termination/vxlan_setup.c
@@ -80,6 +80,7 @@
 #define RTE_TEST_TX_DESC_DEFAULT 512
 
 extern uint16_t num_devices;
+extern uint16_t udp_port;
 extern uint8_t ports[RTE_MAX_ETHPORTS];
 
 /* ethernet addresses of ports */
@@ -156,10 +157,12 @@ vxlan_port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 	const uint16_t tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;
 	int retval;
 	uint16_t num_queues, q;
-        //struct vxlan_conf *pconf = &vxdev;
+        struct vxlan_conf *pconf = &vxdev;
+	struct rte_eth_udp_tunnel tunnel_udp;
 	struct rte_eth_rxconf *rxconf;
 	struct rte_eth_txconf *txconf;
 
+	pconf->vxport = udp_port;
 	rte_eth_dev_info_get (port, &dev_info);
 
 	dev_info.max_rx_queues = num_devices;
@@ -204,6 +207,13 @@ vxlan_port_init(uint8_t port, struct rte_mempool *mbuf_pool)
 	if (retval < 0)
 		return retval;
 
+	/* Configure UDP port for VXLAN */
+	tunnel_udp.udp_port = udp_port;
+	tunnel_udp.prot_type = RTE_TUNNEL_TYPE_VXLAN;
+	retval = rte_eth_dev_udp_tunnel_add(port, &tunnel_udp);
+	if (retval < 0)
+		return retval;
+
 	rte_eth_macaddr_get(port, &ports_eth_addr[port]);
 	RTE_LOG(INFO, PORT, "Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
 			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
@@ -230,8 +240,7 @@ vxlan_rx_process(struct rte_mbuf *pkt)
 	return ret;
 }
 
-static int 
-vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
+static int vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 {
 	int ret = 0;
 
@@ -241,6 +250,7 @@ vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 	}
 
 	ret = encapsulation(pkt, vport_id);
+
 	return ret;
 }
 
@@ -367,7 +377,6 @@ vxlan_tx_pkts (uint8_t port_id, uint16_t queue_id,
 	}
 
 	ret = rte_eth_tx_burst(port_id, queue_id, tx_pkts, nb_pkts);
-
 	return ret;
 
 }
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 07/10] examples/tep_termination:add tunnel filter type configuration
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (5 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 06/10] examples/tep_termination:add UDP port configuration for UDP tunneling packet Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 08/10] examples/tep_termination:add Tx checksum offload configuration for inner header Jijiang Liu
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

The follwoing filter types are supported for VXLAN,

1> Inner MAC&VLAN and tenent ID

2> Inner MAC and tenent ID, and Outer MAC

3> Inner MAC and tenent ID

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/tep_termination/main.c        |   21 +++++++++++++
 examples/tep_termination/vxlan_setup.c |   50 ++++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 68d1706..e8142e0 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -72,6 +72,9 @@
 #define MAX_PKT_BURST 32 	/* Max burst size for RX/TX */
 #define BURST_TX_DRAIN_US 100 	/* TX drain every ~100us */
 
+/* Defines how long we wait between retries on RX */
+#define BURST_RX_WAIT_US 15
+
 #define BURST_RX_RETRIES 4/* Number of retries on RX. */
 
 #define JUMBO_FRAME_MAX_SIZE    0x2600
@@ -116,6 +119,9 @@ uint16_t num_devices;
 /* VXLAN UDP destination port */
 uint16_t udp_port;
 
+/* RX filter type for tunneling packet */
+uint8_t filter_idx;
+
 /* overlay packet operation */
 struct ol_switch_ops overlay_options = {
 	.port_configure = vxlan_port_init,
@@ -236,6 +242,10 @@ vep_termination_usage(const char *prgname)
 	RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
 	"		--udp-port: UDP destination port for VXLAN packet\n"
 	"		--nb-devices: number of virtIO device\n"
+	"		--filter-type[1-3]: filter type for tunneling packet\n"
+	"		    1: Inner MAC&VLAN and tenent ID\n"
+	"		    2: Inner MAC and tenent ID\n"
+	"		    3: Outer MAC, Inner MAC and tenent ID\n"
 	"		--dev-basename <name>\n"
 	"		-p PORTMASK: Set mask for ports to be used by application\n"
 	"		--stats [0-N]: 0: Disable stats, N: Time in seconds to print stats\n"
@@ -256,6 +266,7 @@ tep_parse_args(int argc, char **argv)
 	static struct option long_option[] = {
 		{"udp-port", required_argument, NULL, 0},
 		{"nb-devices", required_argument, NULL, 0},
+		{"filter-type", required_argument, NULL, 0},
 		{"stats", required_argument, NULL, 0},
 		{"dev-basename", required_argument, NULL, 0},
 		{NULL, 0, 0, 0},
@@ -294,6 +305,16 @@ tep_parse_args(int argc, char **argv)
 					return -1;
 				}
 			}
+			
+			if (!strncmp(long_option[option_index].name, "filter-type", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, 3);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for filter type [1-3]\n");
+					vep_termination_usage(prgname);
+					return -1;
+				} else
+					filter_idx = ret - 1;
+			}
 
 			/* Enable/disable stats. */
 			if (!strncmp(long_option[option_index].name, "stats", MAX_LONG_OPT_SZ)) {
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
index fbffbc8..312a878 100644
--- a/examples/tep_termination/vxlan_setup.c
+++ b/examples/tep_termination/vxlan_setup.c
@@ -82,6 +82,7 @@
 extern uint16_t num_devices;
 extern uint16_t udp_port;
 extern uint8_t ports[RTE_MAX_ETHPORTS];
+extern uint8_t filter_idx;
 
 /* ethernet addresses of ports */
 extern struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
@@ -237,10 +238,12 @@ vxlan_rx_process(struct rte_mbuf *pkt)
 		return -1;
 
 	ret = decapsulation(pkt);
+
 	return ret;
 }
 
-static int vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
+static int
+vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 {
 	int ret = 0;
 
@@ -260,11 +263,12 @@ static int vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 int
 vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m)
 {
-	int i;
+	int i, ret;
 	struct ether_hdr *pkt_hdr;
 	struct virtio_net_data_ll *dev_ll;
 	struct virtio_net *dev = vdev->dev;
 	uint64_t portid = dev->device_fh;
+	struct rte_eth_tunnel_filter_conf tunnel_filter_conf;
 
 	dev_ll = ll_root_used;
 
@@ -290,6 +294,28 @@ vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m)
 		vxdev.port[portid].peermac.addr_bytes[i] = peer_mac[i];
 	}
 
+	memset(&tunnel_filter_conf, 0, sizeof(struct rte_eth_tunnel_filter_conf));
+
+	tunnel_filter_conf.outer_mac = &ports_eth_addr[0];
+	tunnel_filter_conf.filter_type = tep_filter_type[filter_idx];
+
+	/* inner MAC */
+	tunnel_filter_conf.inner_mac = &vdev->mac_address;
+
+	tunnel_filter_conf.queue_id = vdev->rx_q;
+	tunnel_filter_conf.tenant_id = tenant_id_conf[vdev->rx_q];
+	tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_VXLAN;
+
+	ret = rte_eth_dev_filter_ctrl(ports[0],
+		RTE_ETH_FILTER_TUNNEL,
+		RTE_ETH_FILTER_ADD,
+		&tunnel_filter_conf);
+	if (ret) {
+		RTE_LOG(ERR, VHOST_DATA, "%d Failed to add device MAC address to cloud filter\n",
+		vdev->rx_q);
+		return -1;
+	}
+
 	/* Print out inner MAC and VNI info. */
 	RTE_LOG(INFO, VHOST_DATA, "(%d) MAC_ADDRESS %02x:%02x:%02x:%02x:%02x:%02x and VNI %d registered\n",
 		vdev->rx_q,
@@ -341,8 +367,28 @@ vxlan_unlink(struct vhost_dev *vdev)
 	int ret = 1;
 	unsigned i = 0, rx_count;
 	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_eth_tunnel_filter_conf tunnel_filter_conf;
 
 	if (vdev->ready == DEVICE_RX) {
+		memset(&tunnel_filter_conf, 0, sizeof(struct rte_eth_tunnel_filter_conf));
+
+		tunnel_filter_conf.outer_mac = &ports_eth_addr[0];
+		tunnel_filter_conf.inner_mac = &vdev->mac_address;
+		tunnel_filter_conf.tenant_id = tenant_id_conf[vdev->rx_q];
+		tunnel_filter_conf.filter_type = tep_filter_type[filter_idx];
+
+		tunnel_filter_conf.queue_id = vdev->rx_q;
+		tunnel_filter_conf.tunnel_type = RTE_TUNNEL_TYPE_VXLAN;
+
+		ret = rte_eth_dev_filter_ctrl(ports[0],
+				RTE_ETH_FILTER_TUNNEL,
+				RTE_ETH_FILTER_DELETE,
+				&tunnel_filter_conf);
+		if (ret) {
+			RTE_LOG(ERR, VHOST_DATA, "%d Failed to add device MAC address to cloud filter\n",
+				vdev->rx_q);
+			return;
+		}
 		for (i = 0; i < ETHER_ADDR_LEN; i++)
 			vdev->mac_address.addr_bytes[i] = 0;
 
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 08/10] examples/tep_termination:add Tx checksum offload configuration for inner header
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (6 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 07/10] examples/tep_termination:add tunnel filter type configuration Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 09/10] examples/tep_termination:add TSO offload configuration Jijiang Liu
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

For VXLAN packet, the inner Tx checksum offload means inner IPv4 and inner L4(TCP/UDP/SCTP).

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/tep_termination/main.c  |   15 +++++++
 examples/tep_termination/vxlan.c |   77 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index e8142e0..7c69a82 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -119,6 +119,9 @@ uint16_t num_devices;
 /* VXLAN UDP destination port */
 uint16_t udp_port;
 
+/* enable/disable inner TX checksum */
+uint8_t tx_checksum;
+
 /* RX filter type for tunneling packet */
 uint8_t filter_idx;
 
@@ -242,6 +245,7 @@ vep_termination_usage(const char *prgname)
 	RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
 	"		--udp-port: UDP destination port for VXLAN packet\n"
 	"		--nb-devices: number of virtIO device\n"
+	"		--tx-checksum [0|1]: inner Tx checksum offload\n"
 	"		--filter-type[1-3]: filter type for tunneling packet\n"
 	"		    1: Inner MAC&VLAN and tenent ID\n"
 	"		    2: Inner MAC and tenent ID\n"
@@ -266,6 +270,7 @@ tep_parse_args(int argc, char **argv)
 	static struct option long_option[] = {
 		{"udp-port", required_argument, NULL, 0},
 		{"nb-devices", required_argument, NULL, 0},
+		{"tx-checksum", required_argument, NULL, 0},
 		{"filter-type", required_argument, NULL, 0},
 		{"stats", required_argument, NULL, 0},
 		{"dev-basename", required_argument, NULL, 0},
@@ -305,6 +310,16 @@ tep_parse_args(int argc, char **argv)
 					return -1;
 				}
 			}
+
+			 if (!strncmp(long_option[option_index].name, "tx-checksum", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, 1);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for tx-checksum [0|1]\n");
+					vep_termination_usage(prgname);
+					return -1;
+				} else
+					tx_checksum = ret;
+			}
 			
 			if (!strncmp(long_option[option_index].name, "filter-type", MAX_LONG_OPT_SZ)) {
 				ret = parse_num_opt(optarg, 3);
diff --git a/examples/tep_termination/vxlan.c b/examples/tep_termination/vxlan.c
index 942eb10..6fc75ee 100644
--- a/examples/tep_termination/vxlan.c
+++ b/examples/tep_termination/vxlan.c
@@ -43,11 +43,21 @@
 #include "main.h"
 #include "vxlan.h"
 
+extern uint8_t tx_checksum;
 extern struct vxlan_conf vxdev;
 extern struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
 extern struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
 extern uint16_t udp_port;
 
+static uint16_t
+get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags)
+{
+	if (ethertype == rte_cpu_to_be_16(ETHER_TYPE_IPv4))
+		return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
+	else /* assume ethertype == ETHER_TYPE_IPv6 */
+		return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
+}
+
 /*
  * Parse an ethernet header to fill the ethertype, l2_len, l3_len and
  * ipproto. This function is able to recognize IPv4/IPv6 with one optional vlan
@@ -87,6 +97,67 @@ parse_ethernet(struct ether_hdr *eth_hdr, struct offload_info *info)
 	}
                 
 }
+/* if possible, calculate the checksum of a packet in hw or sw,
+ *  * depending on the testpmd command line configuration */
+static uint64_t
+process_inner_cksums(struct ether_hdr *eth_hdr, struct offload_info *info)
+{
+	void *l3_hdr = NULL;
+	struct ipv4_hdr *ipv4_hdr;
+	struct ipv6_hdr *ipv6_hdr;
+	struct udp_hdr *udp_hdr;
+	struct tcp_hdr *tcp_hdr;
+	struct sctp_hdr *sctp_hdr;
+	uint64_t ol_flags = 0;
+	
+	info->l2_len = sizeof(struct ether_hdr);
+	info->ethertype = eth_hdr->ether_type;
+
+	if (info->ethertype == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
+		struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
+		info->l2_len  += sizeof(struct vlan_hdr);
+		info->ethertype = vlan_hdr->eth_proto;
+	}
+
+	l3_hdr = (char *)eth_hdr + info->l2_len;
+
+	if (info->ethertype == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
+		ipv4_hdr = l3_hdr;
+		ipv4_hdr->hdr_checksum = 0;
+		ol_flags |= PKT_TX_IPV4;
+		ol_flags |= PKT_TX_IP_CKSUM;
+		info->l3_len = sizeof(struct ipv4_hdr);
+		info->l4_proto = ipv4_hdr->next_proto_id;
+	} else if (info->ethertype == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
+		ipv6_hdr = l3_hdr;
+		info->l3_len = sizeof(struct ipv6_hdr);
+		info->l4_proto = ipv6_hdr->proto;
+		ol_flags |= PKT_TX_IPV6;
+	} else
+		return 0; /* packet type not supported, nothing to do */
+
+	if (info->l4_proto == IPPROTO_UDP) {
+		udp_hdr = (struct udp_hdr *)((char *)l3_hdr + info->l3_len);
+		/* do not recalculate udp cksum if it was 0 */
+		udp_hdr->dgram_cksum = 0;
+		ol_flags |= PKT_TX_UDP_CKSUM;
+		udp_hdr->dgram_cksum = get_psd_sum(l3_hdr,
+				info->ethertype, ol_flags);
+	} else if (info->l4_proto == IPPROTO_TCP) {
+		tcp_hdr = (struct tcp_hdr *)((char *)l3_hdr + info->l3_len);
+		tcp_hdr->cksum = 0;
+		ol_flags |= PKT_TX_TCP_CKSUM;
+		tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype,
+				ol_flags);
+
+	} else if (info->l4_proto == IPPROTO_SCTP) {
+		sctp_hdr = (struct sctp_hdr *)((char *)l3_hdr + info->l3_len);
+		sctp_hdr->cksum = 0;
+		ol_flags |= PKT_TX_SCTP_CKSUM;
+	}
+
+	return ol_flags;
+}
 
 int decapsulation(struct rte_mbuf *pkt)
 {
@@ -137,6 +208,12 @@ int encapsulation(struct rte_mbuf *m, uint8_t vport_id)
 	/* outer IP checksum */
 	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
 	ip->hdr_checksum = 0;
+	if (tx_checksum) {
+		ol_flags |= process_inner_cksums(phdr, &info);
+		m->l2_len = info.l2_len;
+		m->l3_len = info.l3_len;
+		m->l2_len += ETHER_VXLAN_HLEN;
+	}
 
 	m->outer_l2_len = sizeof(struct ether_hdr);
 	m->outer_l3_len = sizeof(struct ipv4_hdr);
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 09/10] examples/tep_termination:add TSO offload configuration
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (7 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 08/10] examples/tep_termination:add Tx checksum offload configuration for inner header Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 10/10] examples/tep_termination:add the configuration for encapsulation and the decapsulation Jijiang Liu
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

If the 'tso-segsz' is not 0, which means TSO offload is enabled.

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/tep_termination/main.c  |   19 +++++++++++++++++--
 examples/tep_termination/vxlan.c |    4 ++++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 7c69a82..8ce78ee 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -122,6 +122,9 @@ uint16_t udp_port;
 /* enable/disable inner TX checksum */
 uint8_t tx_checksum;
 
+/* TSO segment size */
+uint16_t tso_segsz = 0;
+
 /* RX filter type for tunneling packet */
 uint8_t filter_idx;
 
@@ -246,6 +249,7 @@ vep_termination_usage(const char *prgname)
 	"		--udp-port: UDP destination port for VXLAN packet\n"
 	"		--nb-devices: number of virtIO device\n"
 	"		--tx-checksum [0|1]: inner Tx checksum offload\n"
+	"		--tso-segsz [0-N]: TSO segment size\n"
 	"		--filter-type[1-3]: filter type for tunneling packet\n"
 	"		    1: Inner MAC&VLAN and tenent ID\n"
 	"		    2: Inner MAC and tenent ID\n"
@@ -271,6 +275,7 @@ tep_parse_args(int argc, char **argv)
 		{"udp-port", required_argument, NULL, 0},
 		{"nb-devices", required_argument, NULL, 0},
 		{"tx-checksum", required_argument, NULL, 0},
+		{"tso-segsz", required_argument, NULL, 0},
 		{"filter-type", required_argument, NULL, 0},
 		{"stats", required_argument, NULL, 0},
 		{"dev-basename", required_argument, NULL, 0},
@@ -301,6 +306,16 @@ tep_parse_args(int argc, char **argv)
 				} else 
 					num_devices = ret;
 			}
+
+			if (!strncmp(long_option[option_index].name, "tso-segsz", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, INT16_MAX);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for TCP segment size [0-N]\n");
+						vep_termination_usage(prgname);
+					return -1;
+				} else 
+					tso_segsz = ret;
+			}
 	
 			if (!strncmp(long_option[option_index].name, "udp-port", MAX_LONG_OPT_SZ)) {
 				ret = parse_num_opt(optarg, INT16_MAX);
@@ -310,8 +325,8 @@ tep_parse_args(int argc, char **argv)
 					return -1;
 				}
 			}
-
-			 if (!strncmp(long_option[option_index].name, "tx-checksum", MAX_LONG_OPT_SZ)) {
+			
+			if (!strncmp(long_option[option_index].name, "tx-checksum", MAX_LONG_OPT_SZ)) {
 				ret = parse_num_opt(optarg, 1);
 				if (ret == -1) {
 					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for tx-checksum [0|1]\n");
diff --git a/examples/tep_termination/vxlan.c b/examples/tep_termination/vxlan.c
index 6fc75ee..e3ef832 100644
--- a/examples/tep_termination/vxlan.c
+++ b/examples/tep_termination/vxlan.c
@@ -48,6 +48,7 @@ extern struct vxlan_conf vxdev;
 extern struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
 extern struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
 extern uint16_t udp_port;
+extern uint16_t tso_segsz;
 
 static uint16_t
 get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags)
@@ -149,6 +150,8 @@ process_inner_cksums(struct ether_hdr *eth_hdr, struct offload_info *info)
 		ol_flags |= PKT_TX_TCP_CKSUM;
 		tcp_hdr->cksum = get_psd_sum(l3_hdr, info->ethertype,
 				ol_flags);
+		if (tso_segsz != 0)
+			ol_flags |= PKT_TX_TCP_SEG;
 
 	} else if (info->l4_proto == IPPROTO_SCTP) {
 		sctp_hdr = (struct sctp_hdr *)((char *)l3_hdr + info->l3_len);
@@ -219,6 +222,7 @@ int encapsulation(struct rte_mbuf *m, uint8_t vport_id)
 	m->outer_l3_len = sizeof(struct ipv4_hdr);
 
 	m->ol_flags |= ol_flags;
+	m->tso_segsz = tso_segsz;
 
 	/*VXLAN HEADER*/
 	vxlan->vx_flags = VXLAN_FLAGS;
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [dpdk-dev] [PATCH RFC 10/10] examples/tep_termination:add the configuration for encapsulation and the decapsulation
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (8 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 09/10] examples/tep_termination:add TSO offload configuration Jijiang Liu
@ 2015-04-16  3:55 ` Jijiang Liu
  2015-04-20  7:22 ` [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Liu, Jijiang
  2015-04-28  3:31 ` Liu, Jijiang
  11 siblings, 0 replies; 13+ messages in thread
From: Jijiang Liu @ 2015-04-16  3:55 UTC (permalink / raw)
  To: dev, walter.e.gilmore, thomas.long

The two flags by default are enabled, but sometimes we want to know the performance influence due to encapsulation and decapsulation operations, and
I think we should add the two options. 

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
---
 examples/tep_termination/main.c        |   36 ++++++++++++++++++++++++++++++-
 examples/tep_termination/vxlan_setup.c |    8 +++++-
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/examples/tep_termination/main.c b/examples/tep_termination/main.c
index 8ce78ee..7d021f9 100644
--- a/examples/tep_termination/main.c
+++ b/examples/tep_termination/main.c
@@ -125,6 +125,12 @@ uint8_t tx_checksum;
 /* TSO segment size */
 uint16_t tso_segsz = 0;
 
+/* enable/disable decapsulation */
+uint8_t rx_decap = 1;
+
+/* enable/disable encapsulation */
+uint8_t tx_encap = 1;
+
 /* RX filter type for tunneling packet */
 uint8_t filter_idx;
 
@@ -250,6 +256,8 @@ vep_termination_usage(const char *prgname)
 	"		--nb-devices: number of virtIO device\n"
 	"		--tx-checksum [0|1]: inner Tx checksum offload\n"
 	"		--tso-segsz [0-N]: TSO segment size\n"
+	"		--decap [0|1]: Decapsulation for tunneling packet\n"
+	"		--encap [0|1]: Encapsulation for tunneling packet\n"
 	"		--filter-type[1-3]: filter type for tunneling packet\n"
 	"		    1: Inner MAC&VLAN and tenent ID\n"
 	"		    2: Inner MAC and tenent ID\n"
@@ -276,6 +284,8 @@ tep_parse_args(int argc, char **argv)
 		{"nb-devices", required_argument, NULL, 0},
 		{"tx-checksum", required_argument, NULL, 0},
 		{"tso-segsz", required_argument, NULL, 0},
+		{"decap", required_argument, NULL, 0},
+		{"encap", required_argument, NULL, 0},
 		{"filter-type", required_argument, NULL, 0},
 		{"stats", required_argument, NULL, 0},
 		{"dev-basename", required_argument, NULL, 0},
@@ -325,8 +335,30 @@ tep_parse_args(int argc, char **argv)
 					return -1;
 				}
 			}
-			
-			if (!strncmp(long_option[option_index].name, "tx-checksum", MAX_LONG_OPT_SZ)) {
+
+			/* Enable/disable encapsulation on RX. */
+			if (!strncmp(long_option[option_index].name, "decap", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, 1);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for decapsulation [0|1]\n");
+					vep_termination_usage(prgname);
+					return -1;
+				} else
+					rx_decap = ret;
+			}
+
+			/* Enable/disable encapsulation on TX. */
+			if (!strncmp(long_option[option_index].name, "encap", MAX_LONG_OPT_SZ)) {
+				ret = parse_num_opt(optarg, 1);
+				if (ret == -1) {
+					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for encapsulation [0|1]\n");
+					vep_termination_usage(prgname);
+					return -1;
+				} else
+					tx_encap = ret;
+			}
+
+			 if (!strncmp(long_option[option_index].name, "tx-checksum", MAX_LONG_OPT_SZ)) {
 				ret = parse_num_opt(optarg, 1);
 				if (ret == -1) {
 					RTE_LOG(INFO, VHOST_CONFIG, "Invalid argument for tx-checksum [0|1]\n");
diff --git a/examples/tep_termination/vxlan_setup.c b/examples/tep_termination/vxlan_setup.c
index 312a878..b4e8fbc 100644
--- a/examples/tep_termination/vxlan_setup.c
+++ b/examples/tep_termination/vxlan_setup.c
@@ -83,6 +83,8 @@ extern uint16_t num_devices;
 extern uint16_t udp_port;
 extern uint8_t ports[RTE_MAX_ETHPORTS];
 extern uint8_t filter_idx;
+extern uint8_t rx_decap;
+extern uint8_t tx_encap;
 
 /* ethernet addresses of ports */
 extern struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
@@ -237,7 +239,8 @@ vxlan_rx_process(struct rte_mbuf *pkt)
 		| PKT_RX_TUNNEL_IPV6_HDR)) == 0)
 		return -1;
 
-	ret = decapsulation(pkt);
+	if(rx_decap)
+		ret = decapsulation(pkt);
 
 	return ret;
 }
@@ -252,7 +255,8 @@ vxlan_tx_process(uint8_t vport_id, struct rte_mbuf *pkt)
 		return -1;
 	}
 
-	ret = encapsulation(pkt, vport_id);
+	if (tx_encap)
+		ret = encapsulation(pkt, vport_id);
 
 	return ret;
 }
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (9 preceding siblings ...)
  2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 10/10] examples/tep_termination:add the configuration for encapsulation and the decapsulation Jijiang Liu
@ 2015-04-20  7:22 ` Liu, Jijiang
  2015-04-28  3:31 ` Liu, Jijiang
  11 siblings, 0 replies; 13+ messages in thread
From: Liu, Jijiang @ 2015-04-20  7:22 UTC (permalink / raw)
  To: Liu, Jijiang; +Cc: dev


Any comments on this RFC patch set ?

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> Sent: Thursday, April 16, 2015 11:56 AM
> To: dev@dpdk.org; Gilmore, Walter E; Long, Thomas
> Subject: [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample
> 
> This VXLAN example simulates a VXLAN Tunnel endpoint(VTEP) termination in
> DPDK, which is used to demonstrate the offload and filtering capabilities of i40
> NIC for VXLAN packet.
> 
> And this example uses the basic virtio devices management function from vHost
> example, and it uses us-Vhost interface and tunnel filtering mechanism to direct
> the traffic to/from a specific VM.
> 
> In addition, this sample is also designed to show how tunneling protocols can be
> handled. For the vHost interface, we do not need to support zero copy/inter VM
> packet transfer etc. The approach that we take would be of benefit to you in
> that we put a pluggable structure in place so that the application could be easily
> extended to support a new tunneling protocol.
> 
> The software framework is as follows:
> 
>        |-------------------|   |-------------------|
>        | VM-1(VNI:100)     |   |  VM-2(VNI:200)    |
>        | |------| |------| |   | |------| |------| |
>        | |vport0| |vport1| |   | |vport0| |vport1| |
>        |-|------|-|------|-|   |-|------|-|------|-|      Guests
>                     	\           /
>          |-------------\-------/--------|
>          |     us-vHost interface       |
>          |          |-|----|--|         |
>          |     decap| | TEP|  | encap   |       DPDK App
>          |          |-|----|--|         |
>          |            |    |            |
>          |------------|----|------------|
>                       	|    |
>         |-------------|----|---------------|
>         |tunnel filter|    | IP/L4 Tx csum |
>         |IP/L4 csum   |    | TSO           |
>         |packet type  |    |               |               NIC
>         |CRC strip    |    |               |
>         |-------------|----|---------------|
>                       	|    |
>                       	|    |
>                       	|    |
>                       	/-------\
>                       	VXLAN Tunnel
> 
> The sample will support the followings:
> 1> Tunneling packet recognition.
> 
> 2> The port of UDP tunneling is configurable
> 
> 3> Directing of incoming traffic to the correct queue based on the tunnel filter
> type such as inner MAC address and VNI.
> 	The VNI will be assigned from a static internal table based on the us-
> vhost device ID. Each device will receive a unique device ID. The inner MAC will
> be learned from the first packet transmitted from a device.
> 
> 4> Decapsulation of Rx VXLAN traffic. This is a software only
> 4> operation(will use HW header split instead later)
> 
> 5> Encapsulation of Tx VXLAN traffic. This is a software only operation
> 
> 6> Tx outer IP, inner IP and L4 checksum offload
> 
> 7> TSO support for tunneling packet
> 
> Limitations:
> 1. No ARP support
> 2. There are some duplicated source codes because of using the basic virtio
> device management function from vhost sample, but consider that current vhost
> sample is quite complicated and huge enough, and I think we shall have a
> separate sample for tunneling packet processing.
> 3. Currently, only the i40e NIC is supported in the sample, but other types of
> NICs also can be supported later if those NICs are able to support tunneling
> packet filter.
> 
> 
> Jijiang Liu (10):
>   create VXLAN sample framework using virtio device management function
>   add basic VXLAN structures
>   add VXLAN operation APIs
>   support overlay operations
>   Add encapsulation and decapsulation function
>   add udp port configuration
>   add filter type configuration
>   add tx checksum offload configuration
>   add TSO offload configuration
>   add encapsulation and decapsulation flags
> 
>  examples/Makefile                      |    1 +
>  examples/tep_termination/Makefile      |   58 ++
>  examples/tep_termination/main.c        | 1117
> ++++++++++++++++++++++++++++++++
>  examples/tep_termination/main.h        |  113 ++++
>  examples/tep_termination/vxlan.c       |  242 +++++++
>  examples/tep_termination/vxlan.h       |   81 +++
>  examples/tep_termination/vxlan_setup.c |  453 +++++++++++++
>  examples/tep_termination/vxlan_setup.h |   76 +++
>  8 files changed, 2141 insertions(+), 0 deletions(-)  create mode 100644
> examples/tep_termination/Makefile  create mode 100644
> examples/tep_termination/main.c  create mode 100644
> examples/tep_termination/main.h  create mode 100644
> examples/tep_termination/vxlan.c  create mode 100644
> examples/tep_termination/vxlan.h  create mode 100644
> examples/tep_termination/vxlan_setup.c
>  create mode 100644 examples/tep_termination/vxlan_setup.h
> 
> --
> 1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample
  2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
                   ` (10 preceding siblings ...)
  2015-04-20  7:22 ` [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Liu, Jijiang
@ 2015-04-28  3:31 ` Liu, Jijiang
  11 siblings, 0 replies; 13+ messages in thread
From: Liu, Jijiang @ 2015-04-28  3:31 UTC (permalink / raw)
  To: Liu, Jijiang; +Cc: dev

Hi All,

So far, I have not got any comments yet, which means  all of you agree on the proposal of the VXLAN example? 
Actually, if I can get your comments as soon as possible, which can avoid a lot of discussions in formal patch set and can accelerate the development.

Thanks  
Jijiang Liu

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jijiang Liu
> Sent: Thursday, April 16, 2015 11:56 AM
> To: dev@dpdk.org; Gilmore, Walter E; Long, Thomas
> Subject: [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample
> 
> This VXLAN example simulates a VXLAN Tunnel endpoint(VTEP) termination in
> DPDK, which is used to demonstrate the offload and filtering capabilities of i40
> NIC for VXLAN packet.
> 
> And this example uses the basic virtio devices management function from vHost
> example, and it uses us-Vhost interface and tunnel filtering mechanism to direct
> the traffic to/from a specific VM.
> 
> In addition, this sample is also designed to show how tunneling protocols can be
> handled. For the vHost interface, we do not need to support zero copy/inter VM
> packet transfer etc. The approach that we take would be of benefit to you in
> that we put a pluggable structure in place so that the application could be easily
> extended to support a new tunneling protocol.
> 
> The software framework is as follows:
> 
>        |-------------------|   |-------------------|
>        | VM-1(VNI:100)     |   |  VM-2(VNI:200)    |
>        | |------| |------| |   | |------| |------| |
>        | |vport0| |vport1| |   | |vport0| |vport1| |
>        |-|------|-|------|-|   |-|------|-|------|-|      Guests
>                     	\           /
>          |-------------\-------/--------|
>          |     us-vHost interface       |
>          |          |-|----|--|         |
>          |     decap| | TEP|  | encap   |       DPDK App
>          |          |-|----|--|         |
>          |            |    |            |
>          |------------|----|------------|
>                       	|    |
>         |-------------|----|---------------|
>         |tunnel filter|    | IP/L4 Tx csum |
>         |IP/L4 csum   |    | TSO           |
>         |packet type  |    |               |               NIC
>         |CRC strip    |    |               |
>         |-------------|----|---------------|
>                       	|    |
>                       	|    |
>                       	|    |
>                       	/-------\
>                       	VXLAN Tunnel
> 
> The sample will support the followings:
> 1> Tunneling packet recognition.
> 
> 2> The port of UDP tunneling is configurable
> 
> 3> Directing of incoming traffic to the correct queue based on the tunnel filter
> type such as inner MAC address and VNI.
> 	The VNI will be assigned from a static internal table based on the us-
> vhost device ID. Each device will receive a unique device ID. The inner MAC will
> be learned from the first packet transmitted from a device.
> 
> 4> Decapsulation of Rx VXLAN traffic. This is a software only
> 4> operation(will use HW header split instead later)
> 
> 5> Encapsulation of Tx VXLAN traffic. This is a software only operation
> 
> 6> Tx outer IP, inner IP and L4 checksum offload
> 
> 7> TSO support for tunneling packet
> 
> Limitations:
> 1. No ARP support
> 2. There are some duplicated source codes because of using the basic virtio
> device management function from vhost sample, but consider that current vhost
> sample is quite complicated and huge enough, and I think we shall have a
> separate sample for tunneling packet processing.
> 3. Currently, only the i40e NIC is supported in the sample, but other types of
> NICs also can be supported later if those NICs are able to support tunneling
> packet filter.
> 
> 
> Jijiang Liu (10):
>   create VXLAN sample framework using virtio device management function
>   add basic VXLAN structures
>   add VXLAN operation APIs
>   support overlay operations
>   Add encapsulation and decapsulation function
>   add udp port configuration
>   add filter type configuration
>   add tx checksum offload configuration
>   add TSO offload configuration
>   add encapsulation and decapsulation flags
> 
>  examples/Makefile                      |    1 +
>  examples/tep_termination/Makefile      |   58 ++
>  examples/tep_termination/main.c        | 1117
> ++++++++++++++++++++++++++++++++
>  examples/tep_termination/main.h        |  113 ++++
>  examples/tep_termination/vxlan.c       |  242 +++++++
>  examples/tep_termination/vxlan.h       |   81 +++
>  examples/tep_termination/vxlan_setup.c |  453 +++++++++++++
>  examples/tep_termination/vxlan_setup.h |   76 +++
>  8 files changed, 2141 insertions(+), 0 deletions(-)  create mode 100644
> examples/tep_termination/Makefile  create mode 100644
> examples/tep_termination/main.c  create mode 100644
> examples/tep_termination/main.h  create mode 100644
> examples/tep_termination/vxlan.c  create mode 100644
> examples/tep_termination/vxlan.h  create mode 100644
> examples/tep_termination/vxlan_setup.c
>  create mode 100644 examples/tep_termination/vxlan_setup.h
> 
> --
> 1.7.7.6

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2015-04-28  3:31 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-16  3:55 [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 01/10] examples/tep_termination:initialize the VXLAN example Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 02/10] examples/tep_termination:define VXLAN device information and APIs Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 03/10] examples/tep_termination:add the pluggable structures for VXLAN packet processing Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 04/10] examples/tep_termination:implement " Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 05/10] examples/tep_termination:implement the APIs of encapsulation and decapsulation for VXLAN Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 06/10] examples/tep_termination:add UDP port configuration for UDP tunneling packet Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 07/10] examples/tep_termination:add tunnel filter type configuration Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 08/10] examples/tep_termination:add Tx checksum offload configuration for inner header Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 09/10] examples/tep_termination:add TSO offload configuration Jijiang Liu
2015-04-16  3:55 ` [dpdk-dev] [PATCH RFC 10/10] examples/tep_termination:add the configuration for encapsulation and the decapsulation Jijiang Liu
2015-04-20  7:22 ` [dpdk-dev] [PATCH RFC 00/10] Add a VXLAN sample Liu, Jijiang
2015-04-28  3:31 ` Liu, Jijiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).