将DPDK的helloworld和skeleton例子组合起来可以得到一个基本转发程序,整个程序只有100多行,包含了最基本的转发(从一个网卡收包,从另一个网卡发包)
执行./basicfwd -c 3 -n 2启动程序,1个MASTER lcore和1个SLAVE lcore分别绑定到CPU0和CPU1,SLAVE lcore使用1个RX/TX队列收发包
pktegn-dpdk得到的测试结果(单核达到10G网卡线速14.8Mpps):
basicfwd.c
#include <stdint.h>
#include <inttypes.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#define NUM_RX_RING 7
#define NUM_TX_RING 7
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
static struct rte_eth_conf port_conf_default = {
.rxmode = {
.max_rx_pkt_len = ETHER_MAX_LEN
},
};
static int port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
int ret;
uint16_t rx_rings = NUM_RX_RING;
uint16_t tx_rings = NUM_TX_RING;
struct rte_eth_conf port_conf = port_conf_default;
uint16_t q;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
/* 配置网卡 */
ret = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (ret != 0) {
return ret;
}
/* 分配并设置RX队列 */
for (q = 0; q < rx_rings; ++q) {
ret = rte_eth_rx_queue_setup(port, q, nb_rxd, rte_eth_dev_socket_id(port), 0, mbuf_pool);
if (ret < 0) {
return ret;
}
}
/* 分配并设置TX队列 */
for (q = 0; q < tx_rings; ++q) {
ret = rte_eth_tx_queue_setup(port, q, nb_txd, rte_eth_dev_socket_id(port), 0);
if (ret < 0) {
return ret;
}
}
/* 打开网卡 */
ret = rte_eth_dev_start(port);
if (ret < 0) {
return ret;
}
/* 打开混杂模式 */
rte_eth_promiscuous_enable(port);
return 0;
}
static int basicfwd(void *lcore)
{
uint16_t port;
uint16_t q = *lcore - 1;
for (;;) {
RTE_ETH_FOREACH_DEV(port) {
struct rte_mbuf *bufs[BURST_SIZE];
/* 收包 */
uint16_t nb_rx = rte_eth_rx_burst(port, q, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0)) {
continue;
}
/* 发包 */
uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, q, bufs, nb_rx);
if (unlikely(nb_tx < nb_rx)) {
uint16_t buf;
for (buf = nb_tx; buf < nb_rx; ++buf) {
rte_pktmbuf_free(bufs[buf]);
}
}
}
}
return 0;
}
int main(int argc, char *argv[])
{
unsigned nb_ports;
struct rte_mempool *mbuf_pool;
uint16_t port;
unsigned lcore;
/* 初始化环境 */
if (rte_eal_init(argc, argv) < 0) {
return -1;
}
/* 得到网卡数 */
nb_ports = rte_eth_dev_count_avail();
if (nb_ports < 2 || nb_ports & 1) {
return -1;
}
/* 创建内存池 */
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (!mbuf_pool) {
return -1;
}
/* 初始化网卡 */
RTE_ETH_FOREACH_DEV(port) {
if (port_init(port, mbuf_pool) != 0) {
return -1;
}
}
/* 通知各个SLAVE lcore执行basicfwd() */
RTE_LCORE_FOREACH_SLAVE(lcore) {
rte_eal_remote_launch(basicfwd, &lcore, lcore);
}
rte_eal_mp_wait_lcore();
return 0;
}