使用DPDK向其他物理服务器发送指定IP和端口数据包及相关接收方法、l3fwd适用性的技术咨询
嘿,我看到你已经在基于DPDK的rxtx_callbacks示例做开发了,碰到了指定IP端口发包、收包以及l3fwd适用性的问题,我来给你梳理下解决方案:
一、基于rxtx_callbacks发送指定IP和端口的数据包
rxtx_callbacks示例本身侧重展示收发回调的逻辑,并没有内置数据包构造的代码——毕竟DPDK是偏底层的库,需要你手动填充协议栈的每一层头信息。具体步骤如下:
分配并初始化mbuf
首先从内存池里分配一个空的mbuf,用来承载数据包:struct rte_mbuf *mbuf = rte_pktmbuf_alloc(pkt_pool); if (mbuf == NULL) { // 处理分配失败的情况 return; } // 预留协议头空间,方便后续填充 mbuf->data_len = 0; mbuf->pkt_len = 0; char *data = rte_pktmbuf_mtod(mbuf, char *);逐层填充协议头
你需要依次填充以太网头、IP头、UDP/TCP头:- 以太网头:指定目的MAC(目标服务器的网卡MAC)、源MAC(本地网卡MAC)、以太网类型(比如
0x0800代表IPv4) - IP头:设置版本、TTL、协议类型(UDP是17,TCP是6)、源IP、目的IP,最后用
rte_ipv4_cksum()计算并填充校验和 - UDP/TCP头:指定源端口、目的端口,UDP可以用
rte_udp_cksum()计算校验和;如果是TCP,还需要处理序列号、确认号等字段(做简单测试的话UDP会更省心)
- 以太网头:指定目的MAC(目标服务器的网卡MAC)、源MAC(本地网卡MAC)、以太网类型(比如
添加负载(可选)
如果需要发送带业务内容的数据包,在协议头之后填充数据,同时更新mbuf的data_len和pkt_len字段。发送数据包
在发送回调或者你的发送逻辑里,用rte_eth_tx_burst()把构造好的mbuf发送出去:uint16_t tx_count = rte_eth_tx_burst(port_id, queue_id, &mbuf, 1); if (tx_count != 1) { // 处理发送失败,释放mbuf避免内存泄漏 rte_pktmbuf_free(mbuf); }
二、使用DPDK接收数据包
基于rxtx_callbacks的话,接收逻辑已经有基础框架,你可以补充以下细节:
接收数据包
在主循环或者接收回调里,用rte_eth_rx_burst()从网卡队列获取数据包:struct rte_mbuf *rx_mbufs[BURST_SIZE]; uint16_t rx_count = rte_eth_rx_burst(port_id, queue_id, rx_mbufs, BURST_SIZE);解析数据包
遍历接收到的mbuf,逐层解析协议头提取关键信息:for (int i = 0; i < rx_count; i++) { struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(rx_mbufs[i], struct rte_ether_hdr *); if (rte_be_to_cpu_16(eth_hdr->ether_type) == RTE_ETHER_TYPE_IPV4) { struct rte_ipv4_hdr *ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); // 转换并获取源IP、目的IP uint32_t src_ip = rte_be_to_cpu_32(ip_hdr->src_addr); uint32_t dst_ip = rte_be_to_cpu_32(ip_hdr->dst_addr); if (ip_hdr->next_proto_id == IPPROTO_UDP) { struct rte_udp_hdr *udp_hdr = (struct rte_udp_hdr *)(ip_hdr + 1); // 转换并获取源端口、目的端口 uint16_t src_port = rte_be_to_cpu_16(udp_hdr->src_port); uint16_t dst_port = rte_be_to_cpu_16(udp_hdr->dst_port); // 在这里添加你的业务处理逻辑 } } // 处理完成后务必释放mbuf rte_pktmbuf_free(rx_mbufs[i]); }接收回调的优化使用
rxtx_callbacks里的rx_callback函数可以绑定到网卡接收队列,每收到一个mbuf就会触发回调,你可以把解析逻辑放在这个回调里,让代码结构更模块化。
三、l3fwd是否适用于你的场景?
简单来说:不适合。
l3fwd是DPDK官方的三层转发示例,它的核心功能是根据预设的IP路由表,把从一个网卡收到的数据包转发到另一个网卡,本质是做“数据包中转转发”,而不是“主动构造并发送自定义数据包”。
如果你的需求只是实现跨服务器的数据包转发,那l3fwd可以作为参考;但如果是要主动构造指定IP、端口的数据包发送,同时处理接收的数据包,还是基于rxtx_callbacks扩展,或者参考DPDK的packet_generator示例(专门做发包测试的)会更合适。
内容的提问来源于stack exchange,提问作者Leftddr




