DPDK之PMD原理

PMD是Poll Mode Driver的缩写,即基于用户态的轮询机制的驱动。本文将介绍PMD的基本原理。

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

图1. 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。在这个函数中,设置PCI的一些操作(如设置PCI BAR、DMA等),不是重点,那是驱动工程师的职责:) 对于PMD来说,重点是与UIO的交互。

1. 调用igbuio_setup_bars,设置uio_info的uio_mem和uio_port。

图2. igbuio_setup_bars

2. 设置uio_info的其他成员

图3. igb_uio设置uio_info

3. 调用uio_register_device,注册uio设备。

查看/dev目录,可以发现对应的uioX设备,如下图:

图4. uio设备

打开uio设备

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

图5. 打开uio设备

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

图6. open uio设备

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

图7. 设置中断信息

图8. 注册中断

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

图9. igb_uio中断处理函数

其中的关键步骤是调用uio_event_notify。

图10. uio_event_notify

这个函数很简单:1. 增加uio设备的“事件”数; 2. 唤醒在idev->wait等待队列中的task;3. 使用信号异步通知async_queue队列中的进程;目前DPDK没有使用异步IO的方式,所有对于DPDK的PMD来说,只有前两个语句有用。

uio模块除了实现了上面的“事件”通知,还支持了mmap方法,用于将注册的uio设备的“内存空间”映射到应用空间。其mmap的函数为uio_mmap,关键代码如下:

图11.uio_mmap

至此,uio已经可以让PMD的应用层访问设备的大部分资源了。接下来,要转过去看看PMD的应用层。

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

图12. 应用层uio初始化

在pci_uio_alloc_resource中,主要是打开dpdk要管理的uio设备

图13. 打开ui设备

同时,DPDK还需要把PCI设备的BAR映射到应用层。在pci_uio_map_resource函数中,除了调用上图中的pci_uio_alloc_resource,还会调用pci_uio_map_resource_by_index做资源映射。

图14. pci_uio_map_resource

下面就是PMD的应用层的驱动实现了。以最简单的e1000驱动为例,在其初始化函数eth_igb_dev_init中,

图15. 注册e1000的中断处理函数

从图11和图12的代码中,可以看出当uio设备有事件时,由eth_igb_interrupt_handler负责处理,实现了用户态的中断处理。

图16. eth_igb_interrupt_handler

eth_igb_interrupt_handler非常简单,只是处理设备的状态变化事件,如link status。

接下来,就是最重要的了,PMD如何读取网卡数据。DPDK的应用代码,会调用rte_eth_rx_burst读取数据报文。

图17.rte_eth_rx_burst

在这个函数中,会调用驱动dev->rx_pkt_burst来做实际的操作。以e1000为例,即eth_igb_recv_pkts。

图18 eth_igb_recv_pkts

图19 eth_igb_recv_pkts

这里的实现很简单。如果网卡接收buffer的描述符表示已经完成一个报文的接收(有E1000_RXD_STAT_DD标志),则rte_mbuf_raw_alloc一个mbuf,进行处理。如果没有报文,直接跳出循环。

对应RTC模型的DPDK应用来说,就是不断的调用rte_eth_rx_burst去“问”网卡是否有新的报文。如果有,就取走所有的报文或达到参数nb_pkts的上限。然后进行报文处理,处理完毕,再次循环。

以上就是PMD的大体流程。

本文分享自微信公众号 - LinuxerPub(LinuxerPub),作者:glinuxer

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • DPDK之PMD原理

    PMD是Poll Mode Driver的缩写,即基于用户态的轮询机制的驱动。本文将介绍PMD的基本原理。

    glinuxer
  • 容器常用虚拟网络接口之一,veth

    现在容器已经得到了广泛使用,用于实现轻量级的虚拟化,资源的隔离等。Docker则是目前应用最广泛的容器实现。而Docker的实现,依赖于Linu...

    glinuxer
  • 细说TCP的MSS选项(2)

    上周因为发烧没办法坚持每“周一”更 —— 再次感叹“每周一更”这个名字,先给大家道声抱歉。

    glinuxer
  • 吴恩达最新深度学习课程: 斯坦福2018—Andrew Ng、Kian Katanforoosh主讲(附PPT)

    【导读】近期,斯坦福大学深度学习课程有开课了,主讲老师是人工智能领域知名学者Andrew Ng和Kian Katanforoosh。我们在早些时候也编辑发布了卡...

    WZEARW
  • Fungal Diversity | 70位作者共同修订真菌界担子菌门分类系统

    担子菌门 (Basidiomycota R.T. Moore 1980)真菌是以食药用菌为代表的大型真菌最主要构成,也包括植物病原菌锈菌和黑粉菌,还有酵母菌等,...

    生信宝典
  • 镁客网每周硬科技领域投融资汇总(12.25-12.30)

    镁客网
  • JAVA笔试题(全解)

    一. Java基础部分................................................................. 9

    阮键
  • javascript当中二维数组用法

    例 1.6(二维数组) <!的用途是那些不支持 JavaScript 的浏览器会把js脚本作为页面的内容来显示。为了防止这种情况发生,可以使用这样的 HTML...

    马克java社区
  • redis.conf配置文件说明

    # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k => 1000 bytes # 1...

    HUC思梦
  • 使用xshell连接linux服务器

    许多新手第一次买了服务器都不知道该怎样使用,尤其是没有接触过linux的朋友对命令行界面几乎不了解,主机笔记今天就记录下使用国外软件xshell连接linux服...

    用户1188347

扫码关注云+社区

领取腾讯云代金券