dpdk-16.11 virtio 驱动初始化卡住问题定位
创始人
2024-02-22 01:58:46

问题描述

qemu 5.1.0 版本 kvm 虚拟化环境中使用 virtio 网卡时,dpdk 程序初始化打印了如下信息后卡住:

..............................................
EAL: PCI device 0000:00:04.0 on NUMA socket -1
EAL:   probe driver: 1af4:1000 rte_virtio_pmd
EAL:   PCI memory mapped at 0x400148000000
EAL:   PCI memory mapped at 0x400148001000

gdb 查看到如下堆栈信息:

(gdb) bt
#0  0x00007ffff75faec4 in modern_set_status () from /lib64/libdpdk.so
#1  0x00007ffff75fb4cd in vtpci_reset () from /lib64/libdpdk.so
#2  0x00007ffff75ff534 in virtio_init_device () from /lib64/libdpdk.so
#3  0x00007ffff75ffe86 in eth_virtio_dev_init () from /lib64/libdpdk.so
..........................................................................,....

堆栈信息表明程序是在 modern_set_status 函数中卡住了,具体原因并不清楚。

信息收集

内核版本信息

3.16.35

qemu 版本

[root@localhost ~]#  /usr/bin/qemu-system-x86_64 --version
QEMU emulator version 5.1.0

接口驱动绑定信息

Network devices using DPDK-compatible driver
============================================
0000:00:04.0 'Virtio network device' drv=igb_uio unused=uio_pci_generic
0000:00:05.0 'Virtio network device' drv=igb_uio unused=uio_pci_generic

网卡正常绑定到 igb_uio 驱动上。

接口 lspci 信息

00:04.0 0200: 1af4:1000Subsystem: 1af4:0001Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx+Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- SERR- BAR=0 offset=00000000 size=00000000Capabilities: [70] Vendor Specific Information: VirtIO: NotifyBAR=4 offset=00003000 size=00001000 multiplier=00000004Capabilities: [60] Vendor Specific Information: VirtIO: DeviceCfgBAR=4 offset=00002000 size=00001000Capabilities: [50] Vendor Specific Information: VirtIO: ISRBAR=4 offset=00001000 size=00001000Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfgBAR=4 offset=00000000 size=00001000Kernel driver in use: igb_uio

lspci 信息未见明显异常。

程序 pmap 信息

程序映射的 resource 信息如下:

0000600009e00000      4K rw-s- /sys/devices/pci0000:00/0000:00:04.0/resource1
0000600009e01000     16K rw-s- /sys/devices/pci0000:00/0000:00:04.0/resource4

对照测试

dpdk 示例程序 l2fwd 测试

测试结论:
同样卡住,堆栈与产品程序 一致,日志记录如下:

(gdb) bt
#0  0x00000000004f1184 in modern_set_status ()
#1  0x00000000004f178d in vtpci_reset ()
#2  0x00000000004f57f4 in virtio_init_device ()
#3  0x00000000004f6146 in eth_virtio_dev_init ()
...................................................

高版本 l2fwd 程序测试

编译 dpdk-19.11 版本 l2fwd 测试,现象相同。

官方驱动测试

能够正常绑定到 virtio-pci 驱动中,表明问题出在 dpdk 驱动上。

排查内容

1. dmesg 信息

虚拟机 dmesg 信息未见异常,宿主机 dmesg 信息未见异常。

2. 关闭 iommu

关闭后问题仍旧存在

源码分析

modern_set_status 函数源码如下:

static void
modern_set_status(struct virtio_hw *hw, uint8_t status)
{io_write8(status, &hw->common_cfg->device_status);
}

它的功能是写入 virtio 网卡寄存器,设定虚拟网卡状态。执行 io_write8 函数写入的时候卡住表明问题出在虚拟网卡 pci resource 空间访问上,确认代码逻辑中此处为第一次访问网卡寄存器,表明映射的虚拟网卡寄存器空间不可访问,怀疑问题可能与 qemu 版本有关。

卡住的现象到底是怎样的?

gdb 查看卡住是的寄存器信息与函数返汇编代码如下:

(gdb) info registers
rax            0x600009e01000   105553281945600
rbx            0x60000501f100   105553200279808
rcx            0x0      0
rdx            0x3      3
rsi            0x0      0
rdi            0x60000501f100   105553200279808
rbp            0x29cb1f0        0x29cb1f0
rsp            0x7fffffffdd48   0x7fffffffdd48
r8             0x1      1
r9             0xfeff7efdff336462       -72199439641254814
r10            0x7fffffffdb20   140737488345888
r11            0x7ffff75fb4c0   140737343632576
r12            0x29cb1f0        43823600
r13            0x60000501f1c0   105553200280000
r14            0x60000501f100   105553200279808
r15            0x74fcd0 7666896
rip            0x7ffff75faec4   0x7ffff75faec4 
eflags         0x3246   [ PF ZF IF #12 #13 ]
cs             0x33     51
ss             0x2b     43
....................................................................
(gdb) disass
Dump of assembler code for function modern_set_status:0x00007ffff75faec0 <+0>:     mov    0x40(%rdi),%rax
=> 0x00007ffff75faec4 <+4>:     mov    %sil,0x14(%rax)0x00007ffff75faec8 <+8>:     retq
End of assembler dump.

可以确定是在访问 resource4 virtio bar 空间的时候卡住,仅仅影响当前进程,其它进程仍旧能够正常运行。有这个现象,我比较怀疑是 qemu 本身的问题,但是解释不了为什么官方驱动能够正常工作,还需要继续定位。

思考

内核驱动与 dpdk 驱动访问网卡的 pci resource bar 空间都需要经过地址映射,dpdk 中通过 mmap resource 文件来映射地址,这个操作我判断大概率不会存在差别,毕竟 resource 文件也是内核探测 pci 设备的时候配置的,出问题的概率非常小。

从现象上来看比较像是在用户态无法访问,但是一般来说在虚拟机中访问 virtio resource bar 空间在 qemu 中的行为应当是一致的,不应该出现内核能访问,用户态程序无法访问的问题,毕竟 qemu 并不区分虚拟机中的内核与用户态程序,而且其实内核与用户态程序只是分时执行代码,qemu 侧不应该有这个区别。

阅读内核代码

由于我对内核 virtio-pci、virtio-net 这部分代码的实现并不清楚,既然内核代码能够工作,那需要先研究下内核代码的逻辑,一定是这个过程与 dpdk 驱动的执行过程有区别才造成了不同的结果

阅读 3.16.35 内核的代码,发现它的 virtio-pci 驱动并不支持 virtio modern,只支持 virtio legacy 这种访问方式。

在这种访问方式下,它设置 virtio 网卡 status 寄存器使用如下代码:

static void vp_reset(struct virtio_device *vdev)
{struct virtio_pci_device *vp_dev = to_vp_device(vdev);/* 0 status means a reset. */iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);/* Flush out the status write, and flush in device writes,* including MSi-X interrupts, if any. */ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);/* Flush pending VQ/configuration callbacks. */vp_synchronize_vectors(vdev);
}

而我们使用的 dpdk virtio 驱动支持 virtio modern 设备,reset virtio 网卡通过读写 virtio resource bar4 中 CommonCfg 处的空间来进行 virtio 网卡的 reset。

修改 dpdk virtio 驱动,使用 legacy 模式访问 virtio 网卡寄存器

将 vtpci_init 函数修改为如下逻辑:

				#if 0if (virtio_read_caps(dev, hw) == 0) {PMD_INIT_LOG(INFO, "modern virtio pci detected.");hw->vtpci_ops = &modern_ops;hw->modern    = 1;*dev_flags |= RTE_ETH_DEV_INTR_LSC;return 0;}#endifPMD_INIT_LOG(INFO, "trying with legacy virtio pci.");if (legacy_virtio_resource_init(dev, hw, dev_flags) < 0) {if (dev->kdrv == RTE_KDRV_UNKNOWN) {PMD_INIT_LOG(INFO,"skip kernel managed virtio device.");return 1;}return -1;}

临时注掉了使用 virtio modern pci ops 的逻辑,改为使用 legacy pci ops,重新编译 l2fwd 能够正常初始化。
l2fwd 运行打印了如下与 virtio 驱动相关的信息:

EAL: PCI device 0000:00:04.0 on NUMA socket -1
EAL:   probe driver: 1af4:1000 rte_virtio_pmd
EAL: PCI Port IO found start=0xc180
EAL: PCI device 0000:00:05.0 on NUMA socket -1
EAL:   probe driver: 1af4:1000 rte_virtio_pmd
EAL: PCI Port IO found start=0xc1a0

dpdk 驱动对 virtio modern 设备会先尝试使用 modern pci ops 的方法读写网卡寄存器,当尝试失败后再继续尝试 legacy pci ops,这个顺序并不能调整,如果将 legacy pci ops 尝试放到前面,那一些 virtio modern 网卡就不能使用 modern pci ops 来读写网卡寄存器,性能会下降。

从现象上表明问题出在 qemu 上,可能是某种兼容性问题,可以尝试通过升级 qemu 版本解决。

能否修改 qemu 启动参数指定使用 virtio-legacy 设备?

异常 kvm VM qemu 启动参数中 virtio 网卡相关内容如下:

-device virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:5e:90:1a,bus=pci.0,addr=0x4 -netdev tap,fd=48,id=hostnet2,vhost=on,vhostfd=49 -device virtio-net-pci,netdev=hostnet2,id=net2,mac=52:54:00:af:a8:c9,bus=pci.0,addr=0x5

配置上没有发现有啥异常,网上搜索到可以设置 disable-modern=‘off’ 参数,但是我们的虚拟机配置是通过 virt-manager 生成的,一通搜索与尝试确定 libvirtio 不支持强制设置 virtio 设备为 legacy 模式。

参考链接

virtio_net 与 virtio-pci 驱动关联浅析

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...