ZBLOG

DPDK20.11初始化rss,将报文轮询放到不同接收队列的代码

以下是DPDK 20.11版本初始化RSS,并将报文轮询放到不同接收队列的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/queue.h>
#include <rte_common.h>
#include <rte_ethdev.h>

#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_RX_QUEUES 2

static const struct rte_eth_conf port_conf_default = {
    .rxmode = {
        .max_rx_pkt_len = ETHER_MAX_LEN,
        .split_hdr_size = 0,
        .header_split   = 0, /**< Header Split disabled */
        .hw_ip_checksum = 1, /**< IP checksum offload enabled */
        .hw_vlan_filter = 0, /**< VLAN filtering disabled */
        .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
        .hw_strip_crc   = 1, /**< CRC stripped by hardware */
    },
    .txmode = {
        .mq_mode = ETH_MQ_TX_NONE,
    },
};

int main(int argc, char **argv)
{
    int ret;
    uint16_t nb_ports;
    uint16_t portid;

    // 初始化EAL环境
    ret = rte_eal_init(argc, argv);
    if (ret < 0) {
        rte_exit(EXIT_FAILURE, "Error: Failed to initialize EAL (%s)\n", strerror(-ret));
    }

    // 获取可用端口数
    nb_ports = rte_eth_dev_count_avail();
    if (nb_ports == 0) {
        rte_exit(EXIT_FAILURE, "Error: No available network ports\n");
     }

     // 配置每个端口
     for (portid = 0; portid < nb_ports; portid++) {

         struct rte_eth_conf port_conf;
         struct rte_eth_rxconf rxq_conf[NUM_RX_QUEUES];
         struct rte_eth_txconf txq_conf;
         struct rte_eth_dev_info dev_info;

         // 获取端口设备信息
         memset(&dev_info, 0, sizeof(dev_info));
         rte_eth_dev_info_get(portid, &dev_info);

         // 设置rx和tx队列配置
         memset(&rxq_conf, 0, sizeof(rxq_conf));
         
         // 配置每个接收队列的rss功能
         for (int i = 0; i < NUM_RX_QUEUES && dev_info.reta_size > RTE_ETH_RSS_RETA_SIZE_64; i++) {
             uint8_t rss_key[] = {52,102,121,161,177};
             uint8_t rss_hash_func =
                     ETH_RSS_IP | ETH_RSS_UDP | ETH_RSS_TCP |
                     ETH_RSS_SCTP | ETH_RSS_L2_PAYLOAD |
                     ETH_RSS_IPV6_EX | ETH_RSS_IPV6_TCP_EX |
                     ETH_RSS_IPV6_UDP_EX | ETH_RSS_IPV6_EX_L2_PAYLOAD |
                     ETH_RSS_NONFRAG_IPV4_OTHER | 
                     ETH_RSS_NONFRAG_IPV4_UDP | 
                     ETH_RSS_NONFRAG_IPV4_TCP |
                     ETH_RSS_NONFRAG_IPV6_OTHER | 
                     ETH_RSS_NONFRAG_IPV6_UDP | 
                     ETH_RSS_NONFRAG_IPV6_TCP;
             ret = rte_eth_dev_rss_hash_update(portid,
                                               rss_key,
                                               sizeof(rss_key),
                                               rss_hash_func);
             if (ret < 0) {
                 rte_exit(EXIT_FAILURE,
                          "Error: Failed to update RSS hash functions for port %u and queue %d (%s)\n",
                          portid, i, strerror(-ret));
             }
             uint8_t rss_key_len = sizeof(rss_key);
             uint16_t reta_size = dev_info.reta_size;
             uint8_t reta[reta_size];
             memset(reta, 0, sizeof(reta));
             for (int j = 0; j < reta_size; j++) {
                 reta[j] = i % dev_info.nb_rx_queues;
             }
             ret = rte_eth_dev_rss_reta_update(portid,
                                               reta,
                                               reta_size);
              if (ret < 0) {
                  rte_exit(EXIT_FAILURE,
                           "Error: Failed to update RSS redirect table for port %u (%s)\n",
                           portid, strerror(-ret));
              }

            // 配置rx队列
            rxq_conf[i].rx_thresh.pthresh = 8;
            rxq_conf[i].rx_thresh.hthresh = 8;
            rxq_conf[i].rx_thresh.wthresh = 4;
            rxq_conf[i].rx_free_thresh = 32;
         }

         memset(&txq_conf, 0, sizeof(txq_conf));
         txq_conf.tx_rs_thresh = 32;
         txq_conf.tx_free_thresh = 0;
         txq_conf.tx_thresh.pthresh = 36;
         txq_conf.tx_thresh.hthresh = 0;
         txq_conf.tx_thresh.wthresh = 0;

        // 初始化port configuration structure with default values
        port_conf = port_conf_default;

        // 配置端口并启动
        ret = rte_eth_dev_configure(portid, NUM_RX_QUEUES, 1, &port_conf);
        if (ret < 0) {
            rte_exit(EXIT_FAILURE, "Error: Failed to configure port %u (%s)\n", portid, strerror(-ret));
        }

        // 初始化rx和tx队列
        for (int i = 0; i < NUM_RX_QUEUES; i++) {
            ret = rte_eth_rx_queue_setup(portid, i, RX_RING_SIZE,
                                          rte_eth_dev_socket_id(portid),
                                          &rxq_conf[i],
                                          rte_eth_rx_burst);
            if (ret < 0) {
                rte_exit(EXIT_FAILURE, "Error: Failed to setup rx queue %d for port %u (%s)\n",
                          i, portid, strerror(-ret));
            }
         }

         ret = rte_eth_tx_queue_setup(portid, 0, TX_RING_SIZE,
                                        rte_eth_dev_socket_id(portid),
                                        &txq_conf);
          if (ret < 0) {
              rte_exit(EXIT_FAILURE, "Error: Failed to setup tx queue for port %u (%s)\n", portid,strerror(-ret));
           }

           // 启动端口
           ret = rte_eth_dev_start(portid);
           if (ret < 0) {
               rte_exit(EXIT_FAILURE, "Error: Failed to start port %u (%s)\n", portid,strerror(-ret));
            }
     }
}

此示例演示了如何初始化DPDK以使用RSS功能,并将报文轮询放到不同的接收队列中。在主函数中,我们首先调用rte_eal_init()来初始化EAL环境,然后获取可用端口数,并遍历每个端口以配置其rx和tx队列。

对于支持更大的RETAsize的设备,我们为每个接收队列启用RSS哈希功能,并将哈希键、哈希函数等参数传递给rte_eth_dev_rss_hash_update()函数。然后,我们使用rte_eth_dev_rss_reta_update()函数将每个接收队列的重定向表设置为其所在的队列编号。

对于每个接收队列,我们都有自己的rxq_conf结构体变量,并调用rte_eth_rx_queue_setup()来初始化它们。最后,我们启动端口并开始处理数据包。

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

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

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

联系我们

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

微信号:3007537140

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

关注我们
x

注册

已经有帐号?