• DPDK 网卡设备scan及probe流程


    本文以X710网卡设备为例,介绍网卡的scan和probe流程的;通过本篇文章的介绍可以大致了解UIO驱动、PMD驱动之间的关联关系以及如何确认网卡对应的PMD驱动的。针对probe流程处理了解的比较片面,有了解比较深的同学,希望能找您学习一下。

    1、BUS总线设备扫描

    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. 1/**
    2. 2 * Helper for Bus registration.
    3. 3 * The constructor has higher priority than PMD constructors.
    4. 4 */
    5. 5#define RTE_REGISTER_BUS(nm, bus) \
    6. 6RTE_INIT_PRIO(businitfn_ ##nm, BUS) \
    7. 7{\
    8. 8  (bus).name = RTE_STR(nm);\
    9. 9  rte_bus_register(&bus); \
    10. 10}
    11. 11RTE_REGISTER_BUS(FSL_DPAA_BUS_NAME, rte_dpaa_bus.bus);/*drivers/bus/dpaa/dpaa_bus.c*/
    12. 12RTE_REGISTER_BUS(FSLMC_BUS_NAME, rte_fslmc_bus.bus)/*drivers/bus/fslmc/fslmc_bus.c*/
    13. 13RTE_REGISTER_BUS(IFPGA_BUS_NAME, rte_ifpga_bus);/*drivers/bus/ifpga/ifpga_bus.c*/
    14. 14RTE_REGISTER_BUS(pci, rte_pci_bus.bus);/*drivers/bus/pci/pci_common.c*/
    15. 15RTE_REGISTER_BUS(vdev, rte_vdev_bus);/*drivers/bus/vdev/vdev.c*/
    16. 16RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);/*drivers/bus/vmbus/vmbus_common.c*/

    网卡设备BUS的注册
    我们重点学习网卡设备的注册,网卡设备bus已经注册到全局变量rte_bus_list链表上。

    1. 1/*网卡bus的全局变量*/
    2. 2struct rte_pci_bus rte_pci_bus = {
    3. 3  .bus = { /*网卡的struct rte_bus设备内容*/
    4. 4    .scan = rte_pci_scan,
    5. 5    .probe = pci_probe,
    6. 6    .find_device = pci_find_device,
    7. 7    .plug = pci_plug,
    8. 8    .unplug = pci_unplug,
    9. 9    .parse = pci_parse,
    10. 10    .dma_map = pci_dma_map,
    11. 11    .dma_unmap = pci_dma_unmap,
    12. 12    .get_iommu_class = rte_pci_get_iommu_class,
    13. 13    .dev_iterate = rte_pci_dev_iterate,
    14. 14    .hot_unplug_handler = pci_hot_unplug_handler,
    15. 15    .sigbus_handler = pci_sigbus_handler,
    16. 16  },
    17. 17  /*实例化网卡设备后下挂到尾队列链表中*/
    18. 18  .device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
    19. 19  /*对应所有网卡的PMD驱动链表,下面重点说一下*/
    20. 20  .driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
    21. 21};
    22. 22/*网卡设备注册*/
    23. 23RTE_REGISTER_BUS(pci, rte_pci_bus.bus);

    下面是通过gdb在全局bus链表上查找到pci设备全局变量注册信息。来打印看一下网卡设备注册后struct rte_bus 内容如下:

    1. 1/*打印对应pci 内容*/
    2. 2(gdb) p rte_bus_list.tqh_first[0].next.tqe_next[0].next.tqe_next[0].next.tqe_next[0]
    3. 3$7 = {
    4. 4  next = {/*双向链表情况*/
    5. 5    tqe_next = 0x399cd40 <rte_vdev_bus>,
    6. 6    tqe_prev = 0x399cb40 <rte_ifpga_bus>
    7. 7  },
    8. 8  name = 0x33f0f9"pci"/*注册时的name*/
    9. 9  scan = 0x485183 <rte_pci_scan>,
    10. 10  probe = 0x489590 <rte_pci_probe>,/*最新的代码是pci_probe*/
    11. 11  find_device = 0x489a35 <pci_find_device>,
    12. 12  plug = 0x489cf8 <pci_plug>,
    13. 13  unplug = 0x489d26 <pci_unplug>,
    14. 14  parse = 0x489835 <pci_parse>,
    15. 15  dma_map = 0x489d90 <pci_dma_map>,
    16. 16  dma_unmap = 0x489e76 <pci_dma_unmap>,
    17. 17  conf = {
    18. 18    scan_mode = RTE_BUS_SCAN_BLACKLIST
    19. 19  },
    20. 20  get_iommu_class = 0x489fc8 <rte_pci_get_iommu_class>,
    21. 21  dev_iterate = 0x488dc0 <rte_pci_dev_iterate>,
    22. 22  hot_unplug_handler = 0x489bd6 <pci_hot_unplug_handler>,
    23. 23  sigbus_handler = 0x489c70 <pci_sigbus_handler>
    24. 24}

    网卡设备scan操作
    在EAL环境初始化函数rte_eal_init()->rte_bus_scan()遍历全局变量rte_bus_list,调用对应bus回调函数scan。

    1. 1int rte_bus_scan(void)
    2. 2{
    3. 3  int ret;
    4. 4  struct rte_bus *bus = NULL;
    5. 5  /*遍历bus链表,执行相应bus的scan函数*/
    6. 6  TAILQ_FOREACH(bus, &rte_bus_list, next) {
    7. 7    ret = bus->scan();
    8. 8    if (ret)
    9. 9      RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
    10. 10        bus->name);
    11. 11  }
    12. 12  return 0;
    13. 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,”的网卡设备。

    1. 1root@domain 0000:00:07.0]# cd /sys/bus/pci/devices/
    2. 2[root@domain devices]# ls /*当前目录的pci设备编码如下*/
    3. 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. 1[root@domain devices]# lspci | grep Eth /*但是只有四个数据以太网卡设备*/
    2. 200:03.0 Ethernet controlle
  • 相关阅读:
    Spring Bean自动装配的简介
    Spring6.0全新发布,快来看看
    PHP代码审计18—PHP代码审计小结
    【JIRA学习】教你如何快速定位与自己相关问题,定制自己的专属工作台。
    Django:四、Djiango如何连接使用MySQL数据库
    vue CSS 实现上下小三角组件(类似表格排序)
    BlueTooth
    Swift async/await 并发中如何将任务组(TaskGroup)转换为异步序列(AsyncSequence)
    mysql日志服务
    采用QTest进行数据集测试-性能测试-GUI测试
  • 原文地址:https://blog.csdn.net/weixin_60043341/article/details/126607259