dpdk PMD

本文详细介绍了DPDK中的PMD(Poll Mode Driver)工作原理,特别是在不使用vfio的情况下,如何通过uio模块与内核交互。内容包括PMD结构图,uio设备的打开过程,以及中断处理。当DPDK应用启动时,EAL初始化期间会进行设备驱动注册和PCI设备的匹配,映射资源,并设置收发包函数。文中还提及了DPDK的设备驱动注册机制和中断模式MSIX。
摘要由CSDN通过智能技术生成

PMD是Poll Mode Driver的缩写,即基于用户态的轮询机制的驱动

在不考虑vfio的情况下,PMD的结构图如下

   虽然PMD是在用户态实现设备驱动,但还是依赖于内核提供的策略。其中uio模块,是内核提供的用户态驱动框架,而igb_uio是DPDK kit中拥有与uio交互,bind指定网卡的内核模块;

  当使用DPDK脚本dpdk-devbind来bind网卡时,会通过sysfs与内核交互,让内核使用指定驱动来匹配网卡。具体的行为向/sys/bus/pci/devices/(pci id)/driver_override写入指定驱动名称,或者向/sys/bus/pci/drivers/igb_uio(驱动名称)/new_id写入要绑定网卡的PCI ID。前者是配置设备,让其选择驱动。后者是是配置驱动,让其支持新的PCI设备。按照内核的文档https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci,这两个动作都会促使驱动bind新设备。

  但是在dpdk-devbind脚本中,还是通过向/sys/bus/pci/drivers/igb_uio(驱动名称)/bind写入pci id来保证bind;

  当使用igb_uio bind指定设备后,内核会调用igb_uio注册的struct pci_driver的probe函数,即igbuio_pci_probe;

其会调用uio_register_device,注册uio设备

打开uio设备

 应用层DPDK已经可以使用uio设备了。DPDK的应用层代码,会打开uioX设备,在函数pci_uio_alloc_resource中;

   当open对应的uio设备时,对应的内核操作为uio_open,其又会调用igb_uio的open函数,流程图如下

 

 igb_uio的默认中断模式为RTE_INTR_MODE_MSIX,在igbuio_pci_enable_interrupts的关键代码如下

static int
igbuio_pci_enable_interrupts(struct rte_uio_pci_dev *udev)
{
    int err = 0;

    switch (igbuio_intr_mode_preferred) {
    case RTE_INTR_MODE_MSIX:
        /* Only 1 msi-x vector needed */
#ifndef HAVE_ALLOC_IRQ_VECTORS
        msix_entry.entry = 0;
        if (pci_enable_msix(udev->pdev, &msix_entry, 1) == 0) {
            dev_dbg(&udev->pdev->dev, "using MSI-X");
            udev->info.irq_flags = IRQF_NO_THREAD;
            udev->info.irq = msix_entry.vector;
            udev->mode = RTE_INTR_MODE_MSIX;
            break;
        }
#else
        if (pci_alloc_irq_vectors(udev->pdev, 1, 1, PCI_IRQ_MSIX) == 1) {
            dev_dbg(&udev->pdev->dev, "using MSI-X");
            udev->info.irq_flags = IRQF_NO_THREAD;
            udev->info.irq = pci_irq_vector(udev->pdev, 0);
            udev->mode = RTE_INTR_MODE_MSIX;
            break;
        }
#endif

default:
        dev_err(&udev->pdev->dev, "invalid IRQ mode %u",
            igbuio_intr_mode_preferred);
        udev->info.irq = UIO_IRQ_NONE;
        err = -EINVAL;
    }

    if (udev->info.irq != UIO_IRQ_NONE)
        err = request_irq(udev->info.irq, igbuio_pci_irqhandler,
                  udev->info.irq_flags, udev->info.name,
                  udev);
    dev_info(&udev->pdev->dev, "uio device registered with irq %ld\n",
         udev->info.irq);

    return err;
}

   当打开uio设备时,igb_uio注册了一个中断。这时大家应该有个疑问,PMD不是用户态轮询设备吗?为什么还要申请中断,注册中断处理函数呢?这是因为,即使应用层可以通过uio来实现设备驱动,但是设备的某些事件还是需要内核进行响应,然后通知应用层;相当于中断的上半部 和下半部

 上半部中断服务函数: 主要通知一个event到user比如: 唤醒在idev->wait等待队列中的task

/**
 * This is interrupt handler which will check if the interrupt is for the right device.
 * If yes, disable it here and will be enable later.
 */
static irqreturn_t
igbuio_pci_irqhandler(int irq, void *dev_id)
{
    struct rte_uio_pci_dev *udev = (struct rte_uio_pci_dev *)dev_id;
    struct uio_info *info = &udev->info;

    /* Legacy mode need to mask in hardware */
    if (udev->mode == RTE_INTR_MODE_LEGACY &&
        !pci_check_and_mask_intx(udev->pdev))
        return IRQ_NONE;

    uio_event_notify(info);

    /* Message signal mode, no share IRQ and automasked */
    return IRQ_HANDLED;
}

当DPDK的app启动时,会进行EAL初始化,如下图:

 

以ixgbe驱动为例详细说明:

学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂
更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,久学习,或点击这里加qun免费
领取,关注我持续更新哦! !  

RTE_PMD_REGISTER_PCI(net_ixgbe, rte_ixgbe_pmd);

#define RTE_PMD_EXPORT_NAME(name, idx) \
static const char RTE_PMD_EXPORT_NAME_ARRAY(this_pmd_name, idx) \
__attribute__((used)) = RTE_STR(name)

/** Helper for PCI device registration from driver (eth, crypto) instance */
#define RTE_PMD_REGISTER_PCI(nm, pci_drv) \
RTE_INIT(pciinitfn_ ##nm) \
{\
    (pci_drv).driver.name = RTE_STR(nm);\
    rte_pci_register(&pci_drv); \
} \
RTE_PMD_EXPORT_NAME(nm, __COUNTER__)

/* register a driver */
void
rte_pci_register(struct rte_pci_driver *driver)
{
    TAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, driver, next);
    driver->bus = &rte_pci_bus;
}

    RTE_PMD_REGISTER_PCI为dpdk定义的宏,使用了GNU C提供的“__attribute__(constructor)”机制,使得注册设备驱动的过程在main函数执行之前完成。 
  这样就有了设备驱动类型、设备驱动的初始化函数

 使用attribute的constructor属性,在MAIN函数执行前,就执行pmd_driver_register()函数,将pmd_igb_drv驱动挂到全局dev_driver_list链表上。

2、通过读取/sys/bus/pci/devices/目录下的信息,扫描当前系统的PCI设备,并初始化,并按照PCI地址从大到小的顺序挂在到pci_debice_list上。

3、rte_bus_probe

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值