Linux内核以太网驱动分析
1.网络接口卡接收和发送数据在Linux内核中的处理流程如下:
1. 网络接口卡(Network Interface Card, NIC)
- 作用:负责物理层的数据传输,将数据包从网络介质(如以太网线)读取到内存中,或者将内存中的数据包发送到网络介质上。
- 过程:
- 接收数据包:当NIC接收到数据包时,它会触发一个中断(
ei_interrupt
),通知内核有数据包到达。- 发送数据包:当NIC需要发送数据包时,它会从内存中读取数据包并通过网络介质发送出去。
2. 中断处理(
ei_interrupt
)
- 作用:处理NIC触发的中断,将接收到的数据包传递给内核协议栈。
- 过程:
- 当NIC接收到数据包时,会触发
ei_interrupt
中断处理程序。- 中断处理程序会将数据包封装成一个
SKB
(Socket Buffer),并将其传递给内核协议栈进行进一步处理。3. Socket Buffer(SKB)
- 作用:
SKB
是Linux内核中用于存储网络数据包的数据结构,它包含了数据包的头部信息和数据内容。- 过程:
- 在接收数据包时,
ei_interrupt
会将数据包封装成SKB
。- 在发送数据包时,
ei_start_xmit
会从SKB
中读取数据包并传递给NIC进行发送。4. 内核协议栈(Kernel Protocol Stack)
- 作用:负责处理网络协议(如TCP/IP),对数据包进行解析、封装和转发。
- 过程:
- 接收数据包:从
SKB
中读取数据包,进行协议解析和处理,然后将数据传递给用户空间的应用程序。- 发送数据包:从用户空间的应用程序接收数据,进行协议封装,然后将数据包封装成
SKB
并传递给NIC进行发送。5. 用户空间应用程序(User Space Application)
- 作用:运行在用户空间的应用程序,与网络进行交互。
- 过程:
- 接收数据包:从内核协议栈接收数据包,进行应用层处理。
- 发送数据包:将数据传递给内核协议栈,进行网络传输。
6.
ei_start_xmit
- 作用:负责将数据包从内核协议栈传递给NIC进行发送。
- 过程:
- 当内核协议栈需要发送数据包时,会调用
ei_start_xmit
函数。ei_start_xmit
会从SKB
中读取数据包,并将其传递给NIC进行发送。7.
net_device
和hard_start_xmit
- 作用:
net_device
是Linux内核中表示网络设备的数据结构,hard_start_xmit
是net_device
中的一个函数指针,用于实际的数据包发送操作。- 过程:
- 当
ei_start_xmit
需要发送数据包时,会调用net_device
中的hard_start_xmit
函数。hard_start_xmit
会将数据包传递给NIC进行实际的发送操作。
Linux内核直接把中断分成了两个部分:中断上半部和中断下半部。
在Linux内核中,中断处理被分为两个部分:中断上半部(Top Half)和中断下半部(Bottom Half)。这种设计的主要目的是为了提高系统的响应速度和效率,避免在中断处理过程中长时间占用CPU,导致其他任务无法执行。下面是对这两个部分的详细讲解:
1. 中断上半部(Top Half)
- 作用:处理中断的紧急部分,确保系统的实时性和响应速度。
- 特点:
- 优先级高:中断上半部的优先级非常高,可以立即抢占其他任务的执行。
- 执行时间短:中断上半部的执行时间非常短,通常只进行一些简单的操作,如保存现场、读取硬件状态等。
- 不能睡眠:中断上半部不能执行任何可能引起睡眠的操作,如等待I/O完成、申请内存等。
- 过程:
- 当硬件设备(如网络接口卡)触发中断时,CPU会立即停止当前任务的执行,转而执行中断上半部的处理程序。
- 中断上半部会进行一些紧急的操作,如保存现场、读取硬件状态、记录中断信息等。
- 完成紧急操作后,中断上半部会立即返回,继续执行被中断的任务。
2. 中断下半部(Bottom Half)
- 作用:处理中断的非紧急部分,完成中断的后续处理工作。
- 特点:
- 优先级低:中断下半部的优先级较低,不会立即抢占其他任务的执行。
- 执行时间长:中断下半部的执行时间较长,可以进行一些复杂的操作,如数据处理、内存申请等。
- 可以睡眠:中断下半部可以执行可能引起睡眠的操作,如等待I/O完成、申请内存等。
- 过程:
- 中断上半部在完成紧急操作后,会将一些后续处理工作交给中断下半部。
- 中断下半部会在适当的时候(如当前任务执行完毕、系统空闲时)被调度执行。
- 中断下半部会进行一些复杂的操作,如数据处理、内存申请等,完成中断的后续处理工作。
2.Linux内核网络设备驱动框架分为四个模块,分别为网络协议接口模块、网络设备接口模块、设备驱动功能模块、网络设备与媒介模块。
1. 网络协议接口模块
- dev_queue_xmit(): 这个函数负责将数据包从协议层传递到设备层。它会调用设备驱动程序的发送函数,将数据包放入设备的发送队列中。
- netif_rx(): 这个函数负责将数据包从设备层传递到协议层。它通常在中断处理程序中被调用,将接收到的数据包传递给协议栈进行处理。
2. 网络设备接口模块
- net_device结构体类型: 这是Linux内核中表示网络设备的数据结构。它包含了设备的各种属性和方法,如设备名、硬件地址、发送和接收函数等。这个结构体是连接协议层和设备层的关键。
3. 网络驱动功能模块
- hard_start_xmit(): 这是设备驱动程序中的发送函数。它负责将数据包从设备的发送队列中取出,并将其发送到物理设备上。
- 中断处理: 当物理设备接收到数据包时,会产生中断。中断处理程序会调用netif_rx()函数,将接收到的数据包传递给协议栈进行处理。
4. 网络设备与媒介模块
- 网络物理设备: 这是实际的网络硬件设备,如网卡、无线网卡等。它负责将数据包转换为电信号或无线信号,并通过物理媒介(如网线、无线信号)进行传输。
3.网络协议接口模块:
主要功能给上层协议提供透明的数据包发送和接收的接口,dev_queue_xmit()用于发送数据包,netif_rx()/netif_recieve_skb()用于接收数据包。不管是发送还是接收数据包都会使用到sk_buff结构体类型(套接字缓冲区),主要用在网络子系统中别的各层之间传输数据。
1. 数据包发送接口
dev_queue_xmit
功能与原型
- 功能:将构造好的数据包(
sk_buff
)加入发送队列,最终由底层驱动通过ndo_start_xmit
方法发送。- 原型:
int dev_queue_xmit(struct sk_buff *skb);
- 参数:
skb
为包含待发送数据的缓冲区指针。- 返回值:0表示成功加入队列,负值表示失败。
使用步骤
- 构造
sk_buff
:需填充协议头(如IP、TCP/UDP)和数据内容,并关联网络设备(skb->dev
)。- 调用发送接口:
struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);// 填充skb数据(如通过skb_put、skb_push等)skb->dev = dev; // 关联网络设备int ret = dev_queue_xmit(skb);if (ret < 0) {// 错误处理(如释放skb)}
- 注意:
dev_queue_xmit
最终调用驱动实现的ndo_start_xmit
函数完成实际发送。
2. 数据包接收接口
netif_rx
功能与原型
- 功能:将底层驱动接收到的数据包(
sk_buff
)提交给协议栈处理。- 原型:
int netif_rx(struct sk_buff *skb);
- 参数:
skb
为包含接收数据的缓冲区指针。- 返回值:表示接收队列状态(如
NET_RX_SUCCESS
或NET_RX_DROP
)。使用步骤
- 分配并填充
sk_buff
:struct sk_buff *skb = dev_alloc_skb(len + 2); // 分配缓冲区if (!skb) {// 内存不足处理return;}skb_reserve(skb, 2); // 预留协议头空间// 从硬件读取数据到skb->dataskb_put(skb, len); // 设置数据长度skb->protocol = eth_type_trans(skb, dev); // 设置协议类型(如ETH_P_IP)[[15, 18]]
- 提交到协议栈:
int result = netif_rx(skb);if (result == NET_RX_DROP) {// 数据包被丢弃处理}
- 注意:调用
netif_rx
后,驱动不可再访问skb
,协议栈会接管其生命周期。
功能和作用
- 数据包封装与解封装:
sk_buff
结构体用于封装和解封装网络数据包,包括各种网络协议头(如MAC头、网络层头、传输层头等)。- 数据包传输:在网络栈中,数据包在不同层之间传递时,
sk_buff
结构体作为数据包的载体,确保数据包在传输过程中的完整性和一致性。- 数据包管理:
sk_buff
结构体还包含了数据包的长度、引用计数、缓存区管理等信息,用于数据包的管理和调度。- 网络协议处理:在数据包的发送和接收过程中,
sk_buff
结构体用于存储和处理各种网络协议相关的数据和状态信息
1.
alloc_skb
功能
alloc_skb
是一个用于分配网络缓冲区(sk_buff
)的函数。它是一个方便的封装函数,用于简化_alloc_skb
的调用。alloc_skb
会根据指定的大小和优先级分配一个sk_buff
结构体。参数
size
: 需要分配的缓冲区大小。priority
: 分配掩码,用于指定分配的优先级。使用案例
#include <linux/skbuff.h>static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority) {return __alloc_skb(size, priority, 0, NUMA_NO_NODE); }// 使用示例 struct sk_buff *skb = alloc_skb(1024, GFP_ATOMIC); if (skb) {// 成功分配了缓冲区,可以进行后续操作// ...kfree_skb(skb); // 使用完毕后释放缓冲区 }
2.
dev_alloc_skb
功能
dev_alloc_skb
是一个用于分配网络设备缓冲区的函数。它是一个遗留的辅助函数,用于简化netdev_alloc_skb
的调用。参数
length
: 需要分配的缓冲区长度。使用案例
#include <linux/skbuff.h>static inline struct sk_buff *dev_alloc_skb(unsigned int length) {return netdev_alloc_skb(NULL, length); }// 使用示例 struct sk_buff *skb = dev_alloc_skb(1024); if (skb) {// 成功分配了缓冲区,可以进行后续操作// ...kfree_skb(skb); // 使用完毕后释放缓冲区 }
3.
netdev_alloc_skb
功能
netdev_alloc_skb
是一个用于分配网络设备缓冲区的函数。它根据指定的网络设备和长度分配一个sk_buff
结构体。参数
dev
: 指定的网络设备。length
: 需要分配的缓冲区长度。使用案例
#include <linux/skbuff.h>static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, unsigned int length) {return netdev_alloc_skb(dev, length, GFP_ATOMIC); }// 使用示例 struct net_device *dev = ...; // 获取网络设备 struct sk_buff *skb = netdev_alloc_skb(dev, 1024); if (skb) {// 成功分配了缓冲区,可以进行后续操作// ...kfree_skb(skb); // 使用完毕后释放缓冲区 }
4.
struct net_device
功能
struct net_device
是一个用于描述网络设备的结构体。它包含了网络设备的各种属性和配置信息。字段
name
: 网络设备的名称。name_node
: 网络设备名称节点。ifalias
: 网络设备的别名。mem_end
: 共享内存的结束地址。mem_start
: 共享内存的起始地址。base_addr
: 基地址。irq
: 中断号。使用案例
#include <linux/netdevice.h>// 使用示例 struct net_device *dev = ...; // 获取网络设备// 打印网络设备的名称 printk(KERN_INFO "Network device name: %s\n", dev->name);// 打印网络设备的中断号 printk(KERN_INFO "Network device IRQ: %d\n", dev->irq);
5.NAPI 结构体的整体功能
napi_struct
结构体是Linux内核中用于网络设备驱动程序的一种机制,旨在优化网络数据包的处理。它的主要功能包括:
- 减少中断处理频率:通过将数据包处理从中断上下文转移到轮询上下文,减少中断处理的频率,从而提高系统的性能。
- 权重控制:通过设置权重值,控制在一次轮询中可以处理的数据包数量,确保系统资源的合理分配。
- 轮询机制:提供一个轮询函数,用于在轮询上下文中处理数据包,避免在中断上下文中进行大量数据包处理。
NAPI 数据包信息的循环流程如下:
- 数据接收中断发生:当网络设备接收到数据包时,触发数据接收中断。
- 减半接收中断:通过NAPI机制,减少接收中断的频率,将数据包处理转移到轮询上下文。
- 以轮询试接收所有数据包或轮询权重耗尽:在轮询上下文中,通过轮询函数处理数据包,直到处理完所有数据包或达到权重限制。
- 开启接收中断:当轮询处理完成后,重新开启接收中断,等待下一次数据接收中断的发生。
#include <linux/netdevice.h>
#include <linux/napi.h>struct my_net_device {struct net_device *netdev;struct napi_struct napi;
};static int my_poll(struct napi_struct *napi, int budget)
{struct my_net_device *priv = container_of(napi, struct my_net_device, napi);int work_done = 0;// 处理数据包while (work_done < budget) {// 从硬件中读取数据包struct sk_buff *skb = my_read_skb_from_hardware();if (!skb)break;// 将数据包传递给上层协议栈netif_receive_skb(skb);work_done++;}if (work_done < budget) {// 如果处理的数据包数量小于预算值,就停止轮询napi_complete_done(napi, work_done);}return work_done;
}static irqreturn_t my_irq_handler(int irq, void *dev_id)
{struct my_net_device *priv = dev_id;// 触发轮询napi_schedule(&priv->napi);return IRQ_HANDLED;
}static int my_netdev_open(struct net_device *netdev)
{struct my_net_device *priv = netdev_priv(netdev);// 初始化napi_structnetif_napi_add(netdev, &priv->napi, my_poll, 64);// 启用中断enable_irq(netdev->irq);return 0;
}static int my_netdev_close(struct net_device *netdev)
{struct my_net_device *priv = netdev_priv(netdev);// 禁用中断disable_irq(netdev->irq);// 删除napi_structnetif_napi_del(&priv->napi);return 0;
}
相关文章:

Linux内核以太网驱动分析
1.网络接口卡接收和发送数据在Linux内核中的处理流程如下: 1. 网络接口卡(Network Interface Card, NIC) 作用:负责物理层的数据传输,将数据包从网络介质(如以太网线)读取到内存中,或…...
分布式微服务系统架构第92集:智能健康监测设备Java开发方案
加群联系作者vx:xiaoda0423 仓库地址:https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn 嗯,用户需要为血压、血糖、尿酸和血酮测试仪编写产品描述,同时涉及Java开发。首先,我得确定他们的需求是什么。可…...
【推荐项目】023-游泳俱乐部管理系统
023 游泳俱乐部管理系统 游泳俱乐部管理系统概述 前端技术框架: 我们优雅地采用了Vue.js作为游泳俱乐部管理系统的前端基础框架。Vue.js以其轻盈、高效和易于上手的特点,为我们的用户界面带来了极致的流畅性和响应速度。通过Vue.js,我们为…...
Webpack常见配置实例
webpack实例 打包构建流程对应的常见配置 1. mode: development2. entry: ./src/index.js3. output4. module.rules5. Loader6. Plugin7. devServerwebpack.config.js webpack常见配置实例 配置详解 mode: ‘development’: 设置 Webpack 运行模式&am…...
C++核心编程之STL
STL初识:从零开始的奇幻冒险 1 STL的诞生:一场代码复用的革命 很久很久以前,在编程的世界里,开发者们每天都在重复造轮子。无论是数据结构还是算法,每个人都得从头开始写,仿佛在无尽的沙漠中寻找绿洲。直到…...

Mac mini M4安装nvm 和node
先要安装Homebrew(如果尚未安装)。在终端中输入以下命令: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 根据提示操作完成Homebrew的安装。 安装nvm。在终端中输入以下命令…...

Level DB --- 写流程架构
Level DB是高效的k-v数据库,接受多线程写,既要保证多线程写临界区安全,同时又要保证写流程的尽量高效性。 写入数据 Level DB 用一个deque用来衔接生产-消费模型。一个新的kv写入请求,会先将kv封装成Writer结构体。插入之前要先…...

【中等】707.设计链表
题目描述 你可以选择使用单链表或者双链表,设计并实现自己的链表。 单链表中的节点应该具备两个属性:val 和 next 。val 是当前节点的值,next 是指向下一个节点的指针/引用。 如果是双向链表,则还需要属性 prev 以指示链表中的…...
深入理解Reactor Flux的生成方法
在Reactor框架中,Flux 是一个非常重要的概念,它用于表示一个可以产生多个事件的响应式流。通过 Flux 提供的多种生成方法,我们可以灵活地创建各种类型的流。本文将详细介绍 Flux.generate 方法的使用,并通过实例帮助读者更好地理解…...
next实现原理
Next.js 是一个基于 React 的 服务器端渲染(SSR) 和 静态生成(SSG) 框架,它的实现原理涉及多个关键技术点,包括 服务端渲染(SSR)、静态生成(SSG)、客户端渲染…...
LeetCode 热题 100 53. 最大子数组和
LeetCode 热题 100 | 53. 最大子数组和 大家好,今天我们来解决一道经典的算法题——最大子数组和。这道题在 LeetCode 上被标记为中等难度,要求我们找出一个具有最大和的连续子数组,并返回其最大和。下面我将详细讲解解题思路,并…...

DeepSeek 与大数据治理:AI 赋能数据管理的未来
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 1. 引言 在当今数字化时代,数据已成为企业和机构的重要资产,而大数据治理(Big Data Governan…...

【时时三省】(C语言基础)浮点型数据
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 浮点型数据 浮点型数据是用来表示具有小数点的实数的,为什么在C中把实数称为浮点数呢?在C语言中,实数是以指数正式存放在在储单元中的。一个实数表示为指数可以有不…...

【大模型】Ollama本地部署DeepSeek大模型:打造专属AI助手
【大模型】Ollama本地部署DeepSeek大模型:打造专属AI助手 Ollama本地部署DeepSeek大模型:打造专属AI助手一、Ollama简介二、硬件需求三、部署步骤1. 下载并安装Ollama(1)访问Ollama官网(2)安装Ollama 2. 配…...

2025.3.2机器学习笔记:PINN文献阅读
2025.3.2周报 一、文献阅读题目信息摘要Abstract创新点网络架构实验结论不足以及展望 一、文献阅读 题目信息 题目: Physics-Informed Neural Networks of the Saint-Venant Equations for Downscaling a Large-Scale River Model期刊: Water Resource…...

数据集笔记:新加坡 地铁(MRT)和轻轨(LRT)票价
数据连接 data.gov.sg 2024 年 12 月 28 日起生效的新加坡地铁票价 该数据集包含 MRT 和 LRT 票价的信息,包括: 票价类型(Fare Type):成人票、学生票、老年人票、残障人士票等。适用时间(Applicable Tim…...

如何修改安全帽/反光衣检测AI边缘计算智能分析网关V4的IP地址?
TSINGSEE青犀推出的智能分析网关V4,是一款集成了BM1684芯片的高性能AI边缘计算智能硬件。其内置的高性能8核ARM A53处理器,主频可高达2.3GHz,INT8峰值算力更是达到了惊人的17.6Tops。此外,该硬件还预装了近40种AI算法模型…...

Java 大视界 -- 基于 Java 的大数据分布式缓存一致性维护策略解析(109)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...

SyntaxError: positional argument follows keyword argument
命令行里面日常练手爬虫不注意遇到的问题,报错说参数位置不正确 修改代码后,运行如下图: 结果: 希望各位也能顺利解决问题,祝你好运!...

Ruby基础
一、字符串 定义 283.to_s //转为string "something#{a}" //定义字符串,并且插入a变量的值 something//单引号定义变量 %q(aaaaaaaaa) // 定义字符串,()内可以是任何数,自动转义双引号%Q("aaaaa"…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...