在测试环境中,频繁对DPDK的网卡接口反复做DOWN->UP操作,间隔周期2s,在运行一段时间(目前环境会在1min~5min左右)出现WX网卡接口一直DOWN状态,接口使能本端状态DOWN,对端UP正常。
DPDK版本19.11/20.11
1.在复现环境中,对WX网卡接口做DOWN->UP操作,对端状态跟随变化:PMD驱动管控逻辑和硬件逻辑正常,网卡并非硬件挂死。问题需要查看接口状态更新逻辑txgbe_dev_link_update_share
2.代码实现片段:
txgbe_dev_link_update_share(struct rte_eth_dev *dev,
int wait_to_complete)
{
struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
struct rte_eth_link link;
u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN;
struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev);
bool link_up;
int err;
int wait = 1;
memset(&link, 0, sizeof(link));
link.link_status = ETH_LINK_DOWN;
link.link_speed = ETH_SPEED_NUM_NONE;
link.link_duplex = ETH_LINK_HALF_DUPLEX;
link.link_autoneg = !(dev->data->dev_conf.link_speeds &
~ETH_LINK_SPEED_AUTONEG);
hw->mac.get_link_status = true;
if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)
return rte_eth_linkstatus_set(dev, &wu);
gdb定位发现更新函数运行进入了if(intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)逻辑判断,说明此时设备的中断标签已经挂死在了TXGBE_FLAG_NEED_LINK_CONFIG状态。
梳理代码逻辑能对flags做更改的只有两处:
1.txgbe_dev_link_update_share状态有变化且为UP时,去除TXGBE_FLAG_NEED_LINK_CONFIG状态,更新接口属性。
2.接口状态有变化且又为DOWN时,作为光口情况会添加alarm定时器回调,更新macllink状态,并去除中断标签的TXGBE_FLAG_NEED_LINK_CONFIG状态,直接返回link接口。
if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG)
return rte_eth_linkstatus_set(dev, &wu);
/* check if it needs to wait to complete, if lsc interrupt is enabled */
if (wait_to_complete == 0 || dev->data->dev_conf.intr_conf.lsc != 0)
wait = 0;
err = hw->mac.check_link(hw, &link_speed, &link_up, wait);
BP_LOG("link %s\n", link_up ? "up" : "down");
if (err != 0) {
link.link_speed = ETH_SPEED_NUM_100M;
link.link_duplex = ETH_LINK_FULL_DUPLEX;
return rte_eth_linkstatus_set(dev, &link);
}
if (link_up == 0) {
if (hw->subsystem_device_id == TXGBE_DEV_ID_RAPTOR_KR_KX_KX4 ||
hw->subsystem_device_id == TXGBE_DEV_ID_WX1820_KR_KX_KX4) {
hw->mac.bp_down_event(hw);
} else if (hw->phy.media_type == txgbe_media_type_fiber) {
intr->flags |= TXGBE_FLAG_NEED_LINK_CONFIG;
rte_eal_alarm_set(10,
txgbe_dev_setup_link_alarm_handler, dev);
}
return rte_eth_linkstatus_set(dev, &link);
} else if (!hw->dev_start) {
return rte_eth_linkstatus_set(dev, &link);
}
intr->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG;
link.link_status = ETH_LINK_UP;
link.link_duplex = ETH_LINK_FULL_DUPLEX;
结合现象,排除1的可能性,只有2在注定时器回调失败时,直接返回状态才会造成flags标签一直处于TXGBE_FLAG_NEED_LINK_CONFIG状态。
将代码做了修正,添加注册函数返回值处理:
if (link_up == 0) {
if (hw->subsystem_device_id == TXGBE_DEV_ID_RAPTOR_KR_KX_KX4 ||
hw->subsystem_device_id == TXGBE_DEV_ID_WX1820_KR_KX_KX4) {
hw->mac.bp_down_event(hw);
} else if (hw->phy.media_type == txgbe_media_type_fiber) {
intr->flags |= TXGBE_FLAG_NEED_LINK_CONFIG;
err = rte_eal_alarm_set(10,
txgbe_dev_setup_link_alarm_handler, dev);
if ( 0 != err ) {
PMD_INIT_LOG(ERR,"%s[%d] rte_eal_alarm_set failed. err=%d \n",__FUNCTION__,__LINE__,err);
intr->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG;
}
}
return rte_eth_linkstatus_set(dev, &link);
} else if (!hw->dev_start) {
return rte_eth_linkstatus_set(dev, &link);
}
重启运行程序后已未能复现,但会出现log输出,err=-32。
函数rte_eal_alarm_set接口是DPDK库中的一个函数,用于设置定时器事件。该函数允许应用程序在特定的时间点上注册回调函数,以便在达到指定时间时执行特定的操作。
参数说明:
返回值:
为什么rte_eal_alarm_set会出现注册失败情况?
跟踪代码逻辑-32位置,pipe写过程失败了:
/**
* check if need to notify the pipe fd waited by epoll_wait to
* rebuild the wait list.
*/
if (wake_thread)
if (write(intr_pipe.writefd, "1", 1) < 0)
return -EPIPE;
对DPDK的alarm定时器分析:
DPDK中的定时器事件队列是有数量限制的。默认情况下,DPDK的定时器事件队列大小是64。这意味着最多可以同时设置64个定时器事件。
如果频繁使用rte_eal_alarm_set函数来添加回调事件,可能会导致管道无法写入问题。
注: 目前发布的WX版本(手头最高20.11)依然存在此问题,有使用到的道友可以根据自己情况作为参考修改。