1
0
mirror of https://github.com/rtbrick/bngblaster.git synced 2024-05-06 15:54:57 +00:00

DPDK enhancements

This commit is contained in:
Christian Giese
2023-02-22 21:19:00 +00:00
parent 5d203a06ab
commit eb3bf588db
3 changed files with 141 additions and 69 deletions

View File

@@ -18,7 +18,7 @@ typedef struct bbl_interface_
uint32_t state_transitions; /* interface state transitions */
uint32_t ifindex; /* interface index */
uint32_t pcap_index; /* interface index for packet captures */
uint16_t portid; /* DPDK port identifier */
uint16_t port_id; /* DPDK port identifier */
bbl_link_config_s *config;

View File

@@ -22,12 +22,14 @@
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_debug.h>
#include <rte_version.h>
#include <rte_ethdev.h>
#include <rte_malloc.h>
#define NUM_MBUFS 4096
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define BURST_SIZE_RX 64
#define BURST_SIZE_TX 32
static struct rte_eth_conf port_conf = {
.rxmode = {
@@ -38,25 +40,77 @@ static struct rte_eth_conf port_conf = {
},
};
static bool
io_dpdk_dev_info(uint16_t portid, struct rte_eth_dev_info *dev_info)
static bbl_interface_s *
io_dpdk_get_interface_by_port_id(uint16_t port_id)
{
int ret = rte_eth_dev_info_get(portid, dev_info);
if(ret != 0) {
LOG(ERROR, "DPDK: Error during getting device (port %u) info: %s\n",
portid, strerror(-ret));
bbl_interface_s *interface;
CIRCLEQ_FOREACH(interface, &g_ctx->interface_qhead, interface_qnode) {
if(interface->port_id == port_id) {
return interface;
}
}
return NULL;
}
static bool
io_dpdk_link_status(uint16_t port_id)
{
struct rte_eth_link link = {0};
bbl_interface_s *interface;
interface = io_dpdk_get_interface_by_port_id(port_id);
if(!interface) return false; /* unlikely */
if(rte_eth_link_get_nowait(port_id, &link) == 0) {
if(link.link_status) {
interface->state = INTERFACE_UP;
LOG(DPDK, "DPDK: interface %s (%u) link up (speed %u Mbps %s)\n",
interface->name, port_id, (unsigned)link.link_speed,
(link.link_duplex == ETH_LINK_FULL_DUPLEX) ? ("full-duplex") : ("half-duplex"));
} else {
interface->state = INTERFACE_DOWN;
LOG(DPDK, "DPDK: interface %s (%u) link down\n",
interface->name, port_id);
}
} else {
return false;
}
return true;
}
static bool
io_dpdk_dev_info(uint16_t port_id, struct rte_eth_dev_info *dev_info)
{
int ret = rte_eth_dev_info_get(port_id, dev_info);
if(ret != 0) {
LOG(ERROR, "DPDK: Error during getting device (port %u) info: %s\n",
port_id, strerror(-ret));
return false;
}
return true;
}
int
io_dpdk_event_callback(uint16_t port_id, enum rte_eth_event_type type, void *cb_arg, void *ret_param)
{
RTE_SET_USED(cb_arg);
RTE_SET_USED(ret_param);
LOG(DPDK, "DPDK: %s event\n", type == RTE_ETH_EVENT_INTR_LSC ? "LSC interrupt" : "unknown");
io_dpdk_link_status(port_id);
return 0;
}
bool
io_dpdk_init()
{
uint16_t portid;
uint16_t port_id;
uint16_t dpdk_ports;
struct rte_eth_dev_info dev_info;
char fw_version[64];
struct rte_eth_dev_info dev_info;
if(!g_ctx->dpdk) {
return true;
@@ -70,16 +124,25 @@ io_dpdk_init()
LOG_NOARG(DPDK, "DPDK: init the EAL\n");
rte_eal_init(2, argv);
dpdk_ports = rte_eth_dev_count_avail();
LOG(DPDK, "DPDK: version %s\n", rte_version());
dpdk_ports = rte_eth_dev_count_avail();
LOG(DPDK, "DPDK: %u ports available\n", dpdk_ports);
RTE_ETH_FOREACH_DEV(portid) {
if(!io_dpdk_dev_info(portid, &dev_info)) {
RTE_ETH_FOREACH_DEV(port_id) {
if(!io_dpdk_dev_info(port_id, &dev_info)) {
LOG_NOARG(ERROR, "DPDK: failed to get device info\n");
return false;
}
LOG(DPDK, "DPDK: %s (port %u)\n",
dev_info.device->name, portid);
memset(fw_version, 0x0, sizeof(fw_version));
if(rte_eth_dev_fw_version_get(port_id, fw_version, sizeof(fw_version)) == 0) {
LOG(DPDK, "DPDK: interface %s (%u) driver %s firmware %s\n",
dev_info.device->name, port_id, dev_info.driver_name, fw_version);
} else {
LOG(DPDK, "DPDK: interface %s (%u) driver %s\n",
dev_info.device->name, port_id, dev_info.driver_name);
}
}
return true;
@@ -96,8 +159,8 @@ io_dpdk_rx_job(timer_s *timer)
bbl_ethernet_header_s *eth;
struct rte_mbuf *packet_burst[BURST_SIZE];
struct rte_mbuf *packet;
struct rte_mbuf *packet_burst[BURST_SIZE_RX];
struct rte_mbuf *packet;
uint16_t nb_rx;
uint16_t i;
@@ -113,12 +176,13 @@ io_dpdk_rx_job(timer_s *timer)
io->timestamp.tv_sec = timer->timestamp->tv_sec;
io->timestamp.tv_nsec = timer->timestamp->tv_nsec;
while(true) {
nb_rx = rte_eth_rx_burst(interface->portid, io->queue, packet_burst, BURST_SIZE);
nb_rx = rte_eth_rx_burst(interface->port_id, io->queue, packet_burst, BURST_SIZE_RX);
if(nb_rx == 0) {
break;
}
for(i = 0; i < nb_rx; i++) {
packet = packet_burst[i];
rte_prefetch0(rte_pktmbuf_mtod(packet, void *));
io->buf = rte_pktmbuf_mtod(packet, uint8_t *);
io->buf_len = packet->pkt_len;
io->stats.packets++;
@@ -227,7 +291,7 @@ io_dpdk_tx_job(timer_s *timer)
}
io->mbuf->data_len = io->buf_len;
/* Transmit the packet. */
if(rte_eth_tx_burst(interface->portid, io->queue, &io->mbuf, 1) == 0) {
if(rte_eth_tx_burst(interface->port_id, io->queue, &io->mbuf, 1) == 0) {
/* This packet will be retried next interval
* because io->buf_len is not reset to zero. */
if(pcap) {
@@ -258,10 +322,10 @@ io_dpdk_thread_rx_run_fn(io_thread_s *thread)
io_handle_s *io = thread->io;
bbl_interface_s *interface = io->interface;
struct rte_mbuf *pkts_burst[BURST_SIZE];
struct rte_mbuf *pkts_burst[BURST_SIZE_RX];
struct rte_mbuf *packet;
uint16_t portid = interface->portid;
uint16_t port_id = interface->port_id;
uint16_t nb_rx;
uint16_t i;
@@ -274,7 +338,7 @@ io_dpdk_thread_rx_run_fn(io_thread_s *thread)
sleep.tv_nsec = 0;
while(thread->active) {
nb_rx = rte_eth_rx_burst(portid, io->queue, pkts_burst, BURST_SIZE);
nb_rx = rte_eth_rx_burst(port_id, io->queue, pkts_burst, BURST_SIZE_RX);
if(nb_rx == 0) {
sleep.tv_nsec = 10;
nanosleep(&sleep, &rem);
@@ -284,6 +348,7 @@ io_dpdk_thread_rx_run_fn(io_thread_s *thread)
clock_gettime(CLOCK_MONOTONIC, &io->timestamp);
for(i = 0; i < nb_rx; i++) {
packet = pkts_burst[i];
rte_prefetch0(rte_pktmbuf_mtod(packet, void *));
io->buf = rte_pktmbuf_mtod(packet, uint8_t *);
io->buf_len = packet->pkt_len;
/* Process packet */
@@ -358,7 +423,7 @@ io_dpdk_thread_tx_job(timer_s *timer)
}
io->mbuf->data_len = io->buf_len;
/* Transmit the packet. */
if(rte_eth_tx_burst(interface->portid, io->queue, &io->mbuf, 1) == 0) {
if(rte_eth_tx_burst(interface->port_id, io->queue, &io->mbuf, 1) == 0) {
/* This packet will be retried next interval
* because io->buf_len is not reset to zero. */
return;
@@ -386,7 +451,7 @@ io_dpdk_add_mbuf_pool(io_handle_s *io)
mbuf_pool = rte_pktmbuf_pool_create(name,
NUM_MBUFS, MBUF_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE,
rte_eth_dev_socket_id(io->interface->portid));
rte_eth_dev_socket_id(io->interface->port_id));
if(!mbuf_pool) {
free(name);
return false;
@@ -403,7 +468,7 @@ io_dpdk_interface_init(bbl_interface_s *interface)
int ret;
bool found = false;
uint16_t portid;
uint16_t port_id;
uint16_t queue;
uint16_t id;
uint16_t nb_rx_queue = 1;
@@ -415,11 +480,11 @@ io_dpdk_interface_init(bbl_interface_s *interface)
struct rte_ether_addr mac;
io_handle_s *io;
RTE_ETH_FOREACH_DEV(portid) {
if(io_dpdk_dev_info(portid, &dev_info)) {
RTE_ETH_FOREACH_DEV(port_id) {
if(io_dpdk_dev_info(port_id, &dev_info)) {
if(strcmp(dev_info.device->name, interface->name) == 0) {
found = true;
interface->portid = portid;
interface->port_id = port_id;
break;
}
}
@@ -433,11 +498,13 @@ io_dpdk_interface_init(bbl_interface_s *interface)
if(*(uint32_t*)config->mac) {
memcpy(interface->mac, config->mac, ETH_ADDR_LEN);
} else {
if(rte_eth_macaddr_get(portid, &mac) < 0) {
LOG(ERROR, "DPDK: failed to get MAC from interface %s\n", interface->name);
if(rte_eth_macaddr_get(port_id, &mac) < 0) {
LOG(ERROR, "DPDK: interface %s (%u) failed to get MAC\n",
interface->name, port_id);
return false;
}
LOG(DPDK, "DPDK: Set MAC %s for interface %s\n", format_mac_address(mac.addr_bytes), interface->name);
LOG(DPDK, "DPDK: interface %s (%u) MAC address %s\n",
interface->name, port_id, format_mac_address(mac.addr_bytes));
memcpy(interface->mac, mac.addr_bytes, ETH_ADDR_LEN);
}
@@ -457,16 +524,24 @@ io_dpdk_interface_init(bbl_interface_s *interface)
(RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_UDP) &
dev_info.flow_type_rss_offloads;
ret = rte_eth_dev_configure(portid, nb_rx_queue, nb_tx_queue, &local_port_conf);
ret = rte_eth_dev_configure(port_id, nb_rx_queue, nb_tx_queue, &local_port_conf);
if(ret < 0) {
LOG(ERROR, "DPDK: failed to configure interface %s (error %d)\n",
interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to configure interface (error %d)\n",
interface->name, port_id, ret);
return false;
}
ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &config->io_slots_rx, &config->io_slots_tx);
ret = rte_eth_dev_adjust_nb_rx_tx_desc(port_id, &config->io_slots_rx, &config->io_slots_tx);
if(ret < 0) {
LOG(ERROR, "DPDK: failed to adjust number of descriptors for interface %s (error %d)\n",
interface->name, ret);
LOG(ERROR, "DPDK: %s (%u) failed to adjust number of rx/tx descriptors (error %d)\n",
interface->name, port_id, ret);
return false;
}
ret = rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC, (rte_eth_dev_cb_fn)io_dpdk_event_callback, NULL);
if(ret < 0) {
LOG(ERROR, "DPDK: interface %s (%u) failed to register callback (error %d)\n",
interface->name, port_id, ret);
return false;
}
@@ -492,19 +567,19 @@ io_dpdk_interface_init(bbl_interface_s *interface)
}
io->queue = queue;
if(!io_dpdk_add_mbuf_pool(io)) {
LOG(ERROR, "DPDK: failed to create RX mbuf pool for interface %s queue %u\n",
interface->name, queue);
LOG(ERROR, "DPDK: interface %s (%u) failed to create RX mbuf pool for queue %u\n",
interface->name, port_id, queue);
return false;
}
rx_conf = dev_info.default_rxconf;
rx_conf.offloads = local_port_conf.rxmode.offloads;
ret = rte_eth_rx_queue_setup(portid, queue, config->io_slots_rx,
rte_eth_dev_socket_id(portid),
ret = rte_eth_rx_queue_setup(port_id, queue, config->io_slots_rx,
rte_eth_dev_socket_id(port_id),
&rx_conf, io->mbuf_pool);
if(ret < 0) {
LOG(ERROR, "DPDK: failed to setup RX queue %u for interface %s (error %d)\n",
queue, interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to setup RX queue %u (error %d)\n",
interface->name, port_id, queue, ret);
return false;
}
}
@@ -536,62 +611,63 @@ io_dpdk_interface_init(bbl_interface_s *interface)
}
io->queue = queue;
if(!io_dpdk_add_mbuf_pool(io)) {
LOG(ERROR, "DPDK: failed to create TX mbuf pool for interface %s queue %u\n",
interface->name, queue);
LOG(ERROR, "DPDK: interface %s (%u) failed to create TX mbuf pool for queue %u\n",
interface->name, port_id, queue);
return false;
}
tx_conf = dev_info.default_txconf;
tx_conf.offloads = local_port_conf.txmode.offloads;
ret = rte_eth_tx_queue_setup(portid, queue, config->io_slots_tx,
rte_eth_dev_socket_id(portid),
ret = rte_eth_tx_queue_setup(port_id, queue, config->io_slots_tx,
rte_eth_dev_socket_id(port_id),
&tx_conf);
if(ret < 0) {
LOG(ERROR, "DPDK: failed to setup TX queue %u for interface %s (error %d)\n",
queue, interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to setup TX queue %u (error %d)\n",
interface->name, port_id, queue, ret);
return false;
}
/* Initialize TX buffers */
io->tx_buffer = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(BURST_SIZE), 0,
rte_eth_dev_socket_id(portid));
RTE_ETH_TX_BUFFER_SIZE(BURST_SIZE_TX), 0,
rte_eth_dev_socket_id(port_id));
if (!io->tx_buffer) {
LOG(ERROR, "DPDK: failed to allocate TX buffer for interface %s queue %u (error %d)\n",
interface->name, queue, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to allocate TX buffer for queue %u (error %d)\n",
interface->name, port_id, queue, ret);
return false;
}
rte_eth_tx_buffer_init(io->tx_buffer, BURST_SIZE);
rte_eth_tx_buffer_init(io->tx_buffer, BURST_SIZE_TX);
ret = rte_eth_tx_buffer_set_err_callback(io->tx_buffer,
rte_eth_tx_buffer_count_callback, &io->stats.dropped);
if(ret < 0) {
LOG(ERROR, "DPDK: failed to set TX error callback for interface %s queue %u (error %d)\n",
interface->name, queue, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to set TX error callback for queue %u (error %d)\n",
interface->name, port_id, queue, ret);
return false;
}
}
ret = rte_eth_dev_set_ptypes(portid, RTE_PTYPE_UNKNOWN, NULL, 0);
ret = rte_eth_dev_set_ptypes(port_id, RTE_PTYPE_UNKNOWN, NULL, 0);
if (ret < 0) {
LOG(ERROR, "DPDK: failed to disable ptype parsing for interface %s (error %d)\n",
interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to disable ptype parsing (error %d)\n",
interface->name, port_id, ret);
return false;
}
ret = rte_eth_dev_start(portid);
ret = rte_eth_dev_start(port_id);
if (ret < 0) {
LOG(ERROR, "DPDK: failed to start interface %s (error %d)\n",
interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to start device (error %d)\n",
interface->name, port_id, ret);
return false;
}
ret = rte_eth_promiscuous_enable(portid);
ret = rte_eth_promiscuous_enable(port_id);
if (ret < 0) {
LOG(ERROR, "DPDK: failed to enable promiscuous mode for interface %s (error %d)\n",
interface->name, ret);
LOG(ERROR, "DPDK: interface %s (%u) failed to enable promiscuous mode (error %d)\n",
interface->name, port_id, ret);
return false;
}
io_dpdk_link_status(port_id);
return true;
}

View File

@@ -9,10 +9,6 @@
#ifndef __BBL_IO_DPDK_H__
#define __BBL_IO_DPDK_H__
typedef struct io_dpdk_ctx_ {
uint16_t dev_count;
} io_dpdk_ctx_s;
bool
io_dpdk_init();