背景
最近在作將基於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函數聲明ui
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) 函數時均可以正常啓動。spa
dpdk-18.11
dpdk-18.11中對 struct rte_eth_conf 結構體進行了修改,使用offloads代替了以前的幾個變量標誌位,不過這都影響不大。code
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上是一致的。blog
在編譯完成後,進行運行時發現,報錯沒法運行。報錯以下:ip
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。get
找到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)