You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用DPDK向其他物理服务器发送指定IP和端口数据包及相关接收方法、l3fwd适用性的技术咨询

基于DPDK实现指定IP端口发包、收包及l3fwd场景分析

嘿,我看到你已经在基于DPDK的rxtx_callbacks示例做开发了,碰到了指定IP端口发包、收包以及l3fwd适用性的问题,我来给你梳理下解决方案:

一、基于rxtx_callbacks发送指定IP和端口的数据包

rxtx_callbacks示例本身侧重展示收发回调的逻辑,并没有内置数据包构造的代码——毕竟DPDK是偏底层的库,需要你手动填充协议栈的每一层头信息。具体步骤如下:

  1. 分配并初始化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 *);
    
  2. 逐层填充协议头
    你需要依次填充以太网头、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会更省心)
  3. 添加负载(可选)
    如果需要发送带业务内容的数据包,在协议头之后填充数据,同时更新mbuf的data_lenpkt_len字段。

  4. 发送数据包
    在发送回调或者你的发送逻辑里,用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的话,接收逻辑已经有基础框架,你可以补充以下细节:

  1. 接收数据包
    在主循环或者接收回调里,用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);
    
  2. 解析数据包
    遍历接收到的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]);
    }
    
  3. 接收回调的优化使用
    rxtx_callbacks里的rx_callback函数可以绑定到网卡接收队列,每收到一个mbuf就会触发回调,你可以把解析逻辑放在这个回调里,让代码结构更模块化。

三、l3fwd是否适用于你的场景?

简单来说:不适合

l3fwd是DPDK官方的三层转发示例,它的核心功能是根据预设的IP路由表,把从一个网卡收到的数据包转发到另一个网卡,本质是做“数据包中转转发”,而不是“主动构造并发送自定义数据包”。

如果你的需求只是实现跨服务器的数据包转发,那l3fwd可以作为参考;但如果是要主动构造指定IP、端口的数据包发送,同时处理接收的数据包,还是基于rxtx_callbacks扩展,或者参考DPDK的packet_generator示例(专门做发包测试的)会更合适。

内容的提问来源于stack exchange,提问作者Leftddr

火山引擎 最新活动