dpdk 版本信息
dpdk-19.11
lsc 中断
lsc 中断全称为链路状态改变中断,当网卡的链路状态发生改变(down -> up、up->down)时会触发此中断调用中断处理函数更新链路状态。
dpdk 支持配置使能网卡的 lsc 中断,rte_eth_conf 结构的 intr_conf 字段用于配置 lsc 及收发包中断,lsc 中断缺省为关闭状态。
intr_conf 字段的定义如下:
struct rte_eth_intr_conf {
/** enable/disable lsc interrupt. 0 (default) - disable, 1 enable */
uint32_t lsc:1;
/** enable/disable rxq interrupt. 0 (default) - disable, 1 enable */
uint32_t rxq:1;
/** enable/disable rmv interrupt. 0 (default) - disable, 1 enable */
uint32_t rmv:1;
};
当设置 lsc 字段为 1 时,dpdk 会使能网卡 lsc 中断。
lsc 中断的触发过程(以 ixgbe 网卡驱动与 igb_uio 为例)
当网卡状态改变时,硬件中断触发,首先进入到内核的中断处理函数中,根据中断向量表查询到 igb_uio 模块注册的中断回调 igbuio_pci_irqhandler 函数并调用此函数处理中断。
igbuio_pci_irqhandler 主要功能是调用 uio_event_notify 函数唤醒监听 /dev/uioX 事件的进程投递中断到用户态。用户态根据 fd 将中断投递到网卡驱动 probe 阶段注册的中断回调中,此回调在网卡驱动 probe 过程中被注册,ixgbe 的实现代码如下:
rte_intr_callback_register(intr_handle,
ixgbe_dev_interrupt_handler, eth_dev);
ixgeb_dev_interrupt_handler 回调函数通过读取中断相关寄存器分发中断到不同的处理逻辑中,主要有如下两个步骤:
- 读取中断状态寄存器并保存
- 判断状态并执行具体的中断处理流程
ixgbe 网卡的 lsc 中断处理过程如下:
if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
struct rte_eth_link link;
/* get the link status before link update, for predicting later */
rte_eth_linkstatus_get(dev, &link);
ixgbe_dev_link_update(dev, 0);
/* likely to up */
if (!link.link_status)
/* handle it 1 sec later, wait it being stable */
timeout = IXGBE_LINK_UP_CHECK_TIMEOUT;
/* likely to down */
else
/* handle it 4 sec later, wait it being stable */
timeout = IXGBE_LINK_DOWN_CHECK_TIMEOUT;
ixgbe_dev_link_status_print(dev);
if (rte_eal_alarm_set(timeout * 1000,
ixgbe_dev_interrupt_delayed_handler, (void *)dev) < 0)
PMD_DRV_LOG(ERR, "Error setting alarm");
else {
/* remember original mask */
intr->mask_original = intr->mask;
/* only disable lsc interrupt */
intr->mask &= ~IXGBE_EIMS_LSC;
}
}
上述代码在判断到 lsc 中断标志后,调用 ixgbe_dev_link_update 函数访问网卡硬件获取实际的链路状态,同时为了避免抖动,增加了延时检测的逻辑,当延时检测完成后才会重新开启 lsc 中断,避免中断重入问题。
开关 lsc 中断的影响与可能存在的问题
dpdk 内部调用 rte_eth_link_get_nowait 函数来获取接口的 up、down 状态,此接口判断网卡使能 lsc 中断的状态,有如下两种执行逻辑:
1. 使能 lsc 中断的情况
如果使能了 lsc——link status change 中断,则直接原子读取 dev 中的 data->dev_link 成员向上层返回网卡的 down、up 状态。此时网卡 link 状态只在 dpdk 捕获到 lsc 中断并调用相应地中断回调函数时才会更新。
2. 未使能 lsc 中断的情况
如果没有使用 lsc 中断,则调用 pmd 驱动中实现的 dev_ops->link_update 函数来完成。 此时,每次获取网卡的 down、up 状态都会读取网卡硬件寄存器,dpdk 程序定时轮询获取网卡物理状态。
使能 lsc 中断潜在的问题
当接口开启 lsc 中断时,此函数只读取当前接口的软件状态,当关闭 lsc 中断时它才会真正读取寄存器获取硬件真实状态。这里状态的同步由网卡注册的 lsc 中断回调来完成,捕获到 lsc 中断后,网卡中断回调被调用,中断直接调用网卡驱动实现的 link_update 虚函数来获取真实的网卡状态并更新到相应的数据结构中。
当 lsc 中断上报不及时、没有上报时,上层程序获取到的链路状态将一直得不到更新,此时就会造成问题。
是否要开启 lsc 中断?
尽管 lsc 中断有上文提到的潜在问题,该问题也仅在特定的网卡及驱动实现中出现,并不影响正常的使用。一般来说建议开启 lsc,这样仅在中断触发的时候检测硬件状态并更新相关字段,避免了持续周期性轮询网卡硬件状态带来的额外负载。