DPDK 收发包处理流程(一)(网卡驱动注册)

本文基于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;
}

pcai_scan()通过读取/sys/bus/pci/devices/目录下相关PCI设备的如下文件,获取对应的信息,初始化struct rte_pci_device数据结构,并将其按照PCI地址从大到小的顺序挂到pci_device_list链表上。

复制代码
struct rte_pci_device {
        TAILQ_ENTRY(rte_pci_device) next;       /**< Next probed PCI device. */
        struct rte_pci_addr addr;               /**< PCI location. */
        struct rte_pci_id id;                   /**< PCI ID. */
        struct rte_pci_resource mem_resource[PCI_MAX_RESOURCE];   /**< PCI Memory Resource */
        struct rte_intr_handle intr_handle;     /**< Interrupt handle */
        const struct rte_pci_driver *driver;    /**< Associated driver */
        uint16_t max_vfs;                       /**< sriov enable if not zero */
        int numa_node;                          /**< NUMA node connection */
        struct rte_devargs *devargs;            /**< Device user arguments */
};
复制代码
复制代码
root@Ubuntu:~# ls -ltr /sys/bus/pci/devices/0000\:00\:09.0/
total 0
-rw-r--r-- 1 root root   4096 Nov 15 12:18 uevent
lrwxrwxrwx 1 root root      0 Nov 15 12:18 subsystem -> ../../../bus/pci
-r--r--r-- 1 root root   4096 Nov 15 12:19 class
-r--r--r-- 1 root root   4096 Nov 15 12:19 vendor
-r--r--r-- 1 root root   4096 Nov 15 12:19 device
-rw-r--r-- 1 root root    256 Nov 15 12:19 config
-r--r--r-- 1 root root   4096 Nov 15 12:19 local_cpus
-r--r--r-- 1 root root   4096 Nov 15 12:19 irq
-r--r--r-- 1 root root   4096 Nov 15 12:20 resource
drwxr-xr-x 2 root root      0 Nov 15 12:20 power
-r--r--r-- 1 root root   4096 Nov 19 14:33 subsystem_vendor
-r--r--r-- 1 root root   4096 Nov 19 14:33 subsystem_device
-r--r--r-- 1 root root   4096 Nov 19 14:33 numa_node
-rw------- 1 root root      8 Nov 19 14:58 resource2
-rw------- 1 root root 131072 Nov 19 14:58 resource0
--w------- 1 root root   4096 Nov 19 14:58 reset
--w--w---- 1 root root   4096 Nov 19 14:58 rescan
--w--w---- 1 root root   4096 Nov 19 14:58 remove
-rw-r--r-- 1 root root   4096 Nov 19 14:58 msi_bus
-r--r--r-- 1 root root   4096 Nov 19 14:58 modalias
-r--r--r-- 1 root root   4096 Nov 19 14:58 local_cpulist
-rw------- 1 root root   4096 Nov 19 14:58 enable
-r--r--r-- 1 root root   4096 Nov 19 14:58 dma_mask_bits
-r--r--r-- 1 root root   4096 Nov 19 14:58 consistent_dma_mask_bits
-rw-r--r-- 1 root root   4096 Nov 19 14:58 broken_parity_status
drwxr-xr-x 3 root root      0 Nov 19 15:31 uio
lrwxrwxrwx 1 root root      0 Nov 19 15:31 driver -> ../../../bus/pci/drivers/igb_uio
-rw-r--r-- 1 root root   4096 Nov 19 15:32 max_vfs
复制代码

目录名:就是PCI设备的地址,记录在struct rte_pci_addr数据结构中。

vendor文件:获取PCI_ID.vendor_id。

device文件:获取PCI_ID.device_id。

subsystem_vendor文件:获取PCI_ID.subsystem_vendor_id。

subsystem_device文件:获取PCI_ID.subsystem_device_id。

numa_node文件:获取PCI设备属于哪个CPU socket。

resource文件:获取PCI设备的在地址总线上的物理地址,以及物理地址空间的大小,记录在struct rte_pci_resouce数据结构中。

你可能感兴趣的:(dpdk,网卡驱动)