相关代码:DPDK_Learning/ARP_response at main · mfdycs/DPDK_Learning (github.com)

相关原理

ARP数据包

  • ARP Request
  • ARP Response

ARP的功能

  • 1.响应其他机器的arp request(本章实现)
  • 2.定时主动发送arp request,响应其他机器的arp reply,记录在arp table中

ARP是一个广播协议,不是一对一的通信

ARP操作

# 查看arp表
arp -a
# 查看网卡对应的信息
netsh i i show in
# 删除网卡的arp表
netsh i i delete neighbors 22
## 此时再使用工具发送数据包,会发现找不到对应的arp映射

500

# 添加arp映射
netsh -c i i add neighbors 22 192.168.81.128 XX-XX-XX-XX-XX-XX
# 此时发送数据正常

对于DPDK,响应ARP请求一共有三个步骤:

  • 识别ARP请求
  • 是否是自己的机器
  • 发送ARP响应

添加标识

#define ENABLE_ARP 1

与UDP发送类似,构造ARP响应

#if ENABLE_ARP  

static int ng_encode_arp_pkt(uint8_t *msg, uint8_t *dst_mac, uint32_t sip, uint32_t dip)  
{  
    // 1 ethhdr  
    struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;  
    rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);  
    rte_memcpy(eth->d_addr.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN);  
    eth->ether_type = htons(RTE_ETHER_TYPE_ARP);  

    // 2 arp  
    struct rte_arp_hdr *arp = (struct rte_arp_hdr *)(eth + 1); // eth首部下一位  
    arp->arp_hardware = htons(1); // 硬件类型  
    arp->arp_protocol = htons(RTE_ETHER_TYPE_IPV4); // 协议类型  
    arp->arp_hlen = RTE_ETHER_ADDR_LEN; // 硬件地址长度  
    arp->arp_plen = sizeof(uint32_t); // 协议地址长度: len(ipv4)  
    arp->arp_opcode = htons(2); // 操作码  

    rte_memcpy(arp->arp_data.arp_sha.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN); // 发送者硬件地址  
    rte_memcpy( arp->arp_data.arp_tha.addr_bytes, dst_mac, RTE_ETHER_ADDR_LEN); // 接收者硬件地址  

    arp->arp_data.arp_sip = sip;  
    arp->arp_data.arp_tip = dip;  

    return 0;  
}  

static struct rte_mbuf* ng_send_arp(struct rte_mempool *mbuf_pool, uint8_t *dst_mac, uint32_t sip, uint32_t dip)  
{  
    // len(arp:42) = len(eth:14) + len(arp:28)  
    const unsigned total_length = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);  

    struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);  
    if (!mbuf) {  
        rte_exit(EXIT_FAILURE, "rte_pktmbuf_alloc\n");  
    }  

    mbuf->pkt_len = total_length;  
    mbuf->data_len = total_length;  

    uint8_t *pkt_data = rte_pktmbuf_mtod(mbuf, uint8_t *);  
    ng_encode_arp_pkt(pkt_data, dst_mac, sip, dip);  

    return mbuf;  
}  

#endif

主函数解析数据并识别

#if ENABLE_ARP  
            if (ethr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {  
                struct rte_arp_hdr *arp_hdr = rte_pktmbuf_mtod_offset(mbufs[i], struct rte_arp_hdr*, sizeof(struct rte_ether_hdr));  

                struct in_addr addr;  
                addr.s_addr = arp_hdr->arp_data.arp_tip;  
                printf("arp ---> src: %s ", inet_ntoa(addr));  

                addr.s_addr = gLocalIp;  
                printf("arp ---> local: %s \n", inet_ntoa(addr));  

                if (arp_hdr->arp_data.arp_tip == gLocalIp) {  
                    struct rte_mbuf *arpbuf = ng_send_arp(mbuf_pool, arp_hdr->arp_data.arp_sha.addr_bytes,  
                                                          arp_hdr->arp_data.arp_tip, arp_hdr->arp_data.arp_sip);  

                    rte_eth_tx_burst(DPDK_PortID, 0, &arpbuf, 1);  
                    rte_pktmbuf_free(arpbuf);  
                    rte_pktmbuf_free(mbufs[i]);  
                }  

                continue;  
            }  
#endif

此时 ping 主机会显示Timeout,因为没有实现icmp协议,但是ARP响应流通(否则会显示不可到达)