ZBLOG

19.2版本的dpdk使用最新版nDPI过滤http协议代码

以下是使用19.2版本的DPDK和最新版nDPI进行HTTP协议过滤的示例代码:

#include <stdio.h>
#include <string.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include <ndpi_api.h>

#define BURST_SIZE 32

static struct ndpi_detection_module_struct *ndpi_struct = NULL;

static void packet_handler(struct rte_mbuf *pkt) {
    struct ndpi_detection_results results;
    int rc = 0;

    // 获取数据包缓冲区地址
    void *packet = rte_pktmbuf_mtod(pkt, void *);

    // 进行协议识别
    memset(&results, 0, sizeof(results));
    ndpi_protocol detection = ndpi_detection_process_packet(ndpi_struct, packet, pkt->data_len, &results);
    if (detection.app_protocol == NDPI_PROTOCOL_HTTP) {
        printf("Detected HTTP traffic from flow %u.%u.%u.%u:%u to %u.%u.%u.%u:%u\n",
               (pkt->hash.rss & 0xff000000) >> 24, (pkt->hash.rss & 0x00ff0000) >> 16,
               (pkt->hash.rss & 0x0000ff00) >> 8, pkt->hash.rss & 0x000000ff,
               rte_be_to_cpu_16(pkt->port), 
               (pkt->hash.fdir.hi & 0xffff0000) >> 16, pkt->hash.fdir.hi & 0x0000ffff,
               (pkt->hash.fdir.lo & 0xffff0000) >> 16, pkt->hash.fdir.lo & 0x0000ffff,
               rte_be_to_cpu_16(pkt->hash.fdir.hi));
    }
}

int main(int argc, char *argv[]) {
    int ret;

    // 初始化DPDK环境
    ret = rte_eal_init(argc, argv);
    if (ret < 0) {
        rte_exit(EXIT_FAILURE, "rte_eal_init failed\n");
    }

    // 获取网口数量
    uint16_t nb_ports = rte_eth_dev_count_avail();
    if (nb_ports == 0) {
        rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
    }

    // 配置DPDK网口
    for (int portid = 0; portid < nb_ports; portid++) {
        ret = rte_eth_dev_configure(portid, 1, 1, NULL);
        if (ret < 0) {
            rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", ret, portid);
        }

        struct rte_eth_conf port_conf;
        memset(&port_conf, 0, sizeof(port_conf));
        port_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN;
        port_conf.rxmode.mq_mode = ETH_MQ_RX_RSS;
        port_conf.rx_adv_conf.rss_conf.rss_key = NULL;
        port_conf.rx_adv_conf.rss_conf.rss_hf |= ETH_RSS_PROTO_MASK;

        ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
        if (ret < 0) {
            rte_exit(EXIT_FAILURE,"Cannot configure device: err=%d,port=%u\n",ret,(unsigned)portid);
       }

       // 启动DPDK网口接收流量
       const uint16_t rx_rings = 1, tx_rings = 1;
       const uint16_t rx_ring_size = 1024, tx_ring_size = 1024;
       struct rte_eth_rxconf rx_conf;
       memset(&rx_conf, 0, sizeof(rx_conf));
       rx_conf.rx_thresh.pthresh = 8;
       rx_conf.rx_thresh.hthresh = 8;
       rx_conf.rx_thresh.wthresh = 4;

       for (int qid = 0; qid < rx_rings; qid++) {
            ret = rte_eth_rx_queue_setup(portid, qid, rx_ring_size, rte_eth_dev_socket_id(portid), &rx_conf,
                                          rte_pktmbuf_pool_create("RX_POOL", nb_ports * rx_ring_size,
                                                                  RTE_CACHE_LINE_SIZE, 0,
                                                                  RTE_MBUF_DEFAULT_BUF_SIZE,
                                                                  rte_socket_id()));
            if (ret < 0) {
                rte_exit(EXIT_FAILURE,"Cannot configure RX queue: err=%d,q=%u\n",ret,(unsigned)qid);
            }
        }

        struct rte_eth_txconf tx_conf;
        memset(&tx_conf, 0, sizeof(tx_conf));
        tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS;

        for (int qid = 0; qid < tx_rings; qid++) {
            ret = rte_eth_tx_queue_setup(portid, qid, tx_ring_size,rte_eth_dev_socket_id(portid), &tx_conf);
            if (ret < 0) {
                rte_exit(EXIT_FAILURE,"Cannot configure TX queue: err=%d,q=%u\n",ret,(unsigned)qid);
            }
        }

        ret = rte_eth_dev_start(portid);
        if (ret < 0) {
            rte_exit(EXIT_FAILURE,"Cannot start device: err=%d,port=%u\n", ret,(unsigned)portid);
        }

        rte_eth_promiscuous_enable(portid);
    }

    // 初始化nDPI
    ndpi_struct = ndpi_init_detection_module();
    if (ndpi_struct == NULL) {
        rte_exit(EXIT_FAILURE, "Failed to initialize nDPI\n");
    }

    // 加载nDPI协议识别规则
    int num_signatures = ndpi_load_protocols_file(ndpi_struct, "/path/to/ndpi/protocols.txt");
    if (num_signatures <= 0) {
        rte_exit(EXIT_FAILURE, "Failed to load nDPI protocol signatures\n");
    }
    
    printf("Loaded %d nDPI protocol signatures\n", num_signatures);

    // 开始接收数据包并进行处理
    struct rte_mbuf *pkts_burst[BURST_SIZE];
    while (1) {
        for (int portid = 0; portid < nb_ports; portid++) {
            const uint16_t nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst, BURST_SIZE);
            for (int i = 0; i < nb_rx; i++) {
                packet_handler(pkts_burst[i]);
                rte_pktmbuf_free(pkts_burst[i]);
            }
        }
     }

     return 0;
}

在上述代码中,我们使用ndpi_api.h头文件提供的函数来实现对HTTP协议的过滤。具体步骤如下:

  1. 在程序启动时初始化nDPI模块,可以使用ndpi_init_detection_module()函数。

  2. 加载nDPI协议识别规则,可以通过调用ndpi_load_protocols_file()函数来加载协议规则文件。在示例代码中,我们将协议规则文件存放在/path/to/ndpi/protocols.txt路径下。

  3. 在数据包处理函数中调用ndpi_detection_process_packet()函数进行协议识别。如果检测到HTTP流量,则打印出相应的信息。

需要注意的是,在使用nDPI进行协议识别时,需要预留足够的时间来处理每个数据包。因此,在接收数据包时可以使用DPDK提供的批量接收功能,一次性接收多个数据包,减少处理延迟。

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

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

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

联系我们

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

微信号:3007537140

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

关注我们
x

注册

已经有帐号?