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:
parent
eda44ced0e
commit
079981e980
@ -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
|
||||
|
@ -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 |
@ -51,7 +51,6 @@ Sample Applications User Guides
|
||||
eventdev_pipeline
|
||||
dist_app
|
||||
vm_power_management
|
||||
tep_termination
|
||||
ptpclient
|
||||
performance_thread
|
||||
fips_validation
|
||||
|
@ -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.
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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
@ -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_ */
|
@ -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'
|
||||
)
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
@ -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_ */
|
Loading…
Reference in New Issue
Block a user