【问题定位】DPDK控制下的WX网卡接口在反复操作过程中突然无法UP问题

DPDK控制下的WX网卡接口在反复操作过程中突然无法UP

    • 背景:
    • 环境:
    • 问题分析:
    • 问题原因:

背景:

在测试环境中,频繁对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库中的一个函数,用于设置定时器事件。该函数允许应用程序在特定的时间点上注册回调函数,以便在达到指定时间时执行特定的操作。
参数说明:

  • us:定时器事件的触发时间,以微秒为单位。
  • cb:回调函数,当定时器事件触发时会被调用。
  • arg:传递给回调函数的参数。

返回值:

  • 成功时返回0,表示定时器事件设置成功。
  • 失败时返回负值,表示定时器事件设置失败。

为什么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)依然存在此问题,有使用到的道友可以根据自己情况作为参考修改。

你可能感兴趣的:(linux,驱动开发,嵌入式硬件,网络)