dpdk-18.11网卡多队列RSS设置

本文记录了从DPDK 16.11.1迁移到18.11过程中遇到的RSS配置问题。主要介绍了不同版本间配置差异及解决方法,并整理了igb、ixgbe和i40e驱动支持的特性。

背景

最近在做将基于dpdk-16.11.1开发的程序,转移到基于dpdk-18.11版本下开发。遇到了网卡RSS配置的问题,在这里纪录一下。

问题

dpdk-16.11.1

在dpdk-16.11.1上的程序如下:

static uint8_t rss_intel_key[40] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A
                                   };


static const struct rte_eth_conf port_conf = {
    .rxmode = {
        .mq_mode = ETH_MQ_RX_RSS,
        .split_hdr_size = 0,
        .header_split   = 0, /**< Header Split disabled */
        .hw_ip_checksum = 0, /**< IP checksum offload disabled */
        .hw_vlan_filter = 0, /**< VLAN filtering disabled */
        .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
        .hw_strip_crc   = 0, /**< CRC stripped by hardware */
    },
    .rx_adv_conf = {
        .rss_conf = {
            .rss_key = rss_intel_key,
            .rss_hf = ETH_RSS_PROTO_MASK,
        },
    },
    .txmode = {
        .mq_mode = ETH_MQ_TX_NONE,
    },
};

rte_eth_dev_configure函数声明

int rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_queue,
        uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf);

无论是千兆网卡还是万兆网卡,在调用  rte_eth_dev_configure(port_id, nb_rx_queue, nb_tx_queue, &port_conf)  函数时都可以正常启动。

dpdk-18.11

dpdk-18.11中对 struct rte_eth_conf 结构体进行了修改,使用offloads代替了之前的几个变量标志位,不过这都影响不大。

static uint8_t rss_intel_key[40] = { 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
                                     0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A
                                   };


static const struct rte_eth_conf port_conf = {
        .rxmode = {
            .mq_mode = ETH_MQ_RX_RSS,
            .max_rx_pkt_len = 0,
            .split_hdr_size = 0,
            .offloads = 0,
        },
        .rx_adv_conf = {
            .rss_conf = {
                .rss_key = rss_intel_key,
                .rss_key_len = 40,
                .rss_hf = ETH_RSS_PROTO_MASK,
            },
        },
        .txmode = {
            .mq_mode = ETH_MQ_TX_NONE,
        },
};

在调用  rte_eth_dev_configure(port_id, nb_rx_queue, nb_tx_queue, &port_conf)  函数是和16.11.1上是一致的。

在编译完成后,进行运行时发现,报错无法运行。报错如下:

Ethdev port_id=0 invalid rss_hf: 0x3ffffc, valid value: 0x38d34

port_id 0是一个igb驱动的网卡,型号为I350。

报错的意思是在调用 rte_eth_dev_configure 函数时,传入的最后一个函数参数(也就是网卡配置)中的 rx_adv_conf.rss_conf.rss_hf 参数值有问题,这个值是无效的。有效值是 0x38d34。

找到dpdk源码中打印错误信息的位置,前后代码如下:

int
rte_eth_dev_rss_hash_update(uint16_t port_id,
                struct rte_eth_rss_conf *rss_conf)
{
    struct rte_eth_dev *dev;
    struct rte_eth_dev_info dev_info = { .flow_type_rss_offloads = 0, };

    RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
    dev = &rte_eth_devices[port_id];
    rte_eth_dev_info_get(port_id, &dev_info);
    if ((dev_info.flow_type_rss_offloads | rss_conf->rss_hf) !=
        dev_info.flow_type_rss_offloads) {
        RTE_ETHDEV_LOG(ERR,
            "Ethdev port_id=%u invalid rss_hf: 0x%"PRIx64", valid value: 0x%"PRIx64"\n",
            port_id, rss_conf->rss_hf,
            dev_info.flow_type_rss_offloads);
        return -EINVAL;
    }
    RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rss_hash_update, -ENOTSUP);
    return eth_err(port_id, (*dev->dev_ops->rss_hash_update)(dev,
                                rss_conf));
}

 

 dev_info.flow_type_rss_offloads 就是网卡支持的flow类型, rss_conf->rss_hf 就是我们调用 rte_eth_dev_configure 函数的最后一个参考中的  rx_adv_conf.rss_conf.rss_hf 的值,

这里的if判断意思是配置的flow类型必须是网卡支持的flow类型,如果配置了网卡不支持的类型,就会报错。

经过计算器算出 0x38d34的二进制是111000110100110100,再配合在 rte_ethdev.h 中 ETH_RSS_开头的宏定义,得出111000110100110100就是下面所有宏定义的 或 值:

ETH_RSS_IPV4 | \
ETH_RSS_NONFRAG_IPV4_TCP| \
ETH_RSS_NONFRAG_IPV4_UDP| \
ETH_RSS_IPV6 | \
ETH_RSS_NONFRAG_IPV6_TCP | \
ETH_RSS_NONFRAG_IPV6_UDP | \
ETH_RSS_IPV6_EX | \
ETH_RSS_IPV6_TCP_EX | \
ETH_RSS_IPV6_UDP_EX

而我们配置中的参数  ETH_RSS_PROTO_MASK 显然比上面的类型要多,也就是 ETH_RSS_PROTO_MASK 定义的一些类型,网卡不支持,故而报错。

我们再看16.11.1中的源码

int
rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
{
    struct rte_eth_dev *dev;
    uint16_t rss_hash_protos;

    RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
    rss_hash_protos = rss_conf->rss_hf;
    if ((rss_hash_protos != 0) &&
        ((rss_hash_protos & ETH_RSS_PROTO_MASK) == 0)) {
        RTE_PMD_DEBUG_TRACE("Invalid rss_hash_protos=0x%x\n",
                rss_hash_protos);
        return -EINVAL;
    }
    dev = &rte_eth_devices[port_id];
    RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rss_hash_update, -ENOTSUP);
    return (*dev->dev_ops->rss_hash_update)(dev, rss_conf);
}

显然判断逻辑不同的。这里的判断意思是,只要有配置,并且配置中的flow类型至少有1项是在  ETH_RSS_PROTO_MASK  中的就可以,除非你配置的类型都不在  ETH_RSS_PROTO_MASK 中才会报错,这里就可以看出,即使你配置了网卡不支持的特性,也不会报错。

至此问题已解决。

总结

在dpdk-18.11中,配置网卡rss,必须网卡支持这种特性才行,否则会报错。

下面是整理的 igb , ixgbe ,  i40e 驱动网卡所支持的flow类型。

igb支持的特性

测试使用I350及I211网卡,有效值为0x38d34,二进制为111000110100110100,对应宏定义为

#define ETH_RSS_E1000_IGB (\
    ETH_RSS_IPV4 | \
    ETH_RSS_NONFRAG_IPV4_TCP| \
    ETH_RSS_NONFRAG_IPV4_UDP| \
    ETH_RSS_IPV6 | \
    ETH_RSS_NONFRAG_IPV6_TCP | \
    ETH_RSS_NONFRAG_IPV6_UDP | \
    ETH_RSS_IPV6_EX | \
    ETH_RSS_IPV6_TCP_EX | \
    ETH_RSS_IPV6_UDP_EX)

ixgbe支持的特性

测试使用82599ES网卡,有效值和igb相同

#define ETH_RSS_IXGBE ETH_RSS_E1000_IGB

i40e支持的特性

测试使用X710网卡,有效值为0x7ef8,二进制为111111011111000,对应宏定义为

#define ETH_RSS_I40E (\
    ETH_RSS_FRAG_IPV4 | \
    ETH_RSS_NONFRAG_IPV4_TCP | \
    ETH_RSS_NONFRAG_IPV4_UDP | \
    ETH_RSS_NONFRAG_IPV4_SCTP | \
    ETH_RSS_NONFRAG_IPV4_OTHER | \
    ETH_RSS_FRAG_IPV6 | \
    ETH_RSS_NONFRAG_IPV6_TCP | \
    ETH_RSS_NONFRAG_IPV6_UDP | \
    ETH_RSS_NONFRAG_IPV6_SCTP | \
    ETH_RSS_NONFRAG_IPV6_OTHER | \
    ETH_RSS_L2_PAYLOAD)

 

转载于:https://www.cnblogs.com/yanhai307/p/10608323.html

### DPDK 安装依赖与存储需求 安装 DPDK 需要一系列基础依赖,以确保编译和运行过程的顺利进行。这些依赖包括编译工具链、内核开发包、NUMA 支持库、以及用于特定功能的开发库,如 `libpcap-dev`(用于 pcap PMD 支持)[^2]。在基于 Debian 的系统上,可以通过以下命令安装这些依赖: ```bash sudo apt-get install build-essential libnuma-dev libpcap-dev ``` 此外,DPDK 还依赖于大页内存支持,因此需要确保系统内核配置中启用了 `CONFIG_HUGETLBFS` 和 `CONFIG_HUGEMEM` 等相关选项。在某些情况下,可能还需要启用 VFIO 或 UIO 模块以支持设备驱动[^1]。 关于源码下载和编译所需的存储空间,DPDK 源码包通常在 50MB 到 100MB 之间,具体大小取决于版本和包含的平台支持。解压后的源码目录可能占用 300MB 到 500MB 的空间。编译过程中,由于中间文件和目标文件的生成,整个构建目录可能需要额外的 1GB 到 2GB 空间。因此,建议为整个 DPDK 源码目录预留至少 2GB 的存储空间,以确保顺利编译[^2]。 ### 编译流程 DPDK 的编译流程通常包括配置和编译两个阶段。首先需要选择目标平台配置,例如 `x86_64-native-linuxapp-gcc`,然后执行配置命令: ```bash make config T=x86_64-native-linuxapp-gcc ``` 在配置完成后,可以修改 `.config` 文件以启用特定模块,例如启用 pcap 支持: ```bash sed -ri 's,(PMD_PCAP=).*,\1y,' build/.config ``` 随后执行编译命令: ```bash make ``` 若在编译过程中遇到 `numa.h` 无法找到的问题,通常是因为缺少 `libnuma-dev` 包,安装该依赖后即可解决。 ### 初始化环境 在完成编译后,还需要进行一些初始化操作,例如挂载大页内存并分配给 DPDK 使用。可以通过以下命令挂载大页文件系统: ```bash mkdir -p /mnt/huge mount -t hugetlbfs nodev /mnt/huge ``` 然后分配一定数量的大页内存: ```bash echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages ``` 最后,将设备绑定到 DPDK 支持的驱动(如 `vfio-pci` 或 `uio_pci_generic`)以便进行用户态访问: ```bash dpdk-devbind.py --bind=vfio-pci 0000:01:00.0 ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值