examples/tep_term: implement VXLAN processing

Implement the VXLAN packet processing functions.

  - VXLAN port configuration

  - VXLAN tunnel setup

  - VXLAN tunnel destroying

  - VXLAN packet processing for Rx side

  - VXLAN packet processing for Tx side

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Signed-off-by: Thomas Long <thomas.long@intel.com>
This commit is contained in:
Jijiang Liu 2015-06-23 00:40:59 +08:00 committed by Thomas Monjalon
parent f0b85c9837
commit 4abe471ed6
7 changed files with 590 additions and 14 deletions

View File

@ -47,7 +47,7 @@ endif
APP = tep_termination
# all source are stored in SRCS-y
SRCS-y := main.c
SRCS-y := main.c vxlan_setup.c vxlan.c
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)

View File

@ -125,7 +125,7 @@ static uint32_t enabled_port_mask;
static uint32_t nb_switching_cores;
/* number of devices/queues to support*/
uint32_t nb_devices;
uint16_t nb_devices = 2;
/* max ring descriptor, ixgbe, i40e, e1000 all are 4096. */
#define MAX_RING_DESC 4096
@ -136,6 +136,16 @@ struct vpool {
uint32_t buf_size;
} vpool_array[MAX_QUEUES+MAX_QUEUES];
/* 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. */
uint32_t enable_stats = 0;
/* Enable retries on RX. */
@ -312,9 +322,8 @@ tep_termination_parse_args(int argc, char **argv)
"Invalid argument for rx-retry [0|1]\n");
tep_termination_usage(prgname);
return -1;
} else {
} else
enable_retry = ret;
}
}
/* Specify the retries delay time (in useconds) on RX.*/
@ -327,9 +336,8 @@ tep_termination_parse_args(int argc, char **argv)
"Invalid argument for rx-retry-delay [0-N]\n");
tep_termination_usage(prgname);
return -1;
} else {
} else
burst_rx_delay_time = ret;
}
}
/* Specify the retries number on RX. */
@ -342,9 +350,8 @@ tep_termination_parse_args(int argc, char **argv)
"Invalid argument for rx-retry-num [0-N]\n");
tep_termination_usage(prgname);
return -1;
} else {
} else
burst_rx_retry_num = ret;
}
}
/* Enable/disable stats. */
@ -357,9 +364,8 @@ tep_termination_parse_args(int argc, char **argv)
"Invalid argument for stats [0..N]\n");
tep_termination_usage(prgname);
return -1;
} else {
} else
enable_stats = ret;
}
}
/* Set character device basename. */
@ -459,6 +465,10 @@ virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m)
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, m_table,
(uint16_t)tx_q->len);
/* Free any buffers not handled by TX and update
* the port stats.
*/
@ -525,6 +535,10 @@ switch_worker(__rte_unused void *arg)
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]);
@ -559,6 +573,7 @@ switch_worker(__rte_unused void *arg)
if (unlikely(vdev->remove)) {
dev_ll = dev_ll->next;
overlay_options.tunnel_destroy(vdev);
vdev->ready = DEVICE_SAFE_REMOVE;
continue;
}
@ -584,6 +599,7 @@ switch_worker(__rte_unused void *arg)
}
}
ret_count = overlay_options.rx_handle(dev, pkts_burst, rx_count);
if (enable_stats) {
rte_atomic64_add(
&dev_statistics[dev->device_fh].rx_total_atomic,
@ -606,7 +622,8 @@ switch_worker(__rte_unused void *arg)
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)
rte_pktmbuf_free(pkts_burst[--tx_count]);
}
@ -1059,7 +1076,6 @@ main(int argc, char *argv[])
"but only %u port can be enabled\n", nb_ports,
MAX_SUP_PORTS);
}
/* Create the mbuf pool. */
mbuf_pool = rte_mempool_create(
"MBUF_POOL",
@ -1087,6 +1103,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. */
@ -1105,7 +1124,6 @@ main(int argc, char *argv[])
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. */

View File

@ -34,6 +34,8 @@
#ifndef _MAIN_H_
#define _MAIN_H_
#include <rte_ether.h>
#ifdef DEBUG
#define LOG_LEVEL RTE_LOG_DEBUG
#define LOG_DEBUG(log_type, fmt, args...) RTE_LOG(DEBUG, log_type, fmt, ##args)

View File

@ -0,0 +1,172 @@
/*-
* 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_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"
/**
* 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 ether_hdr *eth_hdr, union tunnel_offload_info *info,
uint8_t *l4_proto)
{
struct ipv4_hdr *ipv4_hdr;
struct ipv6_hdr *ipv6_hdr;
uint16_t ethertype;
info->outer_l2_len = sizeof(struct ether_hdr);
ethertype = rte_be_to_cpu_16(eth_hdr->ether_type);
if (ethertype == ETHER_TYPE_VLAN) {
struct vlan_hdr *vlan_hdr = (struct vlan_hdr *)(eth_hdr + 1);
info->outer_l2_len += sizeof(struct vlan_hdr);
ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
}
switch (ethertype) {
case ETHER_TYPE_IPv4:
ipv4_hdr = (struct ipv4_hdr *)
((char *)eth_hdr + info->outer_l2_len);
info->outer_l3_len = sizeof(struct ipv4_hdr);
*l4_proto = ipv4_hdr->next_proto_id;
break;
case ETHER_TYPE_IPv6:
ipv6_hdr = (struct ipv6_hdr *)
((char *)eth_hdr + info->outer_l2_len);
info->outer_l3_len = sizeof(struct ipv6_hdr);
*l4_proto = ipv6_hdr->proto;
break;
default:
info->outer_l3_len = 0;
*l4_proto = 0;
break;
}
}
int
decapsulation(struct rte_mbuf *pkt)
{
uint8_t l4_proto = 0;
uint16_t outer_header_len;
struct udp_hdr *udp_hdr;
union tunnel_offload_info info = { .data = 0 };
struct ether_hdr *phdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *);
parse_ethernet(phdr, &info, &l4_proto);
if (l4_proto != IPPROTO_UDP)
return -1;
udp_hdr = (struct 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(DEFAULT_VXLAN_PORT) &&
(pkt->ol_flags & (PKT_RX_TUNNEL_IPV4_HDR |
PKT_RX_TUNNEL_IPV6_HDR)) == 0)
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;
}
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;
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];
/* 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 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 = 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 udp_hdr)
+ sizeof(struct vxlan_hdr));
udp->dst_port = rte_cpu_to_be_16(vxdev.dst_port);
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;
}

View File

@ -34,6 +34,9 @@
#ifndef _VXLAN_H_
#define _VXLAN_H_
#include <rte_ether.h>
#include <rte_ip.h>
#define PORT_MIN 49152
#define PORT_MAX 65535
#define PORT_RANGE ((PORT_MAX - PORT_MIN) + 1)
@ -42,6 +45,9 @@
#define VXLAN_HF_VNI 0x08000000
#define DEFAULT_VXLAN_PORT 4789
extern struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
extern struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
struct vxlan_port {
uint32_t vport_id; /**< VirtIO port id */
uint32_t peer_ip; /**< remote VTEP IP address */
@ -57,4 +63,21 @@ struct vxlan_conf {
struct vxlan_port port[VXLAN_N_PORTS]; /**< VXLAN configuration */
} __rte_cache_aligned;
#endif /* _MAIN_H_ */
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 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

@ -0,0 +1,357 @@
/*-
* 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 <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_virtio_net.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_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
/* 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 */
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};
/* 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,
},
};
/**
* 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(uint8_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();
const uint16_t rx_ring_size = RTE_TEST_RX_DESC_DEFAULT;
const uint16_t tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;
struct rte_eth_rxconf *rxconf;
struct rte_eth_txconf *txconf;
rte_eth_dev_info_get(port, &dev_info);
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;
if (port >= rte_eth_dev_count())
return -1;
rx_rings = nb_devices;
/* 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)
{
return decapsulation(pkt);
}
static void
vxlan_tx_process(uint8_t queue_id, struct rte_mbuf *pkt)
{
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;
struct ether_hdr *pkt_hdr;
struct virtio_net *dev = vdev->dev;
uint64_t portid = dev->device_fh;
struct ipv4_hdr *ip;
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 *);
if (is_same_ether_addr(&(pkt_hdr->s_addr), &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;
}
for (i = 0; i < 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];
}
/* 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];
ether_addr_copy(&vxdev.port[portid].peer_mac,
&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_16(ETHER_TYPE_IPv4);
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.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;
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) {
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 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(struct virtio_net *dev, 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++) {
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, count);
return ret;
}

View File

@ -34,6 +34,10 @@
#ifndef VXLAN_SETUP_H_
#define VXLAN_SETUP_H_
extern uint16_t nb_devices;
extern uint8_t ports[RTE_MAX_ETHPORTS];
extern struct ether_addr ports_eth_addr[RTE_MAX_ETHPORTS];
typedef int (*ol_port_configure_t)(uint8_t port,
struct rte_mempool *mbuf_pool);