最简单的dpdk udp程序

 

记录一下测试dpdk udp收发的程序,程序很简单,从网卡收到ipv4 udp包后,将udp包回传给源

  1. export 两个dpdk环境变量
    export RTE_SDK=/root/dpdk-19.11
    export RTE_TARGET=x86_64-native-linuxapp-gcc
  2. 设置好环境(安装驱动/大页/配置端口)
    可参考dpdk个人学习使用全过程_地上一个猴的博客-CSDN博客_dpdk教程
  3. 参考其他示例的makefile,写一个                                                  
  4. 写代码(send.c),编译
    #include <stdio.h>
    #include <arpa/inet.h>
    #include <rte_eal.h>
    #include <rte_ethdev.h>
    #include <rte_mbuf.h>
    
    #define NUM_MBUFS		(4096-1)
    #define MBUFS_SIZE		32
    #define ENABLE_SEND		1
    
    uint16_t port_id = 0;
    
    
    
    #if ENABLE_SEND
    
    static uint32_t gSrcIp; 
    static uint32_t gDstIp;
    
    static uint8_t gSrcMac[RTE_ETHER_ADDR_LEN];
    static uint8_t gDstMac[RTE_ETHER_ADDR_LEN];
    
    static uint16_t gSrcPort;
    static uint16_t gDstPort;
    
    #endif
    
    
    
    static const struct rte_eth_conf port_conf_default = {
    	.rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN }
    };
    
    static void init_port(struct rte_mempool *mbufpool)
    {
    	/*Get the number of ports which are usable for the application.*/
    	uint16_t sys_port = rte_eth_dev_count_avail();
    	if(sys_port == 0){
    		rte_exit(EXIT_FAILURE, "Not available eth\n");
    	}
    
    	/*Get ethernet information*/
    	struct rte_eth_dev_info dev_info;
    	rte_eth_dev_info_get(port_id, &dev_info);
    
    	/*Configure an Ethernet device*/
    	uint16_t nb_rx_q = 1;
    	uint16_t nb_tx_q = 1;
    	struct rte_eth_conf dev_conf = port_conf_default;
    	rte_eth_dev_configure(port_id, nb_rx_q, nb_tx_q, &dev_conf);
    
    	/*Allocate and set up a receive queue for an Ethernet device*/
    	uint16_t rx_queue_id = nb_rx_q - 1;
    	unsigned int socket_id = rte_eth_dev_socket_id(port_id);
    	if(rte_eth_rx_queue_setup(port_id, rx_queue_id, 1024, socket_id, NULL, mbufpool) < 0)
    		rte_exit(EXIT_FAILURE, "Receive queue error\n");
    		
    #if ENABLE_SEND
    	/*Allocate and set up a transmit queue for an Ethernet device*/
    	struct rte_eth_txconf txq_conf = dev_info.default_txconf;
    	txq_conf.offloads = dev_conf.rxmode.offloads;
    	if (rte_eth_tx_queue_setup(port_id, 0 , 1024, socket_id, &txq_conf) < 0)
    		rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");
    
    #endif
    
    	/*Start an Ethernet device*/
    	if(rte_eth_dev_start(port_id) < 0)
    		rte_exit(EXIT_FAILURE, "Start ethernet error\n");
    
    }
    
    
    
    int main(int argc, char **argv)
    {
        unsigned int i =0;
        //uint8_t   au8SendMsg[] = "hello misss";
        
    	/*init*/
    	if(rte_eal_init(argc, argv) < 0)
    		rte_exit(EXIT_FAILURE, "EAL init Error\n");
    
    	/*create a mbuf pool*/
    	struct rte_mempool *mbufpool = rte_pktmbuf_pool_create("mbufpool", NUM_MBUFS, 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
    	if(mbufpool == NULL)
    		rte_exit(EXIT_FAILURE, "Create mbufpool Error\n");
    
    	/*init port*/
    	init_port(mbufpool);
    
    
        rte_eth_macaddr_get(port_id, (struct rte_ether_addr *)gSrcMac);
    
    	while(1){
    		struct rte_mbuf *rx_pkts[MBUFS_SIZE];
    		/*Retrieve a burst of input packets from a receive queue of an Ethernet device*/
    		unsigned num_recv = rte_eth_rx_burst(port_id, 0, rx_pkts, MBUFS_SIZE);
    		if(num_recv > MBUFS_SIZE)
    			rte_exit(EXIT_FAILURE, "Receive from eth error\n");
    
    		for(i = 0; i < num_recv; i++){
                
    			struct rte_ether_hdr *ehdr  = rte_pktmbuf_mtod(rx_pkts[i], struct rte_ether_hdr*);
    			if (ehdr->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
    				rte_pktmbuf_free(rx_pkts[i]);
    				continue;
    			}
    			
    			struct rte_ipv4_hdr *iphdr =  rte_pktmbuf_mtod_offset(rx_pkts[i], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
    			if (iphdr->next_proto_id == IPPROTO_UDP) {
    				/*IPPROTO_UDP is defined in kernel source code include/uapi/inux/in.h*/
    
    				struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(iphdr + 1);
    
    #if ENABLE_SEND
    
    				//rte_eth_macaddr_get(port_id, (struct rte_ether_addr *)gSrcMac);
    				rte_memcpy(gDstMac, ehdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
    								
    				rte_memcpy(&gSrcIp, &iphdr->dst_addr, sizeof(uint32_t));
    				rte_memcpy(&gDstIp, &iphdr->src_addr, sizeof(uint32_t));
                    
    				rte_memcpy(&gSrcPort, &udphdr->dst_port, sizeof(uint16_t));
    				rte_memcpy(&gDstPort, &udphdr->src_port, sizeof(uint16_t));
    			
    #endif
    
    				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), udphdr->src_port);
    				addr.s_addr = iphdr->dst_addr;
    				printf("dst: %s:%d, %s\n", inet_ntoa(addr), udphdr->dst_port, (char *)(udphdr+1));
    				
    #if ENABLE_SEND
                    //20220926add
                    rte_memcpy(&iphdr->src_addr, &gSrcIp, sizeof(uint32_t));
                    rte_memcpy(&iphdr->dst_addr, &gDstIp, sizeof(uint32_t));
                    addr.s_addr = iphdr->src_addr;
    				printf("-> src: %s:%d, ", inet_ntoa(addr), udphdr->src_port);
    				addr.s_addr = iphdr->dst_addr;
    				printf("dst: %s:%d, %s\n", inet_ntoa(addr), udphdr->dst_port, (char *)(udphdr+1));
    
                    rte_memcpy(ehdr->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
                    rte_memcpy(ehdr->d_addr.addr_bytes, gDstMac, RTE_ETHER_ADDR_LEN);
                    
    				//调测增加,实际使用可去掉端口限制
                    if (4369 == udphdr->src_port)
                    {
        				rte_eth_tx_burst(port_id , 0, rx_pkts, num_recv);
      								
                    }
    #endif
    				rte_pktmbuf_free(rx_pkts[i]);
    			}
    		}
    	}
    }
    
    

     

  5. Windows本地添加静态地址
    运行管理员cmd,其中ip地址为自定义,不与局域网冲突即可,mac地址必须正确,是配置给dpdk的网卡地址。
    netsh -c i i add neighbors 12  "10.180.147.55" "00-0c-29-88-c1-9a"
  6. 打开网络调试助手网络调试助手下载_网络调试助手绿色版免费下载-华军软件园
    填写正确的本地ip,连接后填写刚才添加的目标主机地址
  7. windows发送消息到dpdk,udp将消息传回windows

 

 文章参考:[4].dpdk实现udp协议发送数据_u.意思的博客-CSDN博客_dpdk udp

 

         

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用C++编程语言编写DPDK应用程序与使用C语言类似,只是在代码的组织和语法上有一些差异。下面是一个简单的示例,展示了如何使用C++编写一个DPDK应用程序来接收和处理数据包: ```cpp #include <iostream> #include <rte_eal.h> #include <rte_ethdev.h> #include <rte_mbuf.h> #define RX_RING_SIZE 128 #define NUM_MBUFS 8191 #define MBUF_CACHE_SIZE 250 #define BURST_SIZE 32 int main(int argc, char *argv[]) { int ret; // 初始化DPDK环境 ret = rte_eal_init(argc, argv); if (ret < 0) { rte_exit(EXIT_FAILURE, "Failed to initialize DPDK environment\n"); } // 获取可用的网卡数量 int num_ports = rte_eth_dev_count_avail(); if (num_ports == 0) { rte_exit(EXIT_FAILURE, "No available Ethernet ports\n"); } // 配置第一个网卡 ret = rte_eth_dev_configure(0, 1, 1, NULL); if (ret < 0) { rte_exit(EXIT_FAILURE, "Failed to configure Ethernet port\n"); } // 分配和初始化内存池 struct rte_mempool *mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); if (mbuf_pool == NULL) { rte_exit(EXIT_FAILURE, "Failed to create memory pool\n"); } // 启动第一个网卡 ret = rte_eth_dev_start(0); if (ret < 0) { rte_exit(EXIT_FAILURE, "Failed to start Ethernet port\n"); } // 设置接收队列 ret = rte_eth_rx_queue_setup(0, 0, RX_RING_SIZE, rte_eth_dev_socket_id(0), NULL, mbuf_pool); if (ret < 0) { rte_exit(EXIT_FAILURE, "Failed to setup RX queue\n"); } // 接收和处理数据包 while (true) { struct rte_mbuf *bufs[BURST_SIZE]; const uint16_t nb_rx = rte_eth_rx_burst(0, 0, bufs, BURST_SIZE); for (uint16_t i = 0; i < nb_rx; ++i) { // 处理接收到的数据包 // ... // 释放缓冲区 rte_pktmbuf_free(bufs[i]); } } return 0; } ``` 上述示例中,我们使用了C++的标准库头文件,并使用了DPDK提供的C API函数和数据结构。在编写DPDK应用程序时,需要包含适当的DPDK头文件,并按照DPDK的编程模型进行操作。此外,还需要注意资源的分配和释放,如内存池和缓冲区的创建和释放。 需要注意的是,上述示例仅用于演示目的,实际的DPDK应用程序可能需要更复杂的逻辑和功能,如数据包解析、协议处理、流量控制等。开发人员可以根据自己的需求在此基础上进行扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值