ZBLOG

用DPDK写C语言代码,包括ARP定时发出ARP请求,ARP解析,并保存APR表功能

以下是使用DPDK库编写的C语言代码,实现了ARP定时发送ARP请求、解析ARP,并保存ARP表的功能。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_arp.h>

#define MAX_PORTS 16    // 最大端口数
#define ARP_TIMEOUT 60  // ARP表项超时时间(秒)

// 保存ARP表项的结构体
struct arp_entry {
    struct ether_addr mac_addr; // MAC地址
    uint32_t ip_addr;           // IP地址
    time_t timestamp;           // 时间戳
};

// 全局变量
int nb_ports;                               // 端口数
uint16_t port_ids[MAX_PORTS];               // 端口ID数组
struct rte_eth_conf port_conf;               // 端口配置
struct rte_mempool *mbuf_pool;               // Mbuf内存池
struct rte_arp_hdr arp_req;                  // ARP请求头
struct arp_entry arp_table[65536];           // ARP表
int arp_table_size = 0;                      // ARP表中的表项数

// 初始化DPDK环境
static void init_dpdk(int argc, char *argv[]) {
    int ret = rte_eal_init(argc, argv);
    if (ret < 0) {
        rte_exit(EXIT_FAILURE, "Failed to initialize DPDK environment.\n");
    }

    nb_ports = rte_eth_dev_count_avail();
    if (nb_ports == 0) {
        rte_exit(EXIT_FAILURE, "No Ethernet ports found.\n");
    }

    // 获取所有端口的ID
    for (int i = 0; i < nb_ports; i++) {
        port_ids[i] = i;
    }

    // 配置端口
    port_conf = (struct rte_eth_conf){
        .rxmode = { .max_rx_pkt_len = RTE_ETHER_MAX_LEN },
        .txmode = { .mq_mode = ETH_MQ_TX_NONE },
    };
}

// 初始化Mbuf内存池
static void init_mbuf_pool(void) {
    mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 8192, 256, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
    if (mbuf_pool == NULL) {
        rte_exit(EXIT_FAILURE, "Failed to create Mbuf memory pool.\n");
    }
}

// 配置端口
static void configure_port(uint16_t port_id) {
    int ret;

    // 配置端口属性
    struct rte_eth_conf port_conf = {
        .rxmode = {
            .split_hdr_size = 0,
            .header_split   = 0,
            .hw_ip_checksum = 1,
            .hw_vlan_filter = 0,
            .jumbo_frame    = 0,
            .hw_strip_crc   = 1,
        },
        .txmode = {
            .mq_mode        = ETH_MQ_TX_NONE,
        },
    };

    ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
    if (ret < 0) {
        rte_exit(EXIT_FAILURE, "Failed to configure Ethernet port %u.\n", port_id);
    }

    // 启动端口
    ret = rte_eth_dev_start(port_id);
    if (ret < 0) {
        rte_exit(EXIT_FAILURE, "Failed to start Ethernet port %u.\n", port_id);
    }

    // 开启混杂模式
    rte_eth_promiscuous_enable(port_id);
}

// 发送ARP请求
static void send_arp_request(uint16_t port_id, struct ether_addr *src_mac, uint32_t src_ip, uint32_t dst_ip) {
    // 准备ARP请求头
    arp_req.arp_hrd = rte_cpu_to_be_16(RTE_ARP_HRD_ETHER);
    arp_req.arp_pro = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPv4);
    arp_req.arp_hln = RTE_ETHER_ADDR_LEN;
    arp_req.arp_pln = sizeof(uint32_t);
    arp_req.arp_op  = rte_cpu_to_be_16(RTE_ARP_OP_REQUEST);

    rte_memcpy(&arp_req.arp_data.arp_sha, src_mac, RTE_ETHER_ADDR_LEN);
    arp_req.arp_data.arp_sip = rte_cpu_to_be_32(src_ip);
    rte_eth_macaddr_get(port_id, &arp_req.arp_data.arp_tha);
    arp_req.arp_data.arp_tip = rte_cpu_to_be_32(dst_ip);

    // 准备Mbuf
    struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mbuf_pool);
    if (mbuf == NULL) {
        printf("No available Mbuf.\n");
        return;
    }

    // 填充Mbuf
    mbuf->data_len = mbuf->pkt_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);
    struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
    rte_memcpy(&eth_hdr->s_addr, src_mac, RTE_ETHER_ADDR_LEN);
    rte_eth_macaddr_get(port_id, &eth_hdr->d_addr);
    eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP);
    struct rte_arp_hdr *arp_hdr = (struct rte_arp_hdr *)((uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr));
    rte_memcpy(arp_hdr, &arp_req, sizeof(struct rte_arp_hdr));

    // 发送Mbuf
    uint16_t nb_tx = rte_eth_tx_burst(port_id, 0, &mbuf, 1);
    if (nb_tx == 0) {
        rte_pktmbuf_free(mbuf);
    }
}

// 解析ARP响应
static void parse_arp_reply(uint16_t port_id, struct rte_mbuf *mbuf) {
    struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
    struct rte_arp_hdr *arp_hdr = (struct rte_arp_hdr *)((uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr));

    // 判断是否为ARP响应
    if (rte_be_to_cpu_16(eth_hdr->ether_type) != RTE_ETHER_TYPE_ARP || rte_be_to_cpu_16(arp_hdr->arp_op) != RTE_ARP_OP_REPLY) {
        return;
    }

    // 将ARP表项保存到ARP表中
    struct arp_entry entry;
    rte_memcpy(&entry.mac_addr, &arp_hdr->arp_data.arp_sha, RTE_ETHER_ADDR_LEN);
    entry.ip_addr = rte_be_to_cpu_32(arp_hdr->arp_data.arp_sip);
    entry.timestamp = time(NULL);
    int i;
    for (i = 0; i < arp_table_size; i++) {
        if (arp_table[i].ip_addr == entry.ip_addr) {
            arp_table[i].mac_addr = entry.mac_addr;
            arp_table[i].timestamp = entry.timestamp;
            break;
        }
    }
    if (i == arp_table_size) {
        arp_table[arp_table_size++] = entry;
    }

    // 打印ARP表
    printf("ARP table:\n");
    for (i = 0; i < arp_table_size; i++) {
        char ip_str[16];
        inet_ntop(AF_INET, &arp_table[i].ip_addr, ip_str, sizeof(ip_str));
        printf("%s -> %02X:%02X:%02X:%02X:%02X:%02X (%ld seconds ago)\n",
            ip_str,
            arp_table[i].mac_addr.addr_bytes[0], arp_table[i].mac_addr.addr_bytes[1],
            arp_table[i].mac_addr.addr_bytes[2], arp_table[i].mac_addr.addr_bytes[3],
            arp_table[i].mac_addr.addr_bytes[4], arp_table[i].mac_addr.addr_bytes[5],
            time(NULL) - arp_table[i].timestamp);
    }
}

// 处理收到的数据包
static void handle_packet(uint16_t port_id, struct rte_mbuf *mbuf) {
    struct rte_ether_hdr *eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);

    // 判断是否为ARP请求
    if (rte_be_to_cpu_16(eth_hdr->ether_type) == RTE_ETHER_TYPE_ARP) {
        struct rte_arp_hdr *arp_hdr = (struct rte_arp_hdr *)((uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr));
        if (rte_be_to_cpu_16(arp_hdr->arp_op) == RTE_ARP_OP_REQUEST) {
            uint32_t dst_ip = rte_be_to_cpu_32(arp_hdr->arp_data.arp_tip);
            if (dst_ip == rte_eth_devices[port_id].data->ipv4_addr) {
                // 发送ARP响应
                struct ether_addr src_mac;
                rte_eth_macaddr_get(port_id, &src_mac);
                arp_hdr->arp_op = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
                rte_memcpy(&arp_hdr->arp_data.arp_tha, &arp_hdr->arp_data.arp_sha, RTE_ETHER_ADDR_LEN);
                rte_memcpy(&arp_hdr->arp_data.arp_sha, &src_mac, RTE_ETHER_ADDR_LEN);
                uint32_t tmp_ip = arp_hdr->arp_data.arp_sip;
                arp_hdr->arp_data.arp_sip = arp_hdr->arp_data.arp_tip;
                arp_hdr->arp_data.arp_tip = tmp_ip;
                rte_memcpy(&eth_hdr->d_addr, &eth_hdr->s_addr, RTE_ETHER_ADDR_LEN);
                rte_eth_macaddr_get(port_id, &eth_hdr->s_addr);
                rte_eth_tx_burst(port_id, 0, &mbuf, 1);
            }
        } else if (rte_be_to_cpu_16(arp_hdr->arp_op) == RTE_ARP_OP_REPLY) {
            parse_arp_reply(port_id, mbuf);
        }
    }

    rte_pktmbuf_free(mbuf);
}

// 定时发送ARP请求
static void send_arp_request_periodically(void) {
    while (1) {
        sleep(10);

        for (int i = 0; i < nb_ports; i++) {
            for (int j = 0; j < arp_table_size; j++) {
                uint32_t dst_ip = arp_table[j].ip_addr;
                struct ether_addr src_mac;
                rte_eth_macaddr_get(port_ids[i], &src_mac);
                send_arp_request(port_ids[i], &src_mac, rte_eth_devices[port_ids[i]].data->ipv4_addr, dst_ip);
            }
        }
    }
}

int main(int argc, char *argv[]) {
    // 初始化DPDK环境
    init_dpdk(argc, argv);

    // 初始化Mbuf内存池
    init_mbuf_pool();

    // 配置所有端口
    for (int i = 0; i < nb_ports; i++) {
        configure_port(port_ids[i]);
    }

    // 启动定时器线程
    pthread_t tid;
    pthread_create(&tid, NULL, (void *(*)(void *))send_arp_request_periodically, NULL);

    // 处理收到的数据包
    struct rte_mbuf *mbufs[32];
    while (1) {
        int nb_rx = rte_eth_rx_burst(port_ids[0], 0, mbufs, 32);
        if (nb_rx > 0) {
            for (int i = 0; i < nb_rx; i++) {
                handle_packet(port_ids[0], mbufs[i]);
            }
        } else {
            usleep(1000);
        }
    }

    return 0;
}

说明:

  • init_dpdk():初始化DPDK环境。
  • init_mbuf_pool():初始化Mbuf内存池。
  • configure_port():配置指定ID的端口。
  • send_arp_request():发送ARP请求。
  • parse_arp_reply():解析ARP响应,并保存到ARP表中。
  • handle_packet():处理收到的数据包,如果是ARP请求,则回复ARP响应;如果是ARP响应,则解析并保存到ARP表中。
  • send_arp_request_periodically():用于定时发送ARP请求。
  • 主函数中先配置所有端口,然后启动定时器线程和数据包接收循环。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=324

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?