本文以X710网卡设备为例,介绍网卡的scan和probe流程的;通过本篇文章的介绍可以大致了解UIO驱动、PMD驱动之间的关联关系以及如何确认网卡对应的PMD驱动的。针对probe流程处理了解的比较片面,有了解比较深的同学,希望能找您学习一下。
ret_bus_scan函数在目录dpdk/lib/librte_eal/common/eal_common_bus.c
初始化流程在EAL环境初始化调用 ret_bus_scan函数完成的。内部会调用各自类型的bus->scan接口;目的是扫描所有该类型bus下注册的设备。
下面有bus设备注册、以PCI设备的注册来详细说明注册流程。
1.1 Bus设备的注册
是由宏RTE_REGISTER_BUS,是一个构造函数,在程序main启动前完成的注册;将bus类型注册到全局结构rte_bus_list 链表上;目前有6中设备类型,本文主要关心网卡设备的。目前查询宏使用的地方如下。(对应宏所在文件:dpdk/lib/librte_eal/include/rte_bus.h)
- 1/**
- 2 * Helper for Bus registration.
- 3 * The constructor has higher priority than PMD constructors.
- 4 */
- 5#define RTE_REGISTER_BUS(nm, bus) \
- 6RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
- 7{\
- 8 (bus).name = RTE_STR(nm);\
- 9 rte_bus_register(&bus); \
- 10}
- 11RTE_REGISTER_BUS(FSL_DPAA_BUS_NAME, rte_dpaa_bus.bus);/*drivers/bus/dpaa/dpaa_bus.c*/
- 12RTE_REGISTER_BUS(FSLMC_BUS_NAME, rte_fslmc_bus.bus)/*drivers/bus/fslmc/fslmc_bus.c*/
- 13RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus);/*drivers/bus/ifpga/ifpga_bus.c*/
- 14RTE_REGISTER_BUS(pci, rte_pci_bus.bus);/*drivers/bus/pci/pci_common.c*/
- 15RTE_REGISTER_BUS(vdev, rte_vdev_bus);/*drivers/bus/vdev/vdev.c*/
- 16RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);/*drivers/bus/vmbus/vmbus_common.c*/
网卡设备BUS的注册
我们重点学习网卡设备的注册,网卡设备bus已经注册到全局变量rte_bus_list链表上。
- 1/*网卡bus的全局变量*/
- 2struct rte_pci_bus rte_pci_bus = {
- 3 .bus = { /*网卡的struct rte_bus设备内容*/
- 4 .scan = rte_pci_scan,
- 5 .probe = pci_probe,
- 6 .find_device = pci_find_device,
- 7 .plug = pci_plug,
- 8 .unplug = pci_unplug,
- 9 .parse = pci_parse,
- 10 .dma_map = pci_dma_map,
- 11 .dma_unmap = pci_dma_unmap,
- 12 .get_iommu_class = rte_pci_get_iommu_class,
- 13 .dev_iterate = rte_pci_dev_iterate,
- 14 .hot_unplug_handler = pci_hot_unplug_handler,
- 15 .sigbus_handler = pci_sigbus_handler,
- 16 },
- 17 /*实例化网卡设备后下挂到尾队列链表中*/
- 18 .device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
- 19 /*对应所有网卡的PMD驱动链表,下面重点说一下*/
- 20 .driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
- 21};
- 22/*网卡设备注册*/
- 23RTE_REGISTER_BUS(pci, rte_pci_bus.bus);
下面是通过gdb在全局bus链表上查找到pci设备全局变量注册信息。来打印看一下网卡设备注册后struct rte_bus 内容如下:
- 1/*打印对应pci 内容*/
- 2(gdb) p rte_bus_list.tqh_first[0].next.tqe_next[0].next.tqe_next[0].next.tqe_next[0]
- 3$7 = {
- 4 next = {/*双向链表情况*/
- 5 tqe_next = 0x399cd40 <rte_vdev_bus>,
- 6 tqe_prev = 0x399cb40 <rte_ifpga_bus>
- 7 },
- 8 name = 0x33f0f9f "pci", /*注册时的name*/
- 9 scan = 0x485183 <rte_pci_scan>,
- 10 probe = 0x489590 <rte_pci_probe>,/*最新的代码是pci_probe*/
- 11 find_device = 0x489a35 <pci_find_device>,
- 12 plug = 0x489cf8 <pci_plug>,
- 13 unplug = 0x489d26 <pci_unplug>,
- 14 parse = 0x489835 <pci_parse>,
- 15 dma_map = 0x489d90 <pci_dma_map>,
- 16 dma_unmap = 0x489e76 <pci_dma_unmap>,
- 17 conf = {
- 18 scan_mode = RTE_BUS_SCAN_BLACKLIST
- 19 },
- 20 get_iommu_class = 0x489fc8 <rte_pci_get_iommu_class>,
- 21 dev_iterate = 0x488dc0 <rte_pci_dev_iterate>,
- 22 hot_unplug_handler = 0x489bd6 <pci_hot_unplug_handler>,
- 23 sigbus_handler = 0x489c70 <pci_sigbus_handler>
- 24}
网卡设备scan操作
在EAL环境初始化函数rte_eal_init()->rte_bus_scan()遍历全局变量rte_bus_list,调用对应bus回调函数scan。
- 1int rte_bus_scan(void)
- 2{
- 3 int ret;
- 4 struct rte_bus *bus = NULL;
- 5 /*遍历bus链表,执行相应bus的scan函数*/
- 6 TAILQ_FOREACH(bus, &rte_bus_list, next) {
- 7 ret = bus->scan();
- 8 if (ret)
- 9 RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
- 10 bus->name);
- 11 }
- 12 return 0;
- 13}
网卡设备调用rte_pci_scan(),函数的大致意思是打开并扫描目录“/sys/bus/pci/devices”下的PCI设备;一个目录名称表示一个pci设备;根据我们设置的网卡黑名单或白名单进行过滤,符合条件的设备,调用pci_scan_one实例化网卡设备rte_pci_device,并进行一些数据的填充(rte_pci_addr(网卡pci编号),struct rte_pci_id (网卡身份信息vendor_id、device_id来确定使用那个网卡驱动)max_vfs(sriov支持最大数量)、numa_node)。
pci_scan_one 函数只是实例化网卡设备并填充网卡的一些基本信息,并没有申请相应的资源,资源是由函数rte_bus_probe完成的。下面大概说一下具体操作流程。
1、打开目录并扫描目录“/sys/bus/pci/devices,”的网卡设备。
- 1root@domain 0000:00:07.0]# cd /sys/bus/pci/devices/
- 2[root@domain devices]# ls /*当前目录的pci设备编码如下*/
- 30000:00:00.0 0000:00:01.0 0000:00:01.1 0000:00:01.2 0000:00:01.3 0000:00:02.0 0000:00:03.0 0000:00:04.0 0000:00:05.0 0000:00:06.0 0000:00:07.0 0000:00:08.0
2、通过lspci | grep Eth ,我们可以知道哪些是Eth网卡设备
- 1[root@domain devices]# lspci | grep Eth /*但是只有四个数据以太网卡设备*/
- 200:03.0 Ethernet controlle