在没有引入pmd用户态网卡驱动之前, 网卡在收到报文后,网卡驱动会将报文从网卡缓冲区拷贝到内核, 接着内核在把报文拷贝到应用层,整个过程需要2次的拷贝以及系统调用。当应用层需要发送数据时,应用层将报文拷贝到内核,接着内核拷贝到网卡缓冲区,由网卡负责发送,整个过程也需要2次的拷贝以及系统调用。 不管接收还是发送报文,系统调用以及内存拷贝都是需要消耗性能的。 在引入了pmd用户态驱动后,情况就完全不一样了。pmd为用户态驱动,这是应用层自己实现的一个网卡驱动程序,运行在应用层, 网络报文不经过内核,相当于把内核旁路了。pmd通过轮询的方式直接从dma控制器获取报文,而无需经过内核,也就减少了系统调用以及用户态与内核态频繁数据拷贝的性能开销。应用层要发送报文时,也是直接将报文交给dma控制器,由dma控制器负责报文的发送。

在分析pmd用户态驱动之前,先来介绍下如何学习pmd驱动。

一、如何学习pmd驱动

虽然pmd运行在用户态,但也是一个网卡驱动程序。 既然是网卡驱动程序也就少不了对网卡硬件进行配置操作,例如设置网卡接收缓冲区,发送缓冲区的大小。这里说的对网卡进行配置, 也就是对网卡寄存器进行配置。每个网卡都有自己的配置空间,配置空间里面有很多的寄存器,每种寄存器各自负责不同的功能。例如接收控制寄存器,用于对网卡接收到报文的一些设置; 中断寄存器,用于设置允许产生哪里中断事件,例如链路中断。在pmd驱动代码e1000中,可以看到网卡驱动所做的事情绝大部分是对寄存器进行设置或者读取操作。这就需要有一个手册,来介绍这些寄存器的使用,如果没有这些手册,则分析pmd用户态驱动将会一头雾水,鬼知道往某个寄存器写入的数值代表什么意思。每种网卡型号都有自己的datasheet数据手册, 可以自行从intel官网下载。文章末尾也给出了82574; 82583两款网卡的数据手册的下载链接。

1、寄存器的位置在哪里

在每一个网卡的配置目录下,都有一个resouce文件,里面记录了这个网卡的配置空间的开始位置,结束位置,以及配置空间的总大小。这个配置空间里面有一堆的寄存器,可以对这些寄存器进行设置,读取操作。

在e1000网卡驱动eth_igb_dev_init初始化函数中,会将网卡硬件结构的hw_addr指针直接指向网卡的配置空间。应用层后面就可以对这个配置空间进行读写操作。应用层之所以可以对这个配置空间中的寄存器进行操作,得益于igb_uio驱动,igb_uio驱动将网卡的配置空间暴露到应用层来,应用层才能知道网卡的寄存器地址在哪里,进而对这些寄存器进行读写操作。

static int eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev)
{//指向网卡的配置空间hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
}

2、网卡寄存器的读写

当要从网卡中读取某个寄存器的内容时,可以调用E1000_READ_REG,例如E1000_READ_REG(hw, E1000_ICR)读取中断寄存器,进而知道当前发生了哪些中断事件; 当需要设置某个网卡寄存器时,可以调用E1000_WRITE_REG,例如E1000_WRITE_REG(hw, E1000_IMS, intr->mask)将设置开启哪些中断。 不管是读取,还是设置,可以看出最终都会调用E1000_PCI_REG_ADDR,访问的是网卡的配置空间。

//网卡寄存器的地址
#define E1000_PCI_REG_ADDR(hw, reg)         ((volatile uint32_t *)((char *)(hw)->hw_addr + (reg)))
//读取某个网卡寄存器
#define E1000_READ_REG(hw, reg)             e1000_read_addr(E1000_PCI_REG_ADDR((hw), (reg)))
//设置某个网卡寄存器
#define E1000_WRITE_REG(hw, reg, value)     E1000_PCI_REG_WRITE(E1000_PCI_REG_ADDR((hw), (reg)), (value))

3、网卡有哪些寄存器

每种网卡型号的数据手册中,都会描述当前网卡支持哪些寄存器,寄存器中的每个位代表什么意思。下面是82574网卡支持的寄存器列表部分截图。

以CTRL设备控制寄存器为例,这个寄存器一共由32位组成,也就是4个字节。每一个位都代表着不同功能,例如是否支持全双工, 是否开启自动协商速率等。往这些位写入1表示设置,写入0表示清除设置。

4、网卡配置空间的格式

Base Address 0指向的位置就是网卡的配置寄存器的地址列表,里面包含了很多的寄存器信息,这些寄存器也就是上图列出的 那些。至于这个网卡配置空间每个字段的格式,读者自行查看网卡的数据手册吧,里面对每一个字段都进行了详细的解释。

二、网卡数据空间的开辟

pmd里面会维护一个网卡数组,对于每一个网卡结构,都会维护这个网卡的接收发送数据的回调,关联的驱动等信息。以此同时,对于每一个网卡,都会创建一个以之一一对应的网卡数据空间结构,这个结构维护了网卡 的接收队列,发送队列信息。后续报文的收发,都会用到这个网卡数据空间结构。

static int rte_eth_dev_init(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
{//从内存池上开辟所有网卡的数据空间结构eth_dev = rte_eth_dev_allocate(ethdev_name);
}
struct rte_eth_dev * rte_eth_dev_allocate(const char *name)
{//从内存池上开辟所有网卡的数据空间结构rte_eth_dev_data_alloc();//从网卡数据空间中获取一个结构,交由网卡eth_dev = &rte_eth_devices[nb_ports];eth_dev->data = &rte_eth_dev_data[nb_ports];snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);eth_dev->data->port_id = nb_ports++;
}

接下里将来分析下网卡驱动的初始化过程。e1000网卡的驱动,对应的初始化函数为eth_igb_dev_init。对于82571, 82583等网卡,驱动初始化都是这个接口。

static int rte_eth_dev_init(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
{//网卡初始化,例如e1000网卡驱动的接口为eth_igb_dev_initdiag = (*eth_drv->eth_dev_init)(eth_drv, eth_dev);
}

三、pmd驱动初始化

每个网卡都有mac层,phy物理层,nvm层,vbx层。pmd用户态主要是为这些层提供一个初始化接口。后续应用层调用接口实现某些功能时,例如对某些寄存器的设置,函数内部会调用这些层的接口来对寄存器进行配置。先来看下整体的框架结构

mac层提供了一个统一的抽象接口,例如

//mac层操作接阔
struct e1000_mac_operations
{s32  (*init_params)(struct e1000_hw *);            s32  (*id_led_init)(struct e1000_hw *);         s32  (*blink_led)(struct e1000_hw *);...
}

而e1000_mac.c这个文件择主要是对mac层的各个接口提供默认的实现,通常是一个空函数。

对于每一个网卡型号,网卡自己都可以重新实现这个mac层的各个接口,相当于重载。当然,如果具体的网卡不提供这个mac层的接口实现, 则还是会使用mac层的默认实现方式。例如e1000_82571.c这个文件,就是对这个网卡重新实现mac层的各个接口功能。

相应的,nvm层,vbx层都是这样的一种框架结构,掌握了mac层,其他层也是类似的。而e1000_api.c是一个调度器,调度默认实现的各个层以及调用具体网卡的实现。

s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
{//注册mac层通用操作接口, 后续可以重载e1000_init_mac_ops_generic(hw);//注册物理层通用操作接口,后续可以重载e1000_init_phy_ops_generic(hw);//注册nvm层通用操作接口,后续可以重载e1000_init_nvm_ops_generic(hw);//注册mbx层通用操作接口,后续可以重载e1000_init_mbx_ops_generic(hw);
}

现在对于pmd驱动的框架已经分析完了,现在从代码层上分析下几个需要注意的地方。驱动初始化开始的时候,会注册一个报文接收回调, 同时还会注册一个报文发送回调。关于pmd驱动实现报文收发,后续会有一篇文章专门分析,这里只需要知道这两个接口是在驱动初始化的时候设置的就好了。

//驱动初始化入口
static int eth_igb_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev)
{//注册报文接口回调eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;//注册报文发送回调eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
}

另一个需要注意的是, pmd既然是一个驱动,必然会提供一些给应用层调用的接口。例如:当应用层调用rte_eth_dev_configure配置网卡时,这个函数内部会调用dev_configure接口;  当应用层调用rte_eth_rx_queue_setup设置接收队列时,函数内部会调用rx_queue_setup。 pmd提供了一个抽象接口层,例如:

struct eth_dev_ops
{eth_dev_configure_t        dev_configure;      /**< 配置网卡,例如eth_igb_configure,Configure device. */eth_dev_start_t            dev_start;            /**< 启用网卡,例如eth_igb_start,Start device. */eth_dev_stop_t             dev_stop;             /**< 停用网卡,Stop device. */eth_dev_set_link_up_t      dev_set_link_up;      /**< 设置链路up,Device link up. */eth_dev_set_link_down_t    dev_set_link_down;  /**< 设置链路down,Device link down. */
}   

不同的网卡类型,都需要实现这个接口,是不是很像c++中的多态设计思想。例如:e1000网卡的实现接口为eth_igb_ops; ixgbe万M网卡的实现接口为ixgbe_eth_dev_ops。

下一篇文章将来分析应用层用来设置网卡,或者获取网卡信息的接口

四、网卡datasheet

82574网卡数据手册

https://docs.rs-online.com/96e8/0900766b81384733.pdf

82583网卡数据手册

https://www.intel.com/content/www/us/en/ethernet-controllers/82583v-gbe-controller-datasheet.html

dpdk pmd驱动初始化相关推荐

  1. DPDK pmd驱动初始化(十九)

    在没有引入pmd用户态网卡驱动之前, 网卡在收到报文后,网卡驱动会将报文从网卡缓冲区拷贝到内核, 接着内核在把报文拷贝到应用层,整个过程需要2次的拷贝以及系统调用.当应用层需要发送数据时,应用层将报文 ...

  2. dpdk pmd驱动分析

    缘起dpdk_devbind.py 运行dpdk程序之前我们一般都会使用dpdk_devbind.py程序对指定的驱动与设备进行绑定与解绑(如下命令).那么dpdk_devbind.py程序是如何实现 ...

  3. DPDK — 网卡驱动初始化流程

    目录 文章目录 目录 Intel 82599 ixgbe 网卡驱动示例 rte_eth_dev/rte_eth_dev_data 数据结构 rte_eth_dev_count 函数 rte_eth_d ...

  4. 从 dpdk-20.11 移植 intel E810 百 G 网卡 pmd 驱动到 dpdk-16.04 中

    文章目录 前言 移植前的调研工作 dpdk-20.11 ice pmd 驱动源码的组成 移植问题与解决方案记录 16.04 使用 make 编译,20.11 使用 meson 与 ninja 方式编译 ...

  5. DPDK网卡PMD驱动

    以/home/user/dpdk-stable-18.11.11/drivers/net/i40e目录下的驱动为例 源代码文件有 # ls base i40e_ethdev_vf.c i40e_log ...

  6. DPDK — PMD,DPDK 的核心优化

    目录 文章目录 目录 前文列表 PMD,DPDK 的核心优化 PMD 与 UIP 的交互实现 PMD 的应用层实现 参考文章 前文列表 <DPDK - 安装部署> <DPDK - 数 ...

  7. DPDK uio驱动实现(二十)

    一.dpdk uio驱动框架 在系统加载igb_uio驱动后,每当有网卡和igb_uio驱动进行绑定时, 就会在/dev目录下创建一个uio设备,例如/dev/uio1.uio设备是一个接口层,用于将 ...

  8. DPDK pci驱动探测(十八)

    上一篇文章已经介绍了pci设备的背景知识, 现在我们来分析下pci设备是如何探测到支持的驱动,进而与驱动进行关联:pci与驱动的解除绑定:pci设备与uio设备的关联. 一.pci驱动注册 网卡驱动的 ...

  9. DPDK PMD( Poll Mode Driver)轮询模式驱动程序

    DPDK PMD( Poll Mode Driver)轮询模式驱动程序 目录 Mellanox PMDs 轮询模式驱动程序 要求和假设 设计原则 逻辑核心,内存和NIC队列关系 设备标识,所有权和配置 ...

最新文章

  1. 工业相机丢帧现象怎么解决?
  2. uniapp中动态添加及修改导航栏
  3. vivo android8公测,vivo 开启安卓P公测不限人数!这四款机型用户别错过了
  4. Identity Server4学习系列四之用户名密码获得访问令牌
  5. 基于SpringBoot,来实现MySQL读写分离技术
  6. 瑞士行-少女峰,峡谷徒步
  7. linux初始化TCP服务失败,深入Linux系统追踪TCP初始化
  8. append()方法_超详细教程 | pandas合并之append和concat
  9. 华为机试HJ3:明明的随机数
  10. python读取文件路径中有中文_转 python 读取中文文件名/中文路径
  11. Mac优化工具多合一MacCleaner PRO
  12. python导入cv2
  13. Multi-attributed heterogeneous graph convolutional network for bot detection(SCI CCF B)
  14. 小米手机刷机ROOT原理
  15. PDF提取页面方法,如何从PDF文件中提取页面
  16. 请问现在好多抖音巨量广告落地页pages.tmall.com的页面如何生成
  17. 在Windows 记事本中快速选中大量文本的方法
  18. 'npm'不是内部命令或外部命令的解决办法
  19. 学shell和python哪个难_shell与python的优劣对比到底用哪个
  20. 我的世界它最懂 华为nova7系列打造5G自拍旗舰

热门文章

  1. (四)C语言零基础入门 --- C语言之入门课程
  2. 2021-12-29 迈向程序猿的第五十七步
  3. 补码加法器中低位进位信息是什么?
  4. 在你眼中,人生最重要的是什么?
  5. [原创] 如何带好一个团队
  6. ettercap局域网内DNS欺骗试验
  7. 什么是 Pandas?
  8. Kerberos与Ranger
  9. 1141E - Superhero Battle(数学思维) Codeforces Round #547 (Div. 3)
  10. 转发器、网桥、路由器和网关的区别如下: