• DPDK原理探索: igb_uio


    我们知道,DPDK的核心特性在于绕开内核对网卡设备进行操作,而要实现这一点,DPDK采用的是Linux内核提供的UIO框架,并且对其进行封装,最终暴露给用户的东西就是——igb_uio

    0.0 什么是igb_uio

    igb_uio本质上是一个驱动(driver)。它是以一个内核模块的形式被加入到内核中的。我们使用的insmod命令其实就是一个插入内核模块(kernel module)的工具。

    igb_uio的初始化:

    模块初始化

    可以看到,igb_uio的初始化是通过igbuio_pci_init_module来实现的,而这个函数又是怎么被调用的呢?事实上,在igb_uio内核模块被插入时,就会触发上图中module_init所设置的初始化回调函数。

    igb_uio初始化回调函数

    igbuio_pci_init_module函数中,我们关心的是pci_register_driver函数,该函数将igbuio_pci_driver向内核中进行注册。同时,在igbuio_pci_driver结构体中,还有一个id_table的字段,它是一个struct pci_device_id数组,表示当前驱动所管理的所有设备。在pci_register_driver函数中,会调用probe回调函数去探测所有设备。但特殊的是,igb_uio在初始化时是没有管理任何设备的,即id_table数组为空。

    奇怪了,显然igb_uio的驱动是需要管理网卡设备的,但是我们这里又没有任何驱动可以被探测到,那我们的网卡设备是什么时候被加入到igb_uio驱动的管理中的呢?

    答案就是DPDK提供的usertools/dpdk-devbind.py脚本,这个脚本可以将某个网卡设备绑定为igb_uio驱动下的网卡设备,而绑定之后,就可以触发probe回调函数探测这个新的网卡设备,探测成功后,我们的新网卡就进入了igb_uio的设备数组中。

    1.0igb_uio的设备探测过程:

    igbuio_pci_probe函数中, 完成的主要工作有五个:

    1. 使能当前设备,即通过pci_enable_device(dev)函数enable当前设备
    2. igbuio_setup_bars,该函数的功能是将当前设备的所有PCI BAR的全部信息读取到struct uio_info结构体中,后续注册UIO设备时需要使用
    3. 设置DMA模式
    4. 初始化UIO设备的File Operations,即openreleaseirqcontrol
    5. 通过uio_register_device函数将当前设备注册为UIO设备。

    1.1 PCI BAR设备信息的读取:

    事实上,一个PCI设备通常有6个PCI BAR,这些PCI BAR在内核中被称为resource。而每一个PCI BAR都有各自的类型和物理地址。其中,类型有两种,一种是Memory类型的资源,另一种是I/O Port

    PCI BAR的数据读取

    其中,对于IORESOURCE_MEM类型,通过igbuio_pci_setup_iomem函数进行读取,而对于IORESOURCE_IO类型,通过igbuio_pci_setup_ioport来进行读取。

    那么,到底是什么PCI BAR呢?BAR的全称是Base Address Register,它是一个存储基地址的寄存器。在PCI设备内部的内存布局是这样的:

    PCI内存布局

    而每个BAR的数据分布如下:

    每一个PCI BAR的数据分布

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

    1.1.0 igbuio_pci_setup_iomem的过程:

    igbuio_pci_setup_iomem函数中,通过pci_resource_start内核函数可以获取当前PCI BAR的物理地址起点,而通过pci_resource_len可以获取当前PCI BAR的物理地址长度。

    IORESOURCE_MEM类型的PCI BAR

    在上图中,最后方框标注的部分,就是将我们所读取到的PCI BAR的数据存入struct uio_info结构体中,以供后面注册UIO设备时使用。

    值得一提的是,internal_addr其实在DPDK中是没有用到的,它表示当前PCI BAR的物理地址映射到内核中的虚拟地址。

    1.1.1 igbuio_pci_setup_ioport的过程:

    igbuio_pci_setup_ioport函数的过程与igbuio_pci_setup_iomem大致相同。

    IORESOURCE_IO

    1.1.2 为什么有I/O MemoryI/O Port两种类型?

    对于一个设备来说,除了自带的内存之外,还可能有寄存器等存储手段。显然,设备自带的内存就属于I/O Memory,而寄存器等其他的存储手段属于I/O Port类型。

    I/O Space 和 Memory Space

    2.0 igb_uio如何绕开内核?

    事实上,所有UIO设备在sysfs文件系统下都有一系列的文件接口,而用户程序就可以通过这些文件读取所需的设备信息,例如我们关心的PCI BAR等。得到了PCI BAR里存储的设备物理地址,就可以建立内存映射,进而与设备进行通信。

    但是在DPDK的PMD中,并未使用PCI BAR的信息建立内存映射,而是直接使用mmap,直接映射/dev/uioX文件从而与某个UIO设备建立联系。

    而不同的PCI BAR对应的内存区域在mmap时如何区分呢? 简单地说,可以通过计算偏移量来区分,第n个PCI BAR对应的内存偏移量为n * pagesz,即每个PCI BAR对应的内存区域都在不同的页内。

    参考资料:

    1. DPDK-IGB_UIO
    2. Userspace I/O HOWTO
    3. How to Write Linux PCI Driver
    4. PCI - OSDev Wiki
    5. Linux Driver Development, Edition 3, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman

    原文链接:https://zhuanlan.zhihu.com/p/483868843 

  • 相关阅读:
    瑞芯微RK3568|SDK开发之Kernel编译
    TCP/IP五层协议栈(3)
    智慧农业系统 - 可视化大屏(Echarts)&管理系统(HTTP(S)协议)&物联网平台(MQTT协议)
    云原生之深入解析Jenkins多分支管道
    java编程培训学习的就业前景好不好
    IIC协议详解
    某大学ipv6和ipv4结合的校园网规划设计
    基于JavaWeb的大学迎新系统设计与实现(源码+数据库脚本+论文+开题报告)
    界面控件DevExpress WPF(v23.2)下半年发展路线图
    npm install 安装总结
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/127810505