examples/tep_term: remove this application

This example sets up a scenario that VXLAN packets can be received
by different PF queues based on VNID and each queue is bound to a VM
with a VNID so that the VM can receive its inner packets.

Usually, OVS is used to do the software encap/decap for VXLAN packets.

And the VXLAN packets offloading can be replaced with flow rules in
testpmd like Chapter "Sample VXLAN flow rules" in Testpmd Application
User Guide.

And this example hasn't been used for a long time.

So deprecate this example.

Signed-off-by: Xiaoyun Li <xiaoyun.li@intel.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Andrew Rybchenko <arybchenko@solarflare.com>
Acked-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Xiaoyun Li 2020-10-26 16:11:43 +08:00 committed by Thomas Monjalon
parent eda44ced0e
commit 079981e980
15 changed files with 47 additions and 3810 deletions

View File

@ -1670,10 +1670,6 @@ M: John McNamara <john.mcnamara@intel.com>
F: examples/skeleton/
F: doc/guides/sample_app_ug/skeleton.rst
TEP termination example
M: Xiaoyun Li <xiaoyun.li@intel.com>
F: examples/tep_termination/
VMDq examples
F: examples/vmdq/
F: doc/guides/sample_app_ug/vmdq_forwarding.rst

View File

@ -373,6 +373,9 @@ Removed Items
* Removed Python 2 support since it was EOL'd in January 2020.
* Removed TEP termination sample application.
API Changes
-----------

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@ -51,7 +51,6 @@ Sample Applications User Guides
eventdev_pipeline
dist_app
vm_power_management
tep_termination
ptpclient
performance_thread
fips_validation

View File

@ -1,214 +0,0 @@
.. SPDX-License-Identifier: BSD-3-Clause
Copyright(c) 2010-2015 Intel Corporation.
TEP termination Sample Application
==================================
The TEP (Tunnel End point) termination sample application simulates a VXLAN
Tunnel Endpoint (VTEP) termination in DPDK, which is used to demonstrate
the offload and filtering capabilities of Intel® XL710 10/40 Gigabit Ethernet
Controller for VXLAN packet.
This sample uses the basic virtio devices management mechanism from vhost example,
and also uses the us-vHost interface and tunnel filtering mechanism to direct
a specified traffic to a specific VM.
In addition, this sample is also designed to show how tunneling protocols can be handled.
Background
----------
With virtualization, overlay networks allow a network structure to be built
or imposed across physical nodes which is abstracted away from the actual
underlining physical network connections.
This allows network isolation, QOS, etc to be provided on a per client basis.
.. _figure_overlay_networking:
.. figure:: img/overlay_networking.*
Overlay Networking.
In a typical setup, the network overlay tunnel is terminated at the Virtual/Tunnel End Point (VEP/TEP).
The TEP is normally located at the physical host level ideally in the software switch.
Due to processing constraints and the inevitable bottleneck that the switch
becomes, the ability to offload overlay support features becomes an important requirement.
Intel® XL710 10/40 Gigabit Ethernet network card provides hardware filtering
and offload capabilities to support overlay networks implementations such as MAC in UDP and MAC in GRE.
Sample Code Overview
--------------------
The DPDK TEP termination sample code demonstrates the offload and filtering
capabilities of Intel® XL710 10/40 Gigabit Ethernet Controller for VXLAN packet.
The sample code is based on vhost library.
The vhost library is developed for user space Ethernet switch to easily integrate with vhost functionality.
The sample will support the followings:
* Tunneling packet recognition.
* The port of UDP tunneling is configurable
* Directing incoming traffic to the correct queue based on the tunnel filter type.
The supported filter type are listed below.
* Inner MAC and VLAN and tenant ID
* Inner MAC and tenant ID, and Outer MAC
* Inner MAC and tenant ID
The tenant ID 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 by the first packet transmitted from a device.
* Decapsulation of RX VXLAN traffic. This is a software only operation.
* Encapsulation of TX VXLAN traffic. This is a software only operation.
* Inner IP and inner L4 checksum offload.
* TSO offload support for tunneling packet.
The following figure shows the framework of the TEP termination sample
application based on DPDK vhost lib.
.. _figure_tep_termination_arch:
.. figure:: img/tep_termination_arch.*
TEP termination Framework Overview
Supported Distributions
-----------------------
The example in this section have been validated with the following distributions:
* Fedora* 18
* Fedora* 19
* Fedora* 20
Running the Sample Code
-----------------------
Run the tep_termination sample code:
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
-p 0x1 --dev-basename tep-termination --nb-devices 4
--udp-port 4789 --filter-type 1
.. note::
Please note the huge-dir parameter instructs the DPDK to allocate its memory from the 2 MB page hugetlbfs.
Parameters
~~~~~~~~~~
**The same parameters with the vhost sample.**
Refer to :ref:`vhost_app_parameters` for detailed explanation.
**Number of Devices.**
The nb-devices option specifies the number of virtIO device.
The default value is 2.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 2
**Tunneling UDP port.**
The udp-port option is used to specify the destination UDP number for UDP tunneling packet.
The default value is 4789.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 2 --udp-port 4789
**Filter Type.**
The filter-type option is used to specify which filter type is used to
filter UDP tunneling packet to a specified queue.
The default value is 1, which means the filter type of inner MAC and tenant ID is used.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 2 --udp-port 4789 --filter-type 1
**TX Checksum.**
The tx-checksum option is used to enable or disable the inner header checksum offload.
The default value is 0, which means the checksum offload is disabled.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 2 --tx-checksum
**TCP segment size.**
The tso-segsz option specifies the TCP segment size for TSO offload for tunneling packet.
The default value is 0, which means TSO offload is disabled.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--tx-checksum --tso-segsz 800
**Decapsulation option.**
The decap option is used to enable or disable decapsulation operation for received VXLAN packet.
The default value is 1.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 4 --udp-port 4789 --decap 1
**Encapsulation option.**
The encap option is used to enable or disable encapsulation operation for transmitted packet.
The default value is 1.
.. code-block:: console
user@target:~$ ./<build_dir>/examples/dpdk-tep_termination -l 0-3 -n 4 --huge-dir /mnt/huge --
--nb-devices 4 --udp-port 4789 --encap 1
Running the Virtual Machine (QEMU)
----------------------------------
Refer to :ref:`vhost_app_run_vm`.
Running DPDK in the Virtual Machine
-----------------------------------
Refer to :ref:`vhost_app_run_dpdk_inside_guest`.
Passing Traffic to the Virtual Machine Device
---------------------------------------------
For a virtio-net device to receive traffic, the traffic's Layer 2 header must include
both the virtio-net device's MAC address.
The DPDK sample code behaves in a similar manner to a learning switch in that
it learns the MAC address of the virtio-net devices from the first transmitted packet.
On learning the MAC address,
the DPDK vhost sample code prints a message with the MAC address and tenant ID virtio-net device.
For example:
.. code-block:: console
DATA: (0) MAC_ADDRESS cc:bb:bb:bb:bb:bb and VNI 1000 registered
The above message indicates that device 0 has been registered with MAC address cc:bb:bb:bb:bb:bb and VNI 1000.
Any packets received on the NIC with these values are placed on the devices receive queue.

View File

@ -4933,6 +4933,49 @@ Validate and create a QinQ rule on port 0 to steer traffic to a queue on the hos
0 0 0 i- ETH VLAN VLAN=>VF QUEUE
1 0 0 i- ETH VLAN VLAN=>PF QUEUE
Sample VXLAN flow rules
~~~~~~~~~~~~~~~~~~~~~~~
Before creating VXLAN rule(s), the UDP port should be added for VXLAN packet
filter on a port::
testpmd> rx_vxlan_port add 4789 0
Create VXLAN rules on port 0 to steer traffic to PF queues.
::
testpmd> flow create 0 ingress pattern eth / ipv4 / udp / vxlan /
eth dst is 00:11:22:33:44:55 / end actions pf / queue index 1 / end
Flow rule #0 created
testpmd> flow create 0 ingress pattern eth / ipv4 / udp / vxlan vni is 3 /
eth dst is 00:11:22:33:44:55 / end actions pf / queue index 2 / end
Flow rule #1 created
testpmd> flow create 0 ingress pattern eth / ipv4 / udp / vxlan /
eth dst is 00:11:22:33:44:55 / vlan tci is 10 / end actions pf /
queue index 3 / end
Flow rule #2 created
testpmd> flow create 0 ingress pattern eth / ipv4 / udp / vxlan vni is 5 /
eth dst is 00:11:22:33:44:55 / vlan tci is 20 / end actions pf /
queue index 4 / end
Flow rule #3 created
testpmd> flow create 0 ingress pattern eth dst is 00:00:00:00:01:00 / ipv4 /
udp / vxlan vni is 6 / eth dst is 00:11:22:33:44:55 / end actions pf /
queue index 5 / end
Flow rule #4 created
testpmd> flow list 0
ID Group Prio Attr Rule
0 0 0 i- ETH IPV4 UDP VXLAN ETH => QUEUE
1 0 0 i- ETH IPV4 UDP VXLAN ETH => QUEUE
2 0 0 i- ETH IPV4 UDP VXLAN ETH VLAN => QUEUE
3 0 0 i- ETH IPV4 UDP VXLAN ETH VLAN => QUEUE
4 0 0 i- ETH IPV4 UDP VXLAN ETH => QUEUE
Sample VXLAN encapsulation rule
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -40,7 +40,7 @@ all_examples = [
'server_node_efd/node',
'server_node_efd/server',
'service_cores',
'skeleton', 'tep_termination',
'skeleton',
'timer', 'vdpa',
'vhost', 'vhost_crypto',
'vhost_blk', 'vm_power_manager',

View File

@ -1,45 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2015 Intel Corporation
# binary name
APP = tep_termination
# all source are stored in SRCS-y
SRCS-y := main.c vxlan_setup.c vxlan.c
# Build using pkg-config variables if possible
ifneq ($(shell pkg-config --exists libdpdk && echo 0),0)
$(error "no installation of DPDK found")
endif
all: shared
.PHONY: shared static
shared: build/$(APP)-shared
ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
ln -sf $(APP)-static build/$(APP)
LDFLAGS += -pthread
PKGCONF ?= pkg-config
PC_FILE := $(shell $(PKGCONF) --path libdpdk 2>/dev/null)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = $(shell $(PKGCONF) --static --libs libdpdk)
CFLAGS += -Wno-deprecated-declarations
build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
build:
@mkdir -p $@
.PHONY: clean
clean:
rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
test -d build && rmdir -p build || true

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2015 Intel Corporation
*/
#ifndef _MAIN_H_
#define _MAIN_H_
#include <rte_ether.h>
/* 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
/* Max number of devices. Limited by the application. */
#define MAX_DEVICES 64
enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};
/* 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;
/**< Bad inner IP csum for tunneling pkt */
rte_atomic64_t rx_bad_ip_csum;
/**< Bad inner L4 csum for tunneling pkt */
rte_atomic64_t rx_bad_l4_csum;
} __rte_cache_aligned;
/**
* Device linked list structure for data path.
*/
struct vhost_dev {
int vid;
/**< 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 rte_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 {
/**< Pointer to head in free linked list. */
struct virtio_net_data_ll *ll_root_free;
/**< Pointer to head of used linked list. */
struct virtio_net_data_ll *ll_root_used;
/**< Number of devices on lcore. */
uint32_t device_num;
/**< Flag to synchronize device removal. */
volatile uint8_t dev_removal_flag;
};
struct lcore_info {
/**< Pointer to data core specific lcore_ll_info struct */
struct lcore_ll_info *lcore_ll;
};
struct virtio_net_data_ll {
/**< Pointer to device created by configuration core. */
struct vhost_dev *vdev;
/**< Pointer to next device in linked list. */
struct virtio_net_data_ll *next;
};
uint32_t
virtio_dev_rx(int vid, struct rte_mbuf **pkts, uint32_t count);
#endif /* _MAIN_H_ */

View File

@ -1,16 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2017 Intel Corporation
# meson file, for building this example as part of a main DPDK build.
#
# To build this example as a standalone application with an already-installed
# DPDK instance, use 'make'
if not is_linux
build = false
endif
deps += ['hash', 'vhost']
cflags += '-Wno-deprecated-declarations'
sources = files(
'main.c', 'vxlan.c', 'vxlan_setup.c'
)

View File

@ -1,243 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2015 Intel Corporation
*/
#include <stdint.h>
#include <rte_mbuf.h>
#include <rte_hash_crc.h>
#include <rte_byteorder.h>
#include <rte_udp.h>
#include <rte_tcp.h>
#include <rte_sctp.h>
#include "main.h"
#include "vxlan.h"
static uint16_t
get_psd_sum(void *l3_hdr, uint16_t ethertype, uint64_t ol_flags)
{
if (ethertype == RTE_ETHER_TYPE_IPV4)
return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
else /* assume ethertype == RTE_ETHER_TYPE_IPV6 */
return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
}
/**
* Parse an ethernet header to fill the ethertype, outer_l2_len, outer_l3_len and
* ipproto. This function is able to recognize IPv4/IPv6 with one optional vlan
* header.
*/
static void
parse_ethernet(struct rte_ether_hdr *eth_hdr, union tunnel_offload_info *info,
uint8_t *l4_proto)
{
struct rte_ipv4_hdr *ipv4_hdr;
struct rte_ipv6_hdr *ipv6_hdr;
uint16_t ethertype;
info->outer_l2_len = sizeof(struct rte_ether_hdr);
ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
if (ethertype == RTE_ETHER_TYPE_VLAN) {
struct rte_vlan_hdr *vlan_hdr =
(struct rte_vlan_hdr *)(eth_hdr + 1);
info->outer_l2_len += sizeof(struct rte_vlan_hdr);
ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
}
switch (ethertype) {
case RTE_ETHER_TYPE_IPV4:
ipv4_hdr = (struct rte_ipv4_hdr *)
((char *)eth_hdr + info->outer_l2_len);
info->outer_l3_len = sizeof(struct rte_ipv4_hdr);
*l4_proto = ipv4_hdr->next_proto_id;
break;
case RTE_ETHER_TYPE_IPV6:
ipv6_hdr = (struct rte_ipv6_hdr *)
((char *)eth_hdr + info->outer_l2_len);
info->outer_l3_len = sizeof(struct rte_ipv6_hdr);
*l4_proto = ipv6_hdr->proto;
break;
default:
info->outer_l3_len = 0;
*l4_proto = 0;
break;
}
}
/**
* Calculate the checksum of a packet in hardware
*/
static uint64_t
process_inner_cksums(struct rte_ether_hdr *eth_hdr,
union tunnel_offload_info *info)
{
void *l3_hdr = NULL;
uint8_t l4_proto;
uint16_t ethertype;
struct rte_ipv4_hdr *ipv4_hdr;
struct rte_ipv6_hdr *ipv6_hdr;
struct rte_udp_hdr *udp_hdr;
struct rte_tcp_hdr *tcp_hdr;
struct rte_sctp_hdr *sctp_hdr;
uint64_t ol_flags = 0;
info->l2_len = sizeof(struct rte_ether_hdr);
ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
if (ethertype == RTE_ETHER_TYPE_VLAN) {
struct rte_vlan_hdr *vlan_hdr =
(struct rte_vlan_hdr *)(eth_hdr + 1);
info->l2_len += sizeof(struct rte_vlan_hdr);
ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
}
l3_hdr = (char *)eth_hdr + info->l2_len;
if (ethertype == RTE_ETHER_TYPE_IPV4) {
ipv4_hdr = (struct rte_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 rte_ipv4_hdr);
l4_proto = ipv4_hdr->next_proto_id;
} else if (ethertype == RTE_ETHER_TYPE_IPV6) {
ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr;
info->l3_len = sizeof(struct rte_ipv6_hdr);
l4_proto = ipv6_hdr->proto;
ol_flags |= PKT_TX_IPV6;
} else
return 0; /* packet type not supported, nothing to do */
if (l4_proto == IPPROTO_UDP) {
udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info->l3_len);
ol_flags |= PKT_TX_UDP_CKSUM;
udp_hdr->dgram_cksum = get_psd_sum(l3_hdr,
ethertype, ol_flags);
} else if (l4_proto == IPPROTO_TCP) {
tcp_hdr = (struct rte_tcp_hdr *)((char *)l3_hdr + info->l3_len);
/* Put PKT_TX_TCP_SEG bit setting before get_psd_sum(), because
* it depends on PKT_TX_TCP_SEG to calculate pseudo-header
* checksum.
*/
if (tso_segsz != 0) {
ol_flags |= PKT_TX_TCP_SEG;
info->tso_segsz = tso_segsz;
info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
}
ol_flags |= PKT_TX_TCP_CKSUM;
tcp_hdr->cksum = get_psd_sum(l3_hdr, ethertype, ol_flags);
} else if (l4_proto == IPPROTO_SCTP) {
sctp_hdr = (struct rte_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)
{
uint8_t l4_proto = 0;
uint16_t outer_header_len;
struct rte_udp_hdr *udp_hdr;
union tunnel_offload_info info = { .data = 0 };
struct rte_ether_hdr *phdr =
rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
parse_ethernet(phdr, &info, &l4_proto);
if (l4_proto != IPPROTO_UDP)
return -1;
udp_hdr = (struct rte_udp_hdr *)((char *)phdr +
info.outer_l2_len + info.outer_l3_len);
/** check udp destination port, 4789 is the default vxlan port
* (rfc7348) or that the rx offload flag is set (i40e only
* currently)*/
if (udp_hdr->dst_port != rte_cpu_to_be_16(RTE_VXLAN_DEFAULT_PORT) &&
(pkt->packet_type & RTE_PTYPE_TUNNEL_MASK) == 0)
return -1;
outer_header_len = info.outer_l2_len + info.outer_l3_len
+ sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr);
rte_pktmbuf_adj(pkt, outer_header_len);
return 0;
}
void
encapsulation(struct rte_mbuf *m, uint8_t queue_id)
{
uint vport_id;
uint64_t ol_flags = 0;
uint32_t old_len = m->pkt_len, hash;
union tunnel_offload_info tx_offload = { .data = 0 };
struct rte_ether_hdr *phdr =
rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
/*Allocate space for new ethernet, IPv4, UDP and VXLAN headers*/
struct rte_ether_hdr *pneth =
(struct rte_ether_hdr *) rte_pktmbuf_prepend(m,
sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)
+ sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr));
struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *) &pneth[1];
struct rte_udp_hdr *udp = (struct rte_udp_hdr *) &ip[1];
struct rte_vxlan_hdr *vxlan = (struct rte_vxlan_hdr *) &udp[1];
/* convert TX queue ID to vport ID */
vport_id = queue_id - 1;
/* replace original Ethernet header with ours */
pneth = rte_memcpy(pneth, &app_l2_hdr[vport_id],
sizeof(struct rte_ether_hdr));
/* copy in IP header */
ip = rte_memcpy(ip, &app_ip_hdr[vport_id],
sizeof(struct rte_ipv4_hdr));
ip->total_length = rte_cpu_to_be_16(m->pkt_len
- sizeof(struct rte_ether_hdr));
/* outer IP checksum */
ol_flags |= PKT_TX_OUTER_IP_CKSUM;
ip->hdr_checksum = 0;
/* inner IP checksum offload */
if (tx_checksum) {
ol_flags |= process_inner_cksums(phdr, &tx_offload);
m->l2_len = tx_offload.l2_len;
m->l3_len = tx_offload.l3_len;
m->l4_len = tx_offload.l4_len;
m->l2_len += RTE_ETHER_VXLAN_HLEN;
}
m->outer_l2_len = sizeof(struct rte_ether_hdr);
m->outer_l3_len = sizeof(struct rte_ipv4_hdr);
ol_flags |= PKT_TX_TUNNEL_VXLAN;
m->ol_flags |= ol_flags;
m->tso_segsz = tx_offload.tso_segsz;
/*VXLAN HEADER*/
vxlan->vx_flags = rte_cpu_to_be_32(VXLAN_HF_VNI);
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 rte_udp_hdr)
+ sizeof(struct rte_vxlan_hdr));
udp->dst_port = rte_cpu_to_be_16(vxdev.dst_port);
hash = rte_hash_crc(phdr, 2 * RTE_ETHER_ADDR_LEN, phdr->ether_type);
udp->src_port = rte_cpu_to_be_16((((uint64_t) hash * PORT_RANGE) >> 32)
+ PORT_MIN);
return;
}

View File

@ -1,57 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2015 Intel Corporation
*/
#ifndef _VXLAN_H_
#define _VXLAN_H_
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_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_HF_VNI 0x08000000
extern struct rte_ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
extern struct rte_ether_hdr app_l2_hdr[VXLAN_N_PORTS];
extern uint8_t tx_checksum;
extern uint16_t tso_segsz;
struct vxlan_port {
uint32_t vport_id; /**< VirtIO port id */
uint32_t peer_ip; /**< remote VTEP IP address */
struct rte_ether_addr peer_mac; /**< remote VTEP MAC address */
struct rte_ether_addr vport_mac; /**< VirtIO port MAC address */
} __rte_cache_aligned;
struct vxlan_conf {
uint16_t dst_port; /**< VXLAN UDP destination port */
uint32_t port_ip; /**< DPDK port IP address*/
uint32_t in_key; /**< VLAN ID */
uint32_t out_key; /**< VXLAN VNI */
struct vxlan_port port[VXLAN_N_PORTS]; /**< VXLAN configuration */
} __rte_cache_aligned;
extern struct vxlan_conf vxdev;
/* structure that caches offload info for the current packet */
union tunnel_offload_info {
uint64_t data;
struct {
uint64_t l2_len:7; /**< L2 (MAC) Header Length. */
uint64_t l3_len:9; /**< L3 (IP) Header Length. */
uint64_t l4_len:8; /**< L4 Header Length. */
uint64_t tso_segsz:16; /**< TCP TSO segment size */
uint64_t outer_l2_len:7; /**< outer L2 Header Length */
uint64_t outer_l3_len:16; /**< outer L3 Header Length */
};
} __rte_cache_aligned;
int decapsulation(struct rte_mbuf *pkt);
void encapsulation(struct rte_mbuf *m, uint8_t queue_id);
#endif /* _VXLAN_H_ */

View File

@ -1,443 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2015 Intel Corporation
*/
#include <getopt.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/virtio_net.h>
#include <linux/virtio_ring.h>
#include <sys/param.h>
#include <unistd.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_vhost.h"
#include "vxlan.h"
#include "vxlan_setup.h"
#define IPV4_HEADER_LEN 20
#define UDP_HEADER_LEN 8
#define VXLAN_HEADER_LEN 8
#define IP_DEFTTL 64 /* from RFC 1340. */
#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
/* Default inner VLAN ID */
#define INNER_VLAN_ID 100
/* VXLAN device */
struct vxlan_conf vxdev;
struct rte_ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
struct rte_ether_hdr app_l2_hdr[VXLAN_N_PORTS];
/* local VTEP IP address */
uint8_t vxlan_multicast_ips[2][4] = { {239, 1, 1, 1 }, {239, 1, 2, 1 } };
/* Remote VTEP IP address */
uint8_t vxlan_overlay_ips[2][4] = { {192, 168, 10, 1}, {192, 168, 30, 1} };
/* Remote VTEP MAC address */
uint8_t peer_mac[6] = {0x00, 0x11, 0x01, 0x00, 0x00, 0x01};
/* VXLAN RX filter type */
uint8_t tep_filter_type[] = {RTE_TUNNEL_FILTER_IMAC_TENID,
RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID,
RTE_TUNNEL_FILTER_OMAC_TENID_IMAC,};
/* Options for configuring ethernet port */
static struct rte_eth_conf port_conf = {
.rxmode = {
.split_hdr_size = 0,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
.offloads = (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM |
DEV_TX_OFFLOAD_SCTP_CKSUM |
DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
DEV_TX_OFFLOAD_TCP_TSO |
DEV_TX_OFFLOAD_MULTI_SEGS |
DEV_TX_OFFLOAD_VXLAN_TNL_TSO),
},
};
/**
* The one or two device(s) that belongs to the same tenant ID can
* be assigned in a VM.
*/
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,
};
/**
* Initialises a given port using global settings and with the rx buffers
* coming from the mbuf_pool passed as parameter
*/
int
vxlan_port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
int retval;
uint16_t q;
struct rte_eth_dev_info dev_info;
uint16_t rx_rings, tx_rings = (uint16_t)rte_lcore_count();
uint16_t rx_ring_size = RTE_TEST_RX_DESC_DEFAULT;
uint16_t tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;
struct rte_eth_udp_tunnel tunnel_udp;
struct rte_eth_rxconf *rxconf;
struct rte_eth_txconf *txconf;
struct vxlan_conf *pconf = &vxdev;
struct rte_eth_conf local_port_conf = port_conf;
pconf->dst_port = udp_port;
retval = rte_eth_dev_info_get(port, &dev_info);
if (retval != 0)
rte_exit(EXIT_FAILURE,
"Error during getting device (port %u) info: %s\n",
port, strerror(-retval));
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;
if (!rte_eth_dev_is_valid_port(port))
return -1;
rx_rings = nb_devices;
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
local_port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
/* Configure ethernet device. */
retval = rte_eth_dev_configure(port, rx_rings, tx_rings,
&local_port_conf);
if (retval != 0)
return retval;
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &rx_ring_size,
&tx_ring_size);
if (retval != 0)
return retval;
/* Setup the queues. */
rxconf->offloads = local_port_conf.rxmode.offloads;
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;
}
txconf->offloads = local_port_conf.txmode.offloads;
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;
/* Configure UDP port for UDP tunneling */
tunnel_udp.udp_port = udp_port;
tunnel_udp.prot_type = RTE_TUNNEL_TYPE_VXLAN;
retval = rte_eth_dev_udp_tunnel_port_add(port, &tunnel_udp);
if (retval < 0)
return retval;
retval = rte_eth_macaddr_get(port, &ports_eth_addr[port]);
if (retval < 0)
return retval;
RTE_LOG(INFO, PORT, "Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
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]);
if (tso_segsz != 0) {
if ((dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO) == 0)
RTE_LOG(WARNING, PORT,
"hardware TSO offload is not supported\n");
}
return 0;
}
static int
vxlan_rx_process(struct rte_mbuf *pkt)
{
int ret = 0;
if (rx_decap)
ret = decapsulation(pkt);
return ret;
}
static void
vxlan_tx_process(uint8_t queue_id, struct rte_mbuf *pkt)
{
if (tx_encap)
encapsulation(pkt, queue_id);
return;
}
/*
* This function learns the MAC address of the device and set init
* L2 header and L3 header info.
*/
int
vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m)
{
int i, ret;
struct rte_ether_hdr *pkt_hdr;
uint64_t portid = vdev->vid;
struct rte_ipv4_hdr *ip;
struct rte_eth_tunnel_filter_conf tunnel_filter_conf;
if (unlikely(portid >= VXLAN_N_PORTS)) {
RTE_LOG(INFO, VHOST_DATA,
"(%d) WARNING: Not configuring device,"
"as already have %d ports for VXLAN.",
vdev->vid, VXLAN_N_PORTS);
return -1;
}
/* Learn MAC address of guest device from packet */
pkt_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
if (rte_is_same_ether_addr(&(pkt_hdr->s_addr), &vdev->mac_address)) {
RTE_LOG(INFO, VHOST_DATA,
"(%d) WARNING: This device is using an existing"
" MAC address and has not been registered.\n",
vdev->vid);
return -1;
}
for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) {
vdev->mac_address.addr_bytes[i] =
vxdev.port[portid].vport_mac.addr_bytes[i] =
pkt_hdr->s_addr.addr_bytes[i];
vxdev.port[portid].peer_mac.addr_bytes[i] = peer_mac[i];
}
memset(&tunnel_filter_conf, 0,
sizeof(struct rte_eth_tunnel_filter_conf));
rte_ether_addr_copy(&ports_eth_addr[0], &tunnel_filter_conf.outer_mac);
tunnel_filter_conf.filter_type = tep_filter_type[filter_idx];
/* inner MAC */
rte_ether_addr_copy(&vdev->mac_address, &tunnel_filter_conf.inner_mac);
tunnel_filter_conf.queue_id = vdev->rx_q;
tunnel_filter_conf.tenant_id = tenant_id_conf[vdev->rx_q];
if (tep_filter_type[filter_idx] == RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID)
tunnel_filter_conf.inner_vlan = INNER_VLAN_ID;
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,
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].vport_id = portid;
for (i = 0; i < 4; i++) {
/* Local VTEP IP */
vxdev.port_ip |= vxlan_multicast_ips[portid][i] << (8 * i);
/* Remote VTEP IP */
vxdev.port[portid].peer_ip |=
vxlan_overlay_ips[portid][i] << (8 * i);
}
vxdev.out_key = tenant_id_conf[vdev->rx_q];
rte_ether_addr_copy(&vxdev.port[portid].peer_mac,
&app_l2_hdr[portid].d_addr);
rte_ether_addr_copy(&ports_eth_addr[0],
&app_l2_hdr[portid].s_addr);
app_l2_hdr[portid].ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
ip = &app_ip_hdr[portid];
ip->version_ihl = RTE_IPV4_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.port_ip;
ip->dst_addr = vxdev.port[portid].peer_ip;
/* 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)
{
unsigned i = 0, rx_count;
int ret;
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));
rte_ether_addr_copy(&ports_eth_addr[0],
&tunnel_filter_conf.outer_mac);
rte_ether_addr_copy(&vdev->mac_address,
&tunnel_filter_conf.inner_mac);
tunnel_filter_conf.tenant_id = tenant_id_conf[vdev->rx_q];
tunnel_filter_conf.filter_type = tep_filter_type[filter_idx];
if (tep_filter_type[filter_idx] ==
RTE_TUNNEL_FILTER_IMAC_IVLAN_TENID)
tunnel_filter_conf.inner_vlan = INNER_VLAN_ID;
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 < RTE_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) {
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(uint16_t port_id, uint16_t queue_id,
struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
int ret = 0;
uint16_t i;
for (i = 0; i < nb_pkts; i++)
vxlan_tx_process(queue_id, 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(int vid, struct rte_mbuf **pkts_burst, uint32_t rx_count)
{
uint32_t i = 0;
uint32_t count = 0;
int ret;
struct rte_mbuf *pkts_valid[rx_count];
for (i = 0; i < rx_count; i++) {
if (enable_stats) {
rte_atomic64_add(
&dev_statistics[vid].rx_bad_ip_csum,
(pkts_burst[i]->ol_flags & PKT_RX_IP_CKSUM_BAD)
!= 0);
rte_atomic64_add(
&dev_statistics[vid].rx_bad_ip_csum,
(pkts_burst[i]->ol_flags & PKT_RX_L4_CKSUM_BAD)
!= 0);
}
ret = vxlan_rx_process(pkts_burst[i]);
if (unlikely(ret < 0))
continue;
pkts_valid[count] = pkts_burst[i];
count++;
}
ret = rte_vhost_enqueue_burst(vid, VIRTIO_RXQ, pkts_valid, count);
return ret;
}

View File

@ -1,58 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(c) 2010-2015 Intel Corporation
*/
#ifndef VXLAN_SETUP_H_
#define VXLAN_SETUP_H_
extern uint16_t nb_devices;
extern uint16_t udp_port;
extern uint8_t filter_idx;
extern uint16_t ports[RTE_MAX_ETHPORTS];
extern struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
extern uint32_t enable_stats;
extern struct device_statistics dev_statistics[MAX_DEVICES];
extern uint8_t rx_decap;
extern uint8_t tx_encap;
typedef int (*ol_port_configure_t)(uint16_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)(uint16_t port_id, uint16_t queue_id,
struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
typedef int (*ol_rx_handle_t)(int vid, struct rte_mbuf **pkts,
uint32_t count);
typedef int (*ol_param_handle)(int vid);
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(uint16_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(uint16_t port_id, uint16_t queue_id,
struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
int
vxlan_rx_pkts(int vid, struct rte_mbuf **pkts, uint32_t count);
#endif /* VXLAN_SETUP_H_ */