dpdk uio整体分析及网卡加载

参考:https://zhuanlan.zhihu.com/p/477600165

一、Linux内核知识点

1. __attribute__ constructor/destructor  

(1)若函数被设定为constructor属性,则该函数会在 main()函数执行之前被自动的执行。

(2)若函数被设定为destructor属性,则该函数会在main()函数执行之后或者exit()被调用后被自动的执行

2.container_of宏

作用是通过结构体内某个成员变量的地址和该变量名,以及结构体类型。找到该结构体变量的地址

3. EXPORT_SYMBOL

标签内定义的函数或者符号对全部内核代码公开,不用修改内核代码就可以在您的内核模块中直接调用,即使用EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用。


4.EXPORT_SYMBOL_GPL


 与EXPORT_SYMBOL类似,_GPL版本的宏定义只能使符号对GPL许可的模块可用。 符号必须在模块文件的全局部分导出,不能在函数中导出

5.ATTR

#define DRIVER_ATTR(_name, _mode, _show, _store) \
    struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DRIVER_ATTR_RW(_name) \
    struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
#define DRIVER_ATTR_RO(_name) \
    struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
#define DRIVER_ATTR_WO(_name) \
    struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)__ATTR定义于文件 include/linux/sysfs.h
#define __ATTR(_name, _mode, _show, _store) {    \.attr = {.name = __stringify(_name), .mode = _mode },  \.show = _show,      \.store = _store,      \
}
说明_name:名称,也就是将在sys fs中生成的文件名称。_mode:上述文件的访问权限,与普通文件相同,UGO的格式,最高权限0644,否则会报错。_show:显示函数,cat该文件时,此函数被调用。_store:写函数,echo内容到该文件时,此函数被调用。

这个主要是绑定网卡时会用到

二、内核UIO驱动框架

内核uio框架通过配置内核选项CONFIG_UIO=y使能Userspace I/O drivers,在内核初始化时会调用uio_init创建uio_class; -----内核uio.c中完成,纯内核操作;

//dpdk定义的uio pci设备描述结构
struct rte_uio_pci_dev {struct uio_info info; //uio 通用结构struct pci_dev *pdev;  //pci设备描述结构enum rte_intr_mode mode; //中断模式
};
struct uio_info {struct uio_device    *uio_dev; //uio设备属于const char        *name; //名称const char        *version; //版本号struct uio_mem        mem[MAX_UIO_MAPS];//可映射的内存区域列表,size == 0表示列表结束struct uio_port        port[MAX_UIO_PORT_REGIONS]; //网口区域列表long            irq; //UIO_IRQ_CUSTOM 中断号unsigned long        irq_flags; //请求中断号的标志void            *priv;  //可选的私有数据irqreturn_t (*handler)(int irq, struct uio_info *dev_info); //中断信息处理int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);//内存映射操作int (*open)(struct uio_info *info, struct inode *inode); //打开int (*release)(struct uio_info *info, struct inode *inode); //释放int (*irqcontrol)(struct uio_info *info, s32 irq_on); //中断控制操作 关闭/打开 当向/dev/uioX中写入值时
/*1.注册uio驱动入口部分
*/
module_init(uio_init)/*2.调用此函数
*/
static int __init uio_init(void)
{return init_uio_class();
}/*3. 真正的注册部分
*/
static int init_uio_class(void)
{int ret;/* 申请字符设备号(alloc_chrdev_region),分配字符设备(cdev_alloc),uio字符设备操作函数挂载(cdev->ops = &uio_fops;)并将字符设备"uio"注册到系统中(cdev_add); */ret = uio_major_init();if (ret)goto exit;/*创建“/sys/class/uio”设备目录或文件系统,此时该目录为空,在insmod igb_uio.ko后且运行python脚本绑定网卡后此目录下才有内容;*/ret = class_register(&uio_groups);if (ret) {printk(KERN_ERR "class_register failed for uio\n");goto err_class_register;}return 0;err_class_register:uio_major_cleanup();
exit:return ret;
}/*__class_register函数
*/int __class_register(struct class *cls, struct lock_class_key *key)
{struct subsys_private *cp;int error;pr_debug("device class '%s': registering\n", cls->name);cp = kzalloc(sizeof(*cp), GFP_KERNEL);if (!cp)return -ENOMEM;klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);INIT_LIST_HEAD(&cp->interfaces);kset_init(&cp->glue_dirs);__mutex_init(&cp->mutex, "subsys mutex", key);error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);if (error) {kfree(cp);return error;}/* set the default /sys/dev directory for devices of this class */if (!cls->dev_kobj)cls->dev_kobj = sysfs_dev_char_kobj;#if defined(CONFIG_BLOCK)/* let the block class directory show up in the root of sysfs */if (!sysfs_deprecated || cls != &block_class)cp->subsys.kobj.kset = class_kset;
#elsecp->subsys.kobj.kset = class_kset;
#endifcp->subsys.kobj.ktype = &class_ktype;cp->class = cls;cls->p = cp;error = kset_register(&cp->subsys);if (error) {kfree(cp);return error;}error = class_add_groups(class_get(cls), cls->class_groups);class_put(cls);error = add_class_attrs(class_get(cls));class_put(cls);return error;
}EXPORT_SYMBOL_GPL(__class_register);

三、dpdk中的igb_uio模块

1.dpdk-steup.sh中插入igb_uid模块

step2_func()
{TITLE="Setup linux environment"TEXT[1]="Insert IGB UIO module"FUNC[1]="load_igb_uio_module"
}load_igb_uio_module()
{if [ ! -f $RTE_SDK/$RTE_TARGET/kmod/igb_uio.ko ];thenecho "## ERROR: Target does not have the DPDK UIO Kernel Module."echo "       To fix, please try to rebuild target."returnfiremove_igb_uio_module/sbin/lsmod | grep -s uio > /dev/nullif [ $? -ne 0 ] ; thenmodinfo uio > /dev/nullif [ $? -eq 0 ]; thenecho "Loading uio module"sudo /sbin/modprobe uiofifi# UIO may be compiled into kernel, so it may not be an error if it can't# be loaded.echo "Loading DPDK UIO module"//把igb_uio模块加入到linux内核驱动中,执行insmod igb_ui.losudo /sbin/insmod $RTE_SDK/$RTE_TARGET/kmod/igb_uio.koif [ $? -ne 0 ] ; thenecho "## ERROR: Could not load kmod/igb_uio.ko."quitfi
}

2.igb_uio

注册igb_uio驱动主要做两件事情

    第一件事是配置中断模式;

    第二种是注册驱动

static struct pci_driver igbuio_pci_driver = {.name = "igb_uio",//id_table指针为空(即deviceid为空,类似内核igb_pci_tbl,dpdk的pci_id_igb_map),找不到驱动能匹配的设备,不会调用.probe钩子函数初始化;.id_table = NULL,.probe = igbuio_pci_probe,.remove = igbuio_pci_remove,
};//插入驱动到内核
static int __init
igbuio_pci_init_module(void)
{int ret;if (igbuio_kernel_is_locked_down()) {pr_err("Not able to use module, kernel lock down is enabled\n");return -EINVAL;}if (wc_activate != 0)pr_info("wc_activate is set\n");//配置中断模式ret = igbuio_config_intr_mode(intr_mode);if (ret < 0)return ret;//注册驱动return pci_register_driver(&igbuio_pci_driver);
}/*1.入口部分
*/
module_init(igbuio_pci_init_module);

pci_register_driver属于内核中函数,是向pci总线上注册uio设备驱动

 以下是内核函数

#define pci_register_driver(driver)		\__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)int __pci_register_driver(struct pci_driver *drv, struct module *owner,const char *mod_name)
{/* initialize common driver fields */drv->driver.name = drv->name;drv->driver.bus = &pci_bus_type;drv->driver.owner = owner;drv->driver.mod_name = mod_name;spin_lock_init(&drv->dynids.lock);INIT_LIST_HEAD(&drv->dynids.list);/* register with core */return driver_register(&drv->driver);
}
EXPORT_SYMBOL(__pci_register_driver);int driver_register(struct device_driver *drv)
{int ret;struct device_driver *other;BUG_ON(!drv->bus->p);if ((drv->bus->probe && drv->probe) ||(drv->bus->remove && drv->remove) ||(drv->bus->shutdown && drv->shutdown))printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);other = driver_find(drv->name, drv->bus);if (other) {printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);return -EBUSY;}ret = bus_add_driver(drv);if (ret)return ret;ret = driver_add_groups(drv, drv->groups);if (ret) {bus_remove_driver(drv);return ret;}kobject_uevent(&drv->p->kobj, KOBJ_ADD);return ret;
}
EXPORT_SYMBOL_GPL(driver_register);int bus_add_driver(struct device_driver *drv)
{struct bus_type *bus;struct driver_private *priv;int error = 0;bus = bus_get(drv->bus);if (!bus)return -EINVAL;pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);priv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv) {error = -ENOMEM;goto out_put_bus;}klist_init(&priv->klist_devices, NULL, NULL);priv->driver = drv;drv->p = priv;priv->kobj.kset = bus->p->drivers_kset;error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);if (error)goto out_unregister;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);if (drv->bus->p->drivers_autoprobe) {if (driver_allows_async_probing(drv)) {pr_debug("bus: '%s': probing driver %s asynchronously\n",drv->bus->name, drv->name);async_schedule(driver_attach_async, drv);} else {error = driver_attach(drv);if (error)goto out_unregister;}}module_add_driver(drv->owner, drv);error = driver_create_file(drv, &driver_attr_uevent);if (error) {printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);}error = driver_add_groups(drv, bus->drv_groups);if (error) {/* How the hell do we get out of this pickle? Give up */printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",__func__, drv->name);}if (!drv->suppress_bind_attrs) {error = add_bind_files(drv);if (error) {/* Ditto */printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);}}return 0;out_unregister:kobject_put(&priv->kobj);kfree(drv->p);drv->p = NULL;
out_put_bus:bus_put(bus);return error;
}int sysfs_create_groups(struct kobject *kobj,const struct attribute_group **groups)
{int error = 0;int i;if (!groups)return 0;for (i = 0; groups[i]; i++) {error = sysfs_create_group(kobj, groups[i]);if (error) {while (--i >= 0)sysfs_remove_group(kobj, groups[i]);break;}}return error;
}
EXPORT_SYMBOL_GPL(sysfs_create_groups);

流程梳理:

insmod igb_uio.ko-->module_init(igbuio_pci_init_module)-->igbuio_pci_init_module-->pci_register_driver(内核函数)-->__pci_register_driver(内核)-->driver_register(内核)

注:

(1)“/sys/bus/pci/drivers/igb_uio/”下存放的是驱动igb_uio目录文件;

(2)“/sys/class/uio/uioX”下存放的是uio设备目录文件,与“/dev/uioX”设备句柄对应

四.绑定网卡到igb_uio模块

4.1 脚本中的代码

dpdk.setup.shstep2_func()
{TEXT[7]="Bind Ethernet/Baseband/Crypto device to IGB UIO module"FUNC[7]="bind_devices_to_igb_uio"}bind_devices_to_igb_uio()
{if [ -d /sys/module/igb_uio ]; then${RTE_SDK}/usertools/dpdk-devbind.py --statusecho ""echo -n "Enter PCI address of device to bind to IGB UIO driver: "read PCI_PATH//主要是执行此部分sudo ${RTE_SDK}/usertools/dpdk-devbind.py -b igb_uio $PCI_PATH && echo "OK"elseecho "# Please load the 'igb_uio' kernel module before querying or "echo "# adjusting device bindings"fi
}
#! /usr/bin/env python
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation
#from __future__ import print_function
import sys
import os
import getopt
import subprocess
from os.path import exists, abspath, dirname, basename# The PCI base class for all devices
network_class = {'Class': '02', 'Vendor': None, 'Device': None,'SVendor': None, 'SDevice': None}
acceleration_class = {'Class': '12', 'Vendor': None, 'Device': None,'SVendor': None, 'SDevice': None}
ifpga_class = {'Class': '12', 'Vendor': '8086', 'Device': '0b30','SVendor': None, 'SDevice': None}
encryption_class = {'Class': '10', 'Vendor': None, 'Device': None,'SVendor': None, 'SDevice': None}
intel_processor_class = {'Class': '0b', 'Vendor': '8086', 'Device': None,'SVendor': None, 'SDevice': None}
cavium_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a04b,a04d','SVendor': None, 'SDevice': None}
cavium_fpa = {'Class': '08', 'Vendor': '177d', 'Device': 'a053','SVendor': None, 'SDevice': None}
cavium_pkx = {'Class': '08', 'Vendor': '177d', 'Device': 'a0dd,a049','SVendor': None, 'SDevice': None}
cavium_tim = {'Class': '08', 'Vendor': '177d', 'Device': 'a051','SVendor': None, 'SDevice': None}
cavium_zip = {'Class': '12', 'Vendor': '177d', 'Device': 'a037','SVendor': None, 'SDevice': None}
avp_vnic = {'Class': '05', 'Vendor': '1af4', 'Device': '1110','SVendor': None, 'SDevice': None}octeontx2_sso = {'Class': '08', 'Vendor': '177d', 'Device': 'a0f9,a0fa','SVendor': None, 'SDevice': None}
octeontx2_npa = {'Class': '08', 'Vendor': '177d', 'Device': 'a0fb,a0fc','SVendor': None, 'SDevice': None}
octeontx2_dma = {'Class': '08', 'Vendor': '177d', 'Device': 'a081','SVendor': None, 'SDevice': None}intel_ioat_bdw = {'Class': '08', 'Vendor': '8086', 'Device': '6f20,6f21,6f22,6f23,6f24,6f25,6f26,6f27,6f2e,6f2f','SVendor': None, 'SDevice': None}
intel_ioat_skx = {'Class': '08', 'Vendor': '8086', 'Device': '2021','SVendor': None, 'SDevice': None}
intel_ntb_skx = {'Class': '06', 'Vendor': '8086', 'Device': '201c','SVendor': None, 'SDevice': None}network_devices = [network_class, cavium_pkx, avp_vnic, ifpga_class]
baseband_devices = [acceleration_class]
crypto_devices = [encryption_class, intel_processor_class]
eventdev

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/21875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发和渗透偷懒利器utools

目录 1.前言 1.1 工具简介 1.2 核心特性 1.3 使用场景 1.4 安装与使用 1.4.1 下载&#xff1a; 1.4.2 安装&#xff1a; 1.4.3 配置&#xff1a; 1.4.4 插件市场&#xff1a; 2.懒狗插件介绍 基本介绍 2.1 数据模拟 2.2 随机生成虚假数据 2.3 API市场 2.4 Hoppscot…

【十二】图解mybatis日志模块之设计模式

图解mybatis日志模块之设计模式 概述 最近经常在思考研发工程师初、中、高级工程师以及系统架构师各个级别的工程师有什么区别&#xff0c;随着年龄增加我们的技术级别也在提升&#xff0c;但是很多人到了高级别反而更加忧虑&#xff0c;因为it行业35岁年龄是个坎这是行业里的共…

一文读懂数据库中的DB、DBMS、DBS、DBAS

目前数据库的应用非常广泛,几乎各行各业都在直接或间接地与数据库打交道,例如网上购物、银行业务、铁路购票和酒店住宿等。在实际应用中,数据库、数据库管理系统、数据库系统和数据库应用系统经常被统称为数据库,而实质上这4个概念是不一样的,它们具有不同的定义和含义。下…

暴力数据结构之排序大杂烩

1. 冒泡排序&#xff1a;O(N^2) 逻辑解析&#xff1a; 冒泡排序并没有什么实际意义&#xff0c;但是有教学意义&#xff0c;相信大部分小白在学习的初期第一个接触的排序就是冒泡排序。那么接下来我们了解一下他的底层逻辑&#xff1a; 冒泡排序顾名思义就是将最大&#xff08…

idea项目maven下载依赖报错

报错&#xff1a; 1、Failure to find bad.robot:simple-excel:jar:1.0 in https://maven.aliyun.com/repository/public was cached in the local repository, resolution will not be reattempted until the update interval of aliyunmaven has elapsed or updates are forc…

python的while循环与for循环总结

前两章中&#xff0c;我们跟着海绵宝宝的故事&#xff0c;掌握了 while 循环和 for 循环&#xff0c;这两种不同的循环模式。while 循环和 for 循环都需要有 循环体 和 缩进&#xff0c;我们来复习一下它俩的语法规则&#xff1a; while 循环与 for 循环辨析 学到这里&#x…

在鲲鹏服务器搭建k8s高可用集群分享

高可用架构 本文采用kubeadm方式搭建k8s高可用集群&#xff0c;k8s高可用集群主要是对apiserver、etcd、controller-manager、scheduler做的高可用&#xff1b;高可用形式只要是为&#xff1a; 1. apiserver利用haproxykeepalived做的负载&#xff0c;多apiserver节点同时工作…

易联众智慧云胶片平台,助推医学影像服务“向云端”

在门诊室里,张女士焦急地告诉主治医师,自己忘了带CT胶片。“您别急,我用系统查询一下。”医生轻点几下鼠标进入云胶片平台,只用不到10秒就顺利完成了影像调取。“不仅我可以看到,您在手机上也能随时随地查阅。”张女士根据提示操作,不仅能调阅自己的影像档案,连抽血化验结果都可…

[GeoServer系列]Shapefile数据发布

【GeoServer系列】——安装与发布shapefile数据-CSDN博客 将待发布数据放置指定目录下 webapps\geoserver\data\data 创建存储仓库 新建矢量数据源 发布图层 设置边框 设置样式 使用 方式1 let highRoad new Cesium.WebMapServiceImageryProvider({url: http://local…

Spring Cloud学习笔记(Nacos):Nacos持久化(未完成)

这是本人学习的总结&#xff0c;主要学习资料如下 - 马士兵教育 1、Overview2、单机使用MySQL 1、Overview 我们关闭单机下的Nacos后&#xff0c;再重新启动会发现之前配置的内容没有被删除。这时因为Nacos有内嵌的数据库derby&#xff0c;会自己持久化。 但是在集群的情况下…

KAN(Kolmogorov-Arnold Network)的理解 3

系列文章目录 第一部分 KAN的理解——数学背景 第二部分 KAN的理解——网络结构 第三部分 KAN的实践——第一个例程 文章目录 系列文章目录前言KAN 的第一个例程 get started 前言 这里记录我对于KAN的探索过程&#xff0c;每次会尝试理解解释一部分问题。欢迎大家和我一起讨…

百度/迅雷/夸克,网盘免费加速,已破!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 之前给大家安利了百度网盘及迅雷的加速方法&#xff0c;详细方法及获取参考之前文章&#xff1a; 刚刚&#xff01;度盘、某雷已破&#xff01;速度50M/s&#xff01; 本次主要介绍夸…

simulink基础学习笔记

写在前面 这个笔记是看B站UP 快乐的宇航boy 所出的simulink基础教程系列视频过程中记下来的&#xff0c;写的很粗糙不完整&#xff0c;也不会补。视频教程很细跟着做就行。 lesson1-7节的笔记up有&#xff0c;可以加up的群&#xff0c;里面大佬挺活跃的。 lesson8 for循环 For …

【C++初阶学习】第十二弹——stack和queue的介绍和使用

C语言栈&#xff1a;数据结构——栈(C语言版)-CSDN博客 C语言队列&#xff1a;数据结构——队列&#xff08;C语言版&#xff09;-CSDN博客 前言&#xff1a; 在之前学习C语言的时候&#xff0c;我们已经学习过栈与队列&#xff0c;并学习过如何使用C语言来实现栈与队列&…

OCR图片转Excel表格:没结构化的弊端

随着OCR技术的不断发展&#xff0c;将表格图片转为excel已不再是难题&#xff0c;但是&#xff0c;目前市面上的程序还大多处于仅能将图片表格转为普通的excel格式阶段&#xff0c;而不能将其结构化&#xff0c;这样就会产生许多的弊端&#xff0c;具体弊端如下&#xff1a; &l…

数据容器的通用操作、字符串大小比较 总结完毕!

1.数据容器的通用操作 1&#xff09;五类数据容器是否都支持while循环/for循环 五类数据容器都支持for循环遍历 列表、元组、字符串都支持while循环&#xff0c;集合、字典不支持&#xff08;无法下标索引&#xff09; 尽管遍历的形式不同&#xff0c;但都支持遍历操作 2&a…

办公软件 Office 安装教程(亲测有效)

Office 现已更名为 Microsoft 365。习惯还是称作 Office。 1、Office 套装下载 Windows 的样子 这里下载的是最新版本的 O365ProPlus 安装完成后&#xff0c;点击关闭&#xff08;请先不要打开&#xff09;。 Mac 的样子 这里下载的是Office for Mac 2019&#xff08;更多版…

速递FineWeb:一个拥有无限潜力的15T Tokens的开源数据集

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

内核宕机自救

【问题】在测试内核级防篡改时&#xff0c;偶尔会遇到内核宕机的问题 【结论】进入紧急救援模式&#xff0c;将服务进程文件的start注释掉&#xff0c;即可 在Linux系统启动时&#xff0c;内核启动顺序选择界面&#xff0c;进入系统欢迎界面按上下左右键进入GRUB界面&#xff…

欧佩克+同意集体性减产延长,油价能否稳住?

KlipC报道&#xff1a;欧佩克组织同意将延长目前部分减产协议至2025年&#xff0c;以支撑油价。主要成员国把2023年11月宣布的日均220万桶的自愿减产措施延长至今年9月底&#xff0c;将在10月份根据市场情况开始缩减自愿减产规模。 高盛分析师表示&#xff0c;“我们认为这次欧…