uio用户态驱动

本文探讨了UIO用户态驱动的设计与应用,特别是在DPDK框架中如何绕过内核处理,实现用户空间直接与硬件交互,提升网络数据包处理效率。文章详细介绍了UIO驱动的注册流程,设备绑定操作,以及用户态驱动的两种开发方式,对比了其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1.1为什么出现了UIO?
   硬件设备可以根据功能分为网络设备,块设备,字符设备,或者根据与CPU相连的方式分为PCI设备,USB设备等。它们被不同的内核子系统支持。这些标准的设备的驱动编写较为容易而且容易维护。很容易加入主内核源码树。但是,又有很多设备难以划分到这些子系统中,比如I/O卡,现场总线接口或者定制的FPGA。通常这些非标准设备的驱动被实现为字符驱动。这些驱动使用了很多内核内部函数和宏。而这些内部函数和宏是变化的。这样驱动的编写者必须编写一个完全的内核驱动,而且一直维护这些代码。而且这些驱动进不了主内核源码。于是就出现了用户空间I/O框架(Userspace I/O framework)。

1.2 dpdk的uio使用

在基于kernel的IO模型中,所有的设备IO都要经过内核处理,在高并发的网络数据包收发的情况下,大量硬件中断会降低内核数据包处理能力,内核和用户空间的数据拷贝也会造成大量的计算资源浪费。所以,作为高并发大流量网络开发框架的DPDK,必须要找到一个能够避免内核中断爆炸和大量数据拷贝的方法,在用户空间能够直接和硬件进行交互。Linux的UIO就是这样一个将硬件操作映射到用户空间的kernel bypass方案。

下图展示了UIO驱动的内核部分,用户空间部分,和UIO框架以及内核的关系:

1.3 dpdk的网口绑定干了啥?

绑定操作:

./dpdk-devbind.py -b igb_uio 0000:00:07.0

既然是设备驱动程序一定会创建设备,/dev下查看:多出了uio0设备;

vm65:/dev # ll |grep uio
crw-------  1 root root    246,   0 Feb 18 07:41 uio0
vm65:/dev #

查看/sys/class/uio/uio:

vm65:/sys/class/uio/uio0 # ll
total 0
-r--r--r-- 1 root root 4096 Feb 18 06:42 dev
lrwxrwxrwx 1 root root    0 Feb 18 06:42 device -> ../../../0000:00:07.0
-r--r--r-- 1 root root 4096 Feb 18 06:42 event
drwxr-xr-x 4 root root    0 Feb 18 06:42 maps
-r--r--r-- 1 root root 4096 Feb 18 06:42 name
drwxr-xr-x 2 root root    0 Feb 18 06:42 power
lrwxrwxrwx 1 root root    0 Feb 18 06:42 subsystem -> ../../../../../class/uio
-rw-r--r-- 1 root root 4096 Feb 18 06:41 uevent
-r--r--r-- 1 root root 4096 Feb 18 06:42 version

同时,查看dmesg,多出了以下几行信息:

<6>[171282.211083] igb_uio 0000:00:07.0: mapping 1K dma=0x123fb9b000 host=ffff88123fb9b000
<6>[171282.211088] igb_uio 0000:00:07.0: unmapping 1K dma=0x123fb9b000 host=ffff88123fb9b000

可以看到。绑定过程中的kernel part会通过uio_register_device 注册对应的uio设备,获取pcie的配置空间BAR信息包括addr、name、size、offset填充到map/map0中,这些在用户态会将其读出,并mmap至用户态进程空间,这样用户态便可直接操作设备的内存空间。

除了内存管理,第二个任务,对于设备中断的应答必须在内核空间进行。所以在内核空间有一小部分代码用来应答和禁止中断,中断的其他任务由用户态完成;

假设用户空间要等待一个设备中断,它仅仅须要简单的堵塞在对 /dev/uioX的read()操作上。 当设备产生中断时,read()操作马上返回。

UIO 也实现了poll()系统调用。你能够使用 select()来等待中断的发生。select()有一个超时參数能够用来实现有限时间内等待中断。

 

1.4 用户态驱动

常用的用户态驱动开发有两种方式可选:

1、打开/dev/mem 后,使用MMAP映射出芯片物理地址对应的虚拟地址,在用户态访问虚拟地址加偏移就能访问到芯片的寄存器;

2、采用UIO方式,在内核态映射地址后,在用户态通过打开/dev/uioxxx 方式,再使用MMAP映射一次,就可采用跟方式1 相同的方式访问芯片reg或是memory;

这两种方式各有优缺点:

方式1:优点是实现简单,如果不需要用到中断,可以不用管内核态的内容,关注用户态代码就好。缺点是代码运行的进程要有root权限,不然无法访问/dev/mem,如果要使用中断还是会涉及到内核态的驱动;

方式2:优点是无需要root权限,中断可以直接在用户态获取。缺点是必须要在内核态做初始化;即需要在内核态通过uio_register_device注册对应的uio设备,这样user space就可以通过/sys/class/uio/uioX/mapsX来访问这个uio设备;

关键结构体&函数:

注册uio设备前需要初始化对应的uio_info结构体:

struct uio_info {  
    struct uio_device   *uio_dev; // 在__uio_register_device中初始化 
    const char      *name; // 调用__uio_register_device之前必须初始化 
    const char      *version; //调用__uio_register_device之前必须初始化 
    struct uio_mem      mem[MAX_UIO_MAPS]; 
    struct uio_port     port[MAX_UIO_PORT_REGIONS]; 
    long            irq; //分配给uio设备的中断号,调用__uio_register_device之前必须初始化 
    unsigned long       irq_flags;// 调用__uio_register_device之前必须初始化 
    void            *priv; // 
    irqreturn_t (*handler)(int irq, struct uio_info *dev_info); //uio_interrupt中调用,用于中断处理 
                                                                                                   // 调用__uio_register_device之前必须初始化 
    int (*mmap)(struct uio_info *info, struct vm_area_struct *vma); //在uio_mmap中被调用, 
                                                                                                                // 执行设备打开特定操作 
    int (*open)(struct uio_info *info, struct inode *inode);//在uio_open中被调用,执行设备打开特定操作 
    int (*release)(struct uio_info *info, struct inode *inode);//在uio_device中被调用,执行设备打开特定操作 
    int (*irqcontrol)(struct uio_info *info, s32 irq_on);//在uio_write方法中被调用,执行用户驱动的 
                                                                                       //特定操作。 
}; 

设备注册函数:

#define uio_register_device(parent, info) __uio_register_device(THIS_MODULE, parent, info)
int __uio_register_device(struct module *owner,
              struct device *parent,
              struct uio_info *info)

用户态驱动示例:

https://blog.youkuaiyun.com/ganggexiongqi/article/details/6751798

https://blog.youkuaiyun.com/ganggexiongqi/article/details/6748103

posted on 2019-02-19 09:27 Rex_Zhang 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/rex-2018-cloud/p/10399184.html

### 回答1: DPDK (Data Plane Development Kit) 是一个开源的数据平面开发工具包。它可以提供高性能的网络 I/O 接口,允许开发人员在用户空间中运行网络应用程序。 igb_uio 是 DPDK 提供的一种用于 Intel 82580/I350 以太网控制器的用户空间驱动程序。要使用 igb_uio 驱动,需要进行以下步骤: 1. 下载 DPDK 并解压缩。 2. 运行 "make config T=x86_64-native-linuxapp-gcc" 来配置 DPDK。 3. 在 .config 文件中找到并启用 "CONFIG_RTE_LIBRTE_IGB_UIO=y" 选项。 4. 运行 "make" 来编译 DPDK。 5. 运行 "make install" 来安装 DPDK。 6. 加载 igb_uio 驱动,运行 "modprobe uio" 和 "insmod build/kmod/igb_uio.ko"。 7. 将网卡绑定到 igb_uio 驱动上,运行 "./usertools/dpdk-devbind.py --bind=igb_uio 网卡名" 在完成这些步骤后,就可以在 DPDK 中使用 igb_uio 驱动了。 注意: - 上面的步骤基于linux系统,在其他系统上安装配置步骤可能有所不同 - 具体操作请参考DPDK官网,这里给出大致流程,需要结合具体DPDK版本参考 ### 回答2: 在DPDK中使用igb_uio驱动需要进行以下步骤: 1. 下载DPDK源代码:首先需要到DPDK官网(https://www.dpdk.org/)下载最新的DPDK源代码。 2. 解压源代码:将下载好的源代码文件解压到一个合适的目录下。 3. 配置编译环境:进入解压后的DPDK源代码目录,在终端中执行命令“make config T=x86_64-native-linuxapp-gcc”配置编译环境。其中,T参数根据自己的处理器架构进行选择,x86_64代表64位。 4. 编译DPDK:继续在终端中执行命令“make”编译DPDK。这一步需要耐心等待编译完成。 5. 设置环境变量:在终端中执行命令“export RTE_SDK=/path/to/dpdk”和“export RTE_TARGET=x86_64-native-linuxapp-gcc”分别设置DPDK的根目录和目标平台。 6. 下载igb_uio驱动:在终端中执行命令“make install T=x86_64-native-linuxapp-gcc”下载igb_uio驱动。这一步会自动从DPDK的软件仓库中下载igb_uio驱动,并将其安装到系统中。 7. 配置驱动:在终端中执行命令“modprobe uio”加载uio驱动,然后执行命令“insmod /path/to/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko”加载igb_uio驱动。 8. 绑定网卡:执行命令“dpdk-devbind --bind=igb_uio ethX”将指定的网卡绑定到igb_uio驱动。 至此,igb_uio驱动就成功下载、编译、配置完毕。现在可以在DPDK中使用igb_uio驱动来进行高性能网络应用开发了。 ### 回答3: DPDK(Data Plane Development Kit)是一种用于快速数据包处理的开源工具集。在DPDK中,igb_uio是一种用户态UIO(Userspace Input/Output)驱动,用于将网卡设备映射到用户态进程,实现零拷贝和更高的性能。 要下载、编译和配置igb_uio驱动,可以按照以下步骤进行: 1. 首先,确保系统安装了必要的构建工具和依赖项。例如,gcc、make、kernel-headers等。如果缺少相关软件包,可以使用包管理器进行安装。 2. 接下来,下载DPDK源代码。可以从DPDK官方网站(https://www.dpdk.org/)或者DPDK的GitHub仓库中获取最新的源代码。 3. 解压源代码包,并进入解压后的目录。 4. 在终端中,执行以下命令编译DPDK和igb_uio驱动: ``` make config T=x86_64-native-linuxapp-gcc make ``` 这将根据系统架构编译DPDK和igb_uio驱动的二进制文件。 5. 编译完成后,可以使用以下命令将igb_uio驱动安装到系统中: ``` sudo make install T=x86_64-native-linuxapp-gcc ``` 此命令将igb_uio.ko模块复制到适当的系统目录中。 6. 配置igb_uio驱动,使其可以加载并与网卡设备关联。需要编辑DPDK的配置文件(config文件),将CONFIG_RTE_EAL_IGB_UIO=y设置为解除注释,并保存更改。 7. 加载igb_uio驱动模块,可以使用以下命令: ``` sudo modprobe igb_uio ``` 如果成功加载,可以通过执行以下命令检查igb_uio模块是否成功绑定到网卡设备: ``` sudo ./dpdk-devbind.py --status ``` 此命令将显示网卡设备及其绑定状态。 通过按照以上步骤进行,可以成功下载、编译和配置DPDK下的igb_uio驱动。完成后,可以在DPDK应用程序中使用igb_uio驱动来进行高性能的数据包处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值