dpdk pmd驱动初始化_dpdk pmd驱动教程-程序员宅基地

技术标签: dpdk  pmd驱动  网卡数据空间  

前言

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

目录

1、如何学习pmd驱动

1.1、寄存器的位置在哪里

1.2、网卡寄存器的读写

1.3、网卡有哪些寄存器

1.4、网卡配置空间的格式

2、网卡数据空间的开辟

3、pmd驱动初始化


1、如何学习pmd驱动

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

1.1、寄存器的位置在哪里

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

   

        在e1000网卡驱动eth_igb_dev_init初始化函数中,会将网卡硬件结构的hw_addr指针直接指向网卡的配置空间。

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;
}

1.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))

1.3、网卡有哪些寄存器

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

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

1.4、网卡配置空间的格式

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

2、网卡数据空间的开辟

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

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_init
	diag = (*eth_drv->eth_dev_init)(eth_drv, eth_dev);
}

3、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。
 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangquan1992/article/details/104067787

智能推荐

Linux用户管理详解_linux登录qq是什么意思-程序员宅基地

文章浏览阅读448次。Linux用户管理用户基本概念什么是用户用户指的是能够正常登录Linux或Windows系统,比如:登录QQ的用户、登入王者荣耀的用户、等等[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nz1edsjq-1626145230283)(C:\Users\李开开\AppData\Roaming\Typora\typora-user-images\image-20210712171546940.png)]为什么需要用户系统上的每一个进程(运行的程序),都_linux登录qq是什么意思

Unity中协程里Animator获取状态一些笔记_getanimatortransitioninfo-程序员宅基地

文章浏览阅读4.5k次,点赞4次,收藏7次。最近用Animator获取状态各种获取错误,所以记一下笔记Animator中可以获取三种不同的状态:GetCurrentAnimatorStateInfo 获取正确的状态机状态GetNextAnimatorStateInfo 获取下一个状态机的状态GetAnimatorTransitionInfo 获取状态机的过渡状态动画同步是在帧最前,而协程是在帧的最后调用。所以切换状态后在协程获取状..._getanimatortransitioninfo

LATEX 中参考文献顺序_spphys.bst-程序员宅基地

文章浏览阅读924次。\bibliography{report} % bibliography data in report.bib\bibliographystyle{unsrt} % makes bibtex use spphys.bstunsrt 表示按照引用的先后顺序进行排序_spphys.bst

Linux下部署maven-web项目,包括JDK安装、TOMCAT安装、MYSQL安装详细解释-程序员宅基地

文章浏览阅读335次。为什么80%的码农都做不了架构师?>>> ..._linux系统搭建maven+tomcat+mysql

effective stl 第18条: 避免使用vector<bool>-程序员宅基地

文章浏览阅读354次。vector不是容器,并且它不存储bool,因为他是按照位来存储的,即一个bool只占一个二进制位。假设有vector v;则&v[0]会引起编译错误。如果不使用&v[0]可以使用vector,否则,可以用deque 和bitset来替代_避免使用vector

Bug的严重程度(缺陷程度)有哪几种。。。。_bug严重程度-程序员宅基地

文章浏览阅读6.8k次,点赞2次,收藏20次。Bug程度分为四种,分别为:致命S0:致命缺陷是指会造成安全问题的各类缺陷。在测试中很少出现,一旦出现立即中止版本测试。系统崩溃,数据丢失,数据毁坏,无法运行等Bug。严重S1:是指可以引起易于纠正的异常情况,可能引起易于修复的故障或对产品外观造成难以接受的缺陷。不影响其他功能的情况下可以继续版本测试。功能和性能不能实现。 次要功能全部丧失。 功能遗漏等等。 一般S2:一般缺陷是指不影响产品的..._bug严重程度

随便推点

《iOS 9 开发指南》——第1章,第1.3节工欲善其事,必先利其器——搭建开发环境...-程序员宅基地

文章浏览阅读202次。本节书摘来自异步社区《iOS 9 开发指南》一书中的第1章,第1.3节工欲善其事,必先利其器——搭建开发环境,作者 管蕾,更多章节内容可以访问云栖社区“异步社区”公众号查看1.3 工欲善其事,必先利其器——搭建开发环境iOS 9 开发指南图片 2 知识点讲解:光盘:视频知识点第1章搭建开发环境.mp4学习iOS 9开发也离不开好的开发工具的帮助,如果使..._(1)下载完成后单击打开下载的“.dmg”格式文件,然后双击xcode文件开始安装。

iView 3.3.2 发布,基于 Vue.js 的企业级 UI 组件库-程序员宅基地

文章浏览阅读115次。开发四年只会写业务代码,分布式高并发都不会还做程序员? iView 3.3.2 发布了,iView 是一套基于 Vue..._iview 3.2.2

详解not in与not exists的区别与用法(not in的性能并不差!)-程序员宅基地

文章浏览阅读93次。2019独角兽企业重金招聘Python工程师标准>>> ..._predicate not in查询

SpringBoot整合Spring Data JPA、MySQL、Druid并使用Mockito实现单元测试_spring jpa mock-程序员宅基地

文章浏览阅读4.7k次,点赞3次,收藏7次。SpringBoot整合Spring Data JPA、MySQL、Druid并使用Mockito实现单元测试_spring jpa mock

java 解析excel金额_java解析Excel(xls、xlsx两种格式)-程序员宅基地

文章浏览阅读441次。package poi;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.LinkedHashMap;import j..._java getcellformatvalue

50个漂亮免费的 WordPress 主题(下)_wordpressbo'ke 免费-程序员宅基地

文章浏览阅读170次。50个漂亮免费的 WordPress 主题(上)Minimatica( Demo | Download )Placeholder( Demo | Download )Navly( Demo | Download )Cobera( Demo | Download )The Blog( Demo | Download )Gabi..._wordpressbo'ke 免费

推荐文章

热门文章

相关标签