本文基于DPDK-1.8.0分析。
网卡驱动模型一般包含三层,即,PCI总线设备、网卡设备以及网卡设备的私有数据结构,即将设备的共性一层层的抽象,PCI总线设备包含网卡设备,网卡设备又包含其私有数据结构。在DPDK中,首先会注册设备驱动,然后查找当前系统有哪些PCI设备,并通过PCI_ID为PCI设备找到对应的驱动,最后调用驱动初始化设备。
一、网卡驱动注册
以e1000网卡驱动为例说明。
在1.8.0版本中,网卡驱动的注册使用了一种奇技淫巧的方法,使用GCC attribute扩展属性的constructor属性,使得网卡驱动的注册在程序MAIN函数之前就执行了。
static struct rte_driver pmd_igb_drv = { .type = PMD_PDEV, .init = rte_igb_pmd_init, }; static struct rte_driver pmd_igbvf_drv = { .type = PMD_PDEV, .init = rte_igbvf_pmd_init, }; PMD_REGISTER_DRIVER(pmd_igb_drv); PMD_REGISTER_DRIVER(pmd_igbvf_drv);
其中PMD_REGISTER_DRIVER()宏的定义如下:
#define PMD_REGISTER_DRIVER(d)\ void devinitfn_ ##d(void);\ void __attribute__((constructor, used)) devinitfn_ ##d(void)\ {\ rte_eal_driver_register(&d);\ }
使用attribute的constructor属性,在MAIN函数执行前,就执行rte_eal_driver_register()函数,将pmd_igb_drv驱动挂到全局dev_driver_list链表上。
二、扫描当前系统有哪些PCI设备
调用rte_eal_init()--->rte_eal_pci_init()函数,查找当前系统中有哪些网卡,分别是什么类型,并将它们挂到全局链表pci_device_list上。
1、首先初始化全局链表pci_driver_list、pci_device_list。用于挂载PCI驱动及PCI设备。
2、pci_scan()通过读取/sys/bus/pci/devices/目录下的信息,扫描当前系统的PCI设备,并初始化,并按照PCI地址从大到小的顺序挂在到pci_debice_list上。
int rte_eal_pci_init(void) { TAILQ_INIT(&pci_driver_list); TAILQ_INIT(&pci_device_list); pci_res_list = RTE_TAILQ_RESERVE_BY_IDX(RTE_TAILQ_PCI, mapped_pci_res_list); /* for debug purposes, PCI can be disabled */ if (internal_config.no_pci) return 0; if (pci_scan() < 0) { RTE_LOG(ERR, EAL, "%s(): Cannot scan PCI bus\n", __func__); return -1; } #ifdef VFIO_PRESENT pci_vfio_enable(); if (pci_vfio_is_enabled()) { /* if we are primary process, create a thread to communicate with * secondary processes. the thread will use a socket to wait for * requests from secondary process to send open file descriptors, * because VFIO does not allow multiple open descriptors on a group or * VFIO container. */ if (internal_config.process_type == RTE_PROC_PRIMARY && pci_vfio_mp_sync_setup() < 0) return -1; } #endif return 0; }www.sczygb.com/点击打开链接