记录一下测试dpdk udp收发的程序,程序很简单,从网卡收到ipv4 udp包后,将udp包回传给源。
- export 两个dpdk环境变量
export RTE_SDK=/root/dpdk-19.11
export RTE_TARGET=x86_64-native-linuxapp-gcc - 设置好环境(安装驱动/大页/配置端口)
可参考dpdk个人学习使用全过程_地上一个猴的博客-CSDN博客_dpdk教程 - 参考其他示例的makefile,写一个
- 写代码(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]); } } } }
- Windows本地添加静态地址
运行管理员cmd,其中ip地址为自定义,不与局域网冲突即可,mac地址必须正确,是配置给dpdk的网卡地址。
netsh -c i i add neighbors 12 "10.180.147.55" "00-0c-29-88-c1-9a" - 打开网络调试助手网络调试助手下载_网络调试助手绿色版免费下载-华军软件园
填写正确的本地ip,连接后填写刚才添加的目标主机地址 - windows发送消息到dpdk,udp将消息传回windows
文章参考:[4].dpdk实现udp协议发送数据_u.意思的博客-CSDN博客_dpdk udp