#include <rte_virtio_net.h>
#include "main.h"
+#include "vxlan.h"
+#include "vxlan_setup.h"
/* the maximum number of external ports supported */
#define MAX_SUP_PORTS 1
#define MAC_ADDR_CMP 0xFFFFFFFFFFFFULL
#define CMD_LINE_OPT_NB_DEVICES "nb-devices"
+#define CMD_LINE_OPT_UDP_PORT "udp-port"
+#define CMD_LINE_OPT_TX_CHECKSUM "tx-checksum"
+#define CMD_LINE_OPT_TSO_SEGSZ "tso-segsz"
+#define CMD_LINE_OPT_FILTER_TYPE "filter-type"
+#define CMD_LINE_OPT_ENCAP "encap"
+#define CMD_LINE_OPT_DECAP "decap"
#define CMD_LINE_OPT_RX_RETRY "rx-retry"
#define CMD_LINE_OPT_RX_RETRY_DELAY "rx-retry-delay"
#define CMD_LINE_OPT_RX_RETRY_NUM "rx-retry-num"
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
uint32_t buf_size;
} vpool_array[MAX_QUEUES+MAX_QUEUES];
+/* UDP tunneling port */
+uint16_t udp_port = 4789;
+
+/* enable/disable inner TX checksum */
+uint8_t tx_checksum = 0;
+
+/* TCP segment size */
+uint16_t tso_segsz = 0;
+
+/* enable/disable decapsulation */
+uint8_t rx_decap = 1;
+
+/* enable/disable encapsulation */
+uint8_t tx_encap = 1;
+
+/* RX filter type for tunneling packet */
+uint8_t filter_idx = 1;
+
+/* 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. */
tep_termination_usage(const char *prgname)
{
RTE_LOG(INFO, VHOST_CONFIG, "%s [EAL options] -- -p PORTMASK\n"
+ " --udp-port: UDP destination port for VXLAN packet\n"
" --nb-devices[1-64]: The number of virtIO device\n"
+ " --tx-checksum [0|1]: inner Tx checksum offload\n"
+ " --tso-segsz [0-N]: TCP segment size\n"
+ " --decap [0|1]: tunneling packet decapsulation\n"
+ " --encap [0|1]: tunneling packet encapsulation\n"
+ " --filter-type[1-3]: filter type for tunneling packet\n"
+ " 1: Inner MAC and tenent ID\n"
+ " 2: Inner MAC and VLAN, and tenent ID\n"
+ " 3: Outer MAC, Inner MAC and tenent ID\n"
" -p PORTMASK: Set mask for ports to be used by application\n"
" --rx-retry [0|1]: disable/enable(default) retries on rx."
" Enable retry if destintation queue is full\n"
const char *prgname = argv[0];
static struct option long_option[] = {
{CMD_LINE_OPT_NB_DEVICES, required_argument, NULL, 0},
+ {CMD_LINE_OPT_UDP_PORT, required_argument, NULL, 0},
+ {CMD_LINE_OPT_TX_CHECKSUM, required_argument, NULL, 0},
+ {CMD_LINE_OPT_TSO_SEGSZ, required_argument, NULL, 0},
+ {CMD_LINE_OPT_DECAP, required_argument, NULL, 0},
+ {CMD_LINE_OPT_ENCAP, required_argument, NULL, 0},
+ {CMD_LINE_OPT_FILTER_TYPE, required_argument, NULL, 0},
{CMD_LINE_OPT_RX_RETRY, required_argument, NULL, 0},
{CMD_LINE_OPT_RX_RETRY_DELAY, required_argument, NULL, 0},
{CMD_LINE_OPT_RX_RETRY_NUM, required_argument, NULL, 0},
"Invalid argument for rx-retry [0|1]\n");
tep_termination_usage(prgname);
return -1;
- } else {
+ } else
enable_retry = ret;
- }
+ }
+
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_TSO_SEGSZ,
+ sizeof(CMD_LINE_OPT_TSO_SEGSZ))) {
+ ret = parse_num_opt(optarg, INT16_MAX);
+ if (ret == -1) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for TCP segment size [0-N]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ tso_segsz = ret;
+ }
+
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_UDP_PORT,
+ sizeof(CMD_LINE_OPT_UDP_PORT))) {
+ ret = parse_num_opt(optarg, INT16_MAX);
+ if (ret == -1) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for UDP port [0-N]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ udp_port = ret;
}
/* Specify the retries delay time (in useconds) on RX.*/
"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. */
"Invalid argument for rx-retry-num [0-N]\n");
tep_termination_usage(prgname);
return -1;
- } else {
+ } else
burst_rx_retry_num = ret;
- }
+ }
+
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_TX_CHECKSUM,
+ sizeof(CMD_LINE_OPT_TX_CHECKSUM))) {
+ ret = parse_num_opt(optarg, 1);
+ if (ret == -1) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for tx-checksum [0|1]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ tx_checksum = ret;
+ }
+
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_FILTER_TYPE,
+ sizeof(CMD_LINE_OPT_FILTER_TYPE))) {
+ ret = parse_num_opt(optarg, 3);
+ if ((ret == -1) || (ret == 0)) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for filter type [1-3]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ filter_idx = ret - 1;
+ }
+
+ /* Enable/disable encapsulation on RX. */
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_DECAP,
+ sizeof(CMD_LINE_OPT_DECAP))) {
+ ret = parse_num_opt(optarg, 1);
+ if (ret == -1) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for decap [0|1]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ rx_decap = ret;
+ }
+
+ /* Enable/disable encapsulation on TX. */
+ if (!strncmp(long_option[option_index].name,
+ CMD_LINE_OPT_ENCAP,
+ sizeof(CMD_LINE_OPT_ENCAP))) {
+ ret = parse_num_opt(optarg, 1);
+ if (ret == -1) {
+ RTE_LOG(INFO, VHOST_CONFIG,
+ "Invalid argument for encap [0|1]\n");
+ tep_termination_usage(prgname);
+ return -1;
+ } else
+ tx_encap = ret;
}
/* Enable/disable stats. */
"Invalid argument for stats [0..N]\n");
tep_termination_usage(prgname);
return -1;
- } else {
+ } else
enable_stats = ret;
- }
}
/* Set character device basename. */
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.
*/
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]);
if (unlikely(vdev->remove)) {
dev_ll = dev_ll->next;
+ overlay_options.tunnel_destroy(vdev);
vdev->ready = DEVICE_SAFE_REMOVE;
continue;
}
}
}
+ 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,
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]);
}
{
struct virtio_net_data_ll *dev_ll;
uint64_t tx_dropped, rx_dropped;
- uint64_t tx, tx_total, rx, rx_total;
+ uint64_t tx, tx_total, rx, rx_total, rx_ip_csum, rx_l4_csum;
uint32_t device_fh;
const char clr[] = { 27, '[', '2', 'J', '\0' };
const char top_left[] = { 27, '[', '1', ';', '1', 'H', '\0' };
rx = rte_atomic64_read(
&dev_statistics[device_fh].rx_atomic);
rx_dropped = rx_total - rx;
+ rx_ip_csum = rte_atomic64_read(
+ &dev_statistics[device_fh].rx_bad_ip_csum);
+ rx_l4_csum = rte_atomic64_read(
+ &dev_statistics[device_fh].rx_bad_l4_csum);
printf("\nStatistics for device %"PRIu32" ----------"
"\nTX total: %"PRIu64""
"\nTX dropped: %"PRIu64""
"\nTX successful: %"PRIu64""
"\nRX total: %"PRIu64""
+ "\nRX bad IP csum: %"PRIu64""
+ "\nRX bad L4 csum: %"PRIu64""
"\nRX dropped: %"PRIu64""
"\nRX successful: %"PRIu64"",
device_fh,
tx_dropped,
tx,
rx_total,
+ rx_ip_csum,
+ rx_l4_csum,
rx_dropped,
rx);
uint8_t portid;
uint16_t queue_id;
static pthread_t tid;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
/* init EAL */
ret = rte_eal_init(argc, 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",
"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. */
memset(&dev_statistics, 0, sizeof(dev_statistics));
/* Enable stats if the user option is set. */
- if (enable_stats)
- pthread_create(&tid, NULL, (void *)print_stats, NULL);
+ if (enable_stats) {
+ ret = pthread_create(&tid, NULL, (void *)print_stats, NULL);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "Cannot create print-stats thread\n");
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "print-stats");
+ ret = pthread_setname_np(tid, thread_name);
+ if (ret != 0)
+ RTE_LOG(ERR, VHOST_CONFIG, "Cannot set print-stats name\n");
+ }
/* Launch all data cores. */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
rte_eal_remote_launch(switch_worker,
mbuf_pool, lcore_id);
}
-
rte_vhost_feature_disable(1ULL << VIRTIO_NET_F_MRG_RXBUF);
/* Register CUSE device to handle IOCTLs. */