【DPDK学习路径】八、轮询

前面我们已经了解了如何使用DPDK创建线程并绑定核心,以及如何申请内存池并创建 RX/TX 队列。

接下来我们将了解DPDK的核心内容之一:以轮询的方式从网卡中收取报文。

下面直接给出一个实例,此实例使用核心1及核心2创建了两个线程用于报文处理,其中在核心1上运行的线程接收网卡0的消息,而在核心2上运行的线程接收网卡1的消息。在这里,从网卡上获取报文的方式为轮询,具体的接口为 rte_eth_rx_burst,而所谓的报文处理,就是简单地打印报文消息。

#include <arpa/inet.h>

#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>

#include<rte_errno.h>


#define NB_SOCKETS 10
#define MEMPOOL_CACHE_SIZE 250

static unsigned nb_mbuf = 512;
static int numa_on = 0;
static struct rte_mempool * pktmbuf_pool[NB_SOCKETS];

static int
init_mem(unsigned nb_mbuf){
	unsigned lcore_id;
	int socketid;
	char mbuf_pool_name[64];

	for(lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++){
		if (rte_lcore_is_enabled(lcore_id) == 0){
			continue;
		}

		if(numa_on){
			socketid = rte_lcore_to_socket_id(lcore_id);
		}
		else{
			socketid = 0;
		}

		if(socketid >= NB_SOCKETS){
			rte_exit(EXIT_FAILURE, "Socket %d of lcore %u is out of range %d\n",
				socketid, lcore_id, NB_SOCKETS);
		}

		if(pktmbuf_pool[socketid] == NULL){
			snprintf(mbuf_pool_name, sizeof(mbuf_pool_name), "mbuf_pool_%d", socketid);
			pktmbuf_pool[socketid] = rte_pktmbuf_pool_create(mbuf_pool_name, nb_mbuf,
				MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, socketid);
			if(pktmbuf_pool[socketid] == NULL){
				rte_exit(EXIT_FAILURE, "Cannot init mbuf pool on socket %d\n", socketid);
			}
			else{
				printf("Allocated mbuf pool on socket %d\n", socketid);
			}
		}
	}
	return 0;
}

#define MAX_RX_QUEUE_PER_PORT 1
#define MAX_TX_QUEUE_PER_PORT 1
#define RX_RING_SIZE 128
#define TX_RING_SIZE 512
#define BURST_SIZE 128

static const struct rte_eth_conf dev_conf_default = {
    .rxmode = {.max_rx_pkt_len = ETHER_MAX_LEN}
};


static void
init_port(void)
{
	int nb_port = 0;
	int portid = 0;
	int ret = 0;

	nb_port = rte_eth_dev_count_avail();
	if(!nb_port){
        rte_exit(EXIT_FAILURE, "No support eth found\n");
    }
    printf("nb_port = %d\n", nb_port);

	for(portid=0;portid < nb_port;portid++){

		ret = rte_eth_dev_configure(portid, MAX_RX_QUEUE_PER_PORT, MAX_TX_QUEUE_PER_PORT, &dev_conf_default);
		if (ret < 0) {
       		rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", ret, portid);
    	}

		ret = rte_eth_rx_queue_setup(portid, 0, RX_RING_SIZE, rte_eth_dev_socket_id(portid), NULL, pktmbuf_pool[0]);
    	if (ret < 0) {
       		rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", ret, portid);
    	}

		ret = rte_eth_tx_queue_setup(portid, 0, TX_RING_SIZE, rte_eth_dev_socket_id(portid), NULL);
    	if (ret < 0) {
       		rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", ret, portid);
    	}

		ret = rte_eth_dev_start(portid);
    	if (ret < 0) {
       		rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", ret, portid);
    	}

    	rte_eth_promiscuous_enable(portid);
	}
}

static void
pkt_process(struct rte_mbuf *mbuf){
	struct ether_hdr *eth = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
	if(eth->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)){
		struct ipv4_hdr *iphdr = rte_pktmbuf_mtod_offset(mbuf, struct ipv4_hdr *,sizeof(struct ether_hdr));
        //udp
        if(iphdr->next_proto_id == IPPROTO_UDP){
            struct udp_hdr *udphdr = (struct udp_hdr *)(iphdr + 1);
            uint16_t length = ntohs(udphdr->dgram_len);
            *(char*)(udphdr + length) = '\0';//这个操作有必要吗?
            struct in_addr addr;
            addr.s_addr = iphdr->src_addr;
            printf("src:%s:%d,",inet_ntoa(addr),ntohs(udphdr->src_port));
            addr.s_addr = iphdr->dst_addr;
            printf("dst:%s:%d, %s\n",inet_ntoa(addr),ntohs(udphdr->dst_port),(char*)(udphdr + 1));
       	}
	}
	rte_pktmbuf_free(mbuf);
}

static int
main_loop(__attribute__((unused)) void *dummy)
{
	struct rte_mbuf *mbufs[BURST_SIZE];
	int num_recvd = 0;
	unsigned target_lcore_id_1 = 1;
	unsigned target_lcore_id_2 = 2;
	int portid = 0;
	unsigned lcore_id = rte_lcore_id();
	int i;
	if(lcore_id != target_lcore_id_1 && lcore_id != target_lcore_id_2){
        return 0;
    }

	//核1接收port0的消息
	//核2接收port1的消息
	if(lcore_id == target_lcore_id_1){
		portid = 0;
	}
	else if(lcore_id == target_lcore_id_2){
		portid = 1;
	}
	else{
		return 0;
	}

	while(1){
		num_recvd = rte_eth_rx_burst(portid, 0, mbufs, BURST_SIZE);
		if(num_recvd > BURST_SIZE){
            rte_exit(EXIT_FAILURE, "rte_eth_rx_burst failed\n");
        }
		for(i = 0; i < num_recvd; i++){
			pkt_process(mbufs[i]);
		}
    }

	return 0;
}


int main(int argc, char *argv[]) {
	unsigned lcore_id;
	// init eal
	if(rte_eal_init(argc, argv) < 0){
        rte_exit(EXIT_FAILURE, "Error with eal init\n");
    }

	// alloc memory
	init_mem(nb_mbuf);

	// create tx queue and rx queue
	init_port();

	// main_loop
	rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);
	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
        if (rte_eal_wait_lcore(lcore_id) < 0){
            return -1;
        }
    }

	// free
	for(int i = 0; i < NB_SOCKETS; i++){
		rte_mempool_free(pktmbuf_pool[i]);
	}
	
	return 0;
}
相关推荐
flysnow01025 天前
WSL(Ubuntu20.04)编译和安装DPDK
dpdk·1024程序员节
彭泽布衣2 个月前
解读: 火山引擎自研vSwitch技术
dpdk·火山引擎·ovs·云网络·vswitch
别NULL2 个月前
DPDK 简易应用开发之路 2:UDP数据包发送及实现
linux·网络·网络协议·udp·dpdk
别NULL2 个月前
DPDK基础入门(十):虚拟化
linux·网络·tcp/ip·dpdk
Once_day4 个月前
DPDK源码分析之(1)libmbuf模块补充
dpdk
墨染 锦年5 个月前
DPDK概述
笔记·学习·dpdk·uio·igb-uio
大1234草6 个月前
dpdk flow 的简单使用
dpdk
写一封情书6 个月前
tldk之tle简单记录
dpdk·tldk·tle
范桂飓6 个月前
Intel HDSLB 高性能四层负载均衡器 — 基本原理和部署配置
运维·负载均衡·dpdk