背景

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

问题

dpdk-16.11.1

在dpdk-16.11.1上的程序如下:

static uint8_t rss_intel_key[] = { 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 = ,
.header_split = , /**< Header Split disabled */
.hw_ip_checksum = , /**< IP checksum offload disabled */
.hw_vlan_filter = , /**< VLAN filtering disabled */
.jumbo_frame = , /**< Jumbo Frame Support disabled */
.hw_strip_crc = , /**< 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[] = { 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 = ,
.split_hdr_size = ,
.offloads = ,
},
.rx_adv_conf = {
.rss_conf = {
.rss_key = rss_intel_key,
.rss_key_len = ,
.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= 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 = , }; 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 != ) &&
((rss_hash_protos & ETH_RSS_PROTO_MASK) == )) {
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)

最新文章

  1. HTML 学习笔记 JavaScript (prototype)
  2. makeJar
  3. MFC下调用控制台和控制台下MFC库的支持
  4. LeetCode 笔记26 Single Number II
  5. 关于JS加载的问题
  6. Java---算法---插入排序
  7. Dojo Widget中的全局变量
  8. ajax传递json数据,springmvc后台就收json数据
  9. 进阶-案例九: WD中实现export 到Excel,Doc,Txt.
  10. Microservice架构模
  11. PHP 流程
  12. KB奇遇记(1):开篇
  13. cssradius
  14. aforge 学习-命名空间中文理解
  15. java.util.zip.ZipException:ZIP file must have at least one entry
  16. 【练习】Python第四次:实现对文件的增删改查
  17. 关于java职业路径
  18. 针对piix4_smbus ****host smbus controller not enabled的解决方法
  19. IDEA发布应用时发布到lib下面的包不全
  20. TUANDUIZUOYE

热门文章

  1. 用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识
  2. 日吞吐万亿,腾讯云时序数据库CTSDB解密
  3. 轻量级数据库Sqlite的使用
  4. 【Android Studio安装部署系列】十、Android studio打包发布apk安装包
  5. 学习笔记01(mybatis逆向工程)
  6. Floyd算法java实现demo
  7. Node.js学习(第一章:Node.js安装和模块化理解)
  8. Asp.NetCore轻松学-实现一个轻量级高可复用的RabbitMQ客户端
  9. [翻译] GCC 内联汇编 HOWTO
  10. JVM平台上的响应式流(Reactive Streams)规范