Linux网络软中断与数据包收发机制详解
1. Linux网络软中断概述
Linux内核2.4支持四种内置软中断,它们在系统的不同任务处理中发挥着重要作用:
-
HI_SOFTIRQ
:用于处理高优先级任务,例如定时器小任务。
-
NET_TX_SOFTIRQ
:处理网络传输中断。
-
NET_RX_SOFTIRQ
:处理网络接收中断。
-
TASKLET_SOFTIRQ
:处理低优先级任务。
这些软中断具有以下特点:
- 可以在不同的CPU上并行调度和运行,提高了系统的处理效率。
- 在
do_IRQ()
函数从中断返回时执行,确保中断处理的及时性。
- 可以通过调用
local_bh_disable()
函数在本地禁用,而在禁用期间仍可能发生中断。当调用
local_bh_enable()
函数重新启用软中断时,之前被禁用的软中断将被执行。
- 软中断的禁用和启用是嵌套设计的,方便进行复杂的中断管理。
此外,还提供了两个重要的接口:
-
raise_softirq()
:用于在当前CPU上调度软中断。
-
softirq_open()
:用于注册软中断,注册时需要提供
softirq_action
类型的对象和软中断编号。
softirq_vec
是一个
softirq_action
类型的数组,用于注册软中断。每个CPU都有一个内核守护进程来执行软中断。然而,在网络软中断方面存在一个小问题:如果同一连接的两个连续TCP数据包被不同的CPU中断处理,当前的软中断机制无法确定哪个数据包会先被处理。如果数据包的处理顺序与传输顺序相反,TCP会认为数据包乱序到达,这会影响TCP性能,因为接收到乱序段会立即生成ACK。在更糟糕的情况下,超过三个数据包可能会被重新排序,导致错误地进入快速恢复和快速重传状态。
2. 数据包收发机制基础
接下来,我们将重点讨论具有DMA功能的网卡上的数据包收发过程。这里不涉及硬件的具体功能,而是关注DMA描述符的初始化以及如何设计它们来接收和传输网络数据包。我们以一个具有DMA能力的以太网网络驱动为例进行讲解,同时会研究为网卡编程的网络DMA环形缓冲区的设计,以及处理数据包收发的中断处理程序。
2.1 DMA环形缓冲区的初始化
在加载驱动模块进行设备初始化时,会对网络设备的DMA缓冲区描述符进行初始化:
-
接收方面
:为每个DMA描述符分配DMA缓冲区,并进行初始化。
-
传输方面
:仅初始化DMA缓冲区描述符,不分配DMA缓冲区。
之后,会对设备寄存器进行编程,使其使用初始化后的DMA缓冲区描述符作为接收(Rx)和传输(Tx)的DMA缓冲区。每个DMA缓冲区描述符包含以下信息:
- 实际存储网络数据包的DMA缓冲区的物理地址。
- 某些控制标志。
- 下一个DMA缓冲区描述符的物理地址。
在进行DMA传输时,使用物理地址,因为DMA不了解内核虚拟地址。DMA可以在不干扰CPU的情况下,将帧从设备传输到DMA内存。
2.2 数据包接收过程
在具有DMA功能的网卡上,会为网络设备编程Rx DMA描述符,设备通过DMA传输将接收到的帧存储在这些描述符指向的DMA缓冲区中。当一个完整的帧通过设备的DMA传输存储到DMA缓冲区后,设备会触发Rx中断。Rx中断处理程序会从DMA Rx环形缓冲区中取出帧,并将下一个指针指向下一个描述符中的缓冲区,以便读取下一个帧。具体步骤如下:
1. Rx中断处理程序通过调用
netif_rx()
函数,将数据包排队到与发生中断的CPU对应的
softnet_data
数组元素(
queue → input_pkt_queue
)中。
2. 接收到数据包的设备也会被排队到当前CPU的
softnet_data
轮询列表(
softnet_data[cpu].poll_list
)中。
3. 在当前CPU上触发网络Rx软中断,该软中断将在同一CPU上处理。
由于任何数据包都只会排队到当前CPU对应的
softnet_data
数组元素中,因此不会出现两个CPU处理同一数据包的情况。即使同一设备可能被排队到不同CPU的软网络队列中,通过Rx软中断处理这些设备也不需要进行同步。
下面我们通过一个具体的例子来理解接收环形缓冲区的工作原理:
- 假设Rx环形缓冲区初始时没有接收到任何数据包,驱动程序会初始化三个指针:
next
指向要接收下一个帧的DMA描述符,
prev
指向最后接收帧的DMA描述符,
last
指向环形缓冲区的末尾。
- 当两个帧被接收但尚未触发中断时,
next
指针会顺时针移动两个描述符。此时,
next
指针与网卡实际接收到下一个帧的位置存在差异,
next
是Rx中断处理程序处理下一个帧的位置,而网卡接收到完整帧后,DMA引擎逻辑会将其指向下一个缓冲区。
- 当触发Rx中断并处理第一个帧时,
next
和
prev
指针会逆时针移动一个单位,
last
指针的位置保持不变。只有当相对于
last
指针处理了环形缓冲区的一半时,
last
指针的位置才会改变。在同一个Rx中断事件中,会处理Rx环形缓冲区中的所有帧。
整个数据包接收过程可以用以下mermaid流程图表示:
graph TD;
A[数据包到达网卡] --> B[DMA传输到Rx缓冲区];
B --> C[触发Rx中断];
C --> D[从Rx环形缓冲区取出帧];
D --> E[更新指针];
E --> F[将数据包排队到softnet_data];
F --> G[触发网络Rx软中断];
3. 数据包传输过程
我们从IP数据报准备好传输的栈点开始讨论。此时,数据报的输出设备已知,并且数据报会被排队到设备队列中。设备会调度传输队列中的数据包,设备的数据包调度器会逐个从设备队列中取出数据包,并调用特定于设备的硬件传输例程进行传输。硬件传输例程会为IP数据报构建链路层头部,并编程下一个可用的DMA Tx环形缓冲区指向要传输的帧。如果到目前为止硬件传输过程没有出错,数据包将被传输。数据包传输完成后,设备的DMA控制器会触发中断,通知内核帧传输的状态。在Tx中断处理程序中,会释放刚刚传输的缓冲区,并调整Tx环形缓冲区中第一个需要传输的描述符的指针。
3.1 传输环形缓冲区的管理
Tx环形缓冲区在设备初始化时进行初始化,设备使用三个指针来管理Tx环形缓冲区:
-
next
:指向Tx环形缓冲区中应存放下一帧进行传输的DMA描述符。
-
first
:指向Tx环形缓冲区中第一个要传输的DMA描述符。
-
last
:指向Tx环形缓冲区中最后一个要传输的描述符。
下面通过具体场景来理解传输环形缓冲区的工作过程:
- 当Tx环形缓冲区初始化后,一个帧被排队到控制器的Tx环形缓冲区,
next
指针会被修改,指向下一个应存放传输帧的缓冲区,但此时帧尚未传输。
- 在三个帧都排队到Tx环形缓冲区但尚未开始传输时,
next
指针指向第四个缓冲区,
last
指针指向第三个帧(即Tx环形缓冲区中最后一个要传输的帧)。
- 当一个帧被传输后,
first
指针会顺时针移动三个位置,
next
指针指向要传输的下一帧的位置。如果此时没有更多帧需要传输,会触发Tx中断。
- 在Tx中断处理程序中,会从
first
指针指向的位置开始释放Tx DMA缓冲区中排队的缓冲区,直到到达
next
指针或设备指针(指向要传输的下一个缓冲区)为止。每传输一个帧,DMA控制器的Tx指针会逆时针移动一个单位,指向下一个要传输的帧。
整个数据包传输过程可以用以下mermaid流程图表示:
graph TD;
A[IP数据报准备传输] --> B[排队到设备队列];
B --> C[调度传输];
C --> D[构建链路层头部并编程Tx缓冲区];
D --> E[传输数据包];
E --> F[触发Tx中断];
F --> G[释放缓冲区并调整指针];
3.2 传输过程中的缓冲区管理
如果DMA Tx环形缓冲区已满,会停止设备以停止进一步的数据包调度。当Tx环形缓冲区中的数据包传输完成后,在Tx中断处理程序中会启用设备队列,并尝试释放所有已成功传输但尚未从DMA Tx环形缓冲区中移除的缓冲区。
4. 以ETRAX网络控制器为例的实现细节
我们以ETRAX网络控制器为例,详细解释DMA环形缓冲区以及帧的接收和传输过程。
4.1 数据结构
-
struct etrax_eth_descr:该对象用于驱动程序实现DMA环形缓冲区,它包含两个部分: -
descr对象:是一个DMA控制器结构,用于在硬件上实现环形缓冲区。 -
skb:是一个网络缓冲区,指向完整的帧。 -
struct etrax_dma_descr:这是一个DMA控制器结构,用于在硬件上实现环形缓冲区。通过初始化这个对象,可以为Tx/Rx编程DMA控制器环形缓冲区。该描述符包含以下字段: -
sw_len:该DMA描述符(buf字段)指向的DMA缓冲区(包含数据)的长度。 -
ctrl:包含DMA通道的控制信息(标志),这些控制标志在cs 18.4中指定。 -
next:指向DMA环形缓冲区列表中的下一个描述符,cs 18.5解释了如何创建环形缓冲区。 -
buf:指向该描述符的DMA缓冲区的起始位置,即实际存储要传输到设备或从设备接收的数据的DMA位置。 -
hw_len:包含DMA数据的硬件长度,与sw_len不同,它可能包含一些表示帧结束的硬件控制字节。 -
status:包含控制器上DMA描述符的状态/控制标志,例如,状态可以设置为d_eop,表示该描述符指向的DMA缓冲区是大数据包分割成多个小数据包后的最后一个数据包。
4.2 设备初始化
在以太网设备的模块初始化时,会进行一些初始化操作,其中一些是通用的以太网协议操作,而另一些则是特定于网络控制器类型的操作:
1. 调用
etrax_ethernet_init()
函数初始化设备。
2. 调用
ether_setup()
函数初始化与以太网协议相关的通用回调例程和标志,这些例程与以太网头部的缓存和构建有关。
3. 从DMA描述符初始化接收和传输环形缓冲区。在硬件中,通过编程由
struct etrax_dma_descr
表示的DMA控制器来实现环形缓冲区。将整个DMA描述符链通过
etrax_dma_descr
对象的
next
字段链接起来,然后将第一个描述符写入实现环形缓冲区的硬件控制器特定位置。当第一个DMA描述符被处理后,控制器会从该结构的
next
字段加载下一个描述符,并在环形缓冲区中继续处理。因此,我们只需要构建Rx和Tx DMA描述符链,并将链的头部写入实现环形缓冲区的硬件逻辑中,DMA描述符的标志会处理其余的工作。
4.3 DMA传输环形缓冲区的初始化
从以太网驱动的示例(
cs 18.5
,第418 - 426行)可以看出,在模块初始化时会初始化Tx DMA描述符。这是一个
etrax_eth_descr
类型的
TxDescList
数组,大小为
NBR_OF_TX_DESC
。通过
descr
字段(
etrax_dma_descr
类型)的
next
字段将数组的连续元素链接起来,使
TxDescList
数组看起来像一个单链循环链表。在传输时,Tx的DMA描述符和
etrax_dma_descr
对象的所有字段都不会初始化,而是在需要传输帧时进行初始化。
最后,需要为设备初始化变量
myNextTxDesc
、
myLastTxDesc
和
myFirstTxDesc
:
-
MyNextTxDesc
:指向应存放下一帧进行传输的描述符,来自更高协议层的下一个完整帧将由
MyNextTxDesc
指向。
-
MyLastTxDesc
:是DMA描述符环形缓冲区中指向最后一个传输帧的描述符,该描述符的
d_eol
控制位始终被设置。
综上所述,Linux系统中的网络软中断和数据包收发机制是一个复杂而高效的系统,通过DMA环形缓冲区和中断处理程序的协同工作,实现了网络数据包的快速、稳定传输。了解这些机制对于优化网络性能和开发高效的网络应用程序具有重要意义。
Linux网络软中断与数据包收发机制详解
5. 数据包收发机制的优化思考
在实际的网络环境中,为了进一步提升数据包收发的性能和稳定性,我们可以从多个方面对现有的机制进行优化。
5.1 软中断调度优化
由于网络软中断可能会出现数据包处理顺序与传输顺序不一致的问题,影响TCP性能,我们可以考虑引入更智能的调度算法。例如,为每个连接维护一个单独的软中断队列,确保同一连接的数据包按照传输顺序进行处理。这样可以避免TCP数据包乱序到达的情况,减少不必要的ACK生成和错误的快速恢复、快速重传状态。
5.2 DMA环形缓冲区优化
- 缓冲区大小调整 :根据实际的网络流量情况,动态调整DMA环形缓冲区的大小。当网络流量较大时,增加缓冲区的大小,避免因缓冲区满而导致数据包丢失;当网络流量较小时,减小缓冲区的大小,节省系统资源。
- 缓冲区分配策略优化 :采用更高效的缓冲区分配策略,例如预分配一定数量的缓冲区,当需要时直接从预分配的缓冲区池中获取,减少动态分配和释放缓冲区的开销。
5.3 中断处理优化
- 中断合并 :将多个连续的中断合并为一个中断进行处理,减少中断处理的开销。例如,当多个数据包在短时间内到达时,可以等待一段时间,将这些数据包的中断合并处理。
- 中断亲和性设置 :将中断处理程序绑定到特定的CPU上,避免中断在不同CPU之间频繁迁移,提高中断处理的效率。
6. 实际应用案例分析
为了更好地理解Linux网络软中断和数据包收发机制在实际中的应用,我们来看一个简单的网络服务器案例。
假设我们有一个基于Linux系统的Web服务器,需要处理大量的HTTP请求。服务器使用具有DMA功能的网卡进行网络通信。
6.1 数据包接收过程
当客户端发送HTTP请求时,数据包通过网络到达服务器的网卡。网卡通过DMA传输将数据包存储到Rx DMA环形缓冲区中。一旦一个完整的数据包被存储到缓冲区,网卡触发Rx中断。
Rx中断处理程序将数据包排队到与发生中断的CPU对应的
softnet_data
数组元素中,并将接收到数据包的设备排队到当前CPU的
softnet_data
轮询列表中。然后,在当前CPU上触发网络Rx软中断,对数据包进行处理。
在这个过程中,如果网络流量较大,可能会出现Rx DMA环形缓冲区满的情况。为了避免数据包丢失,我们可以根据前面提到的优化策略,动态调整缓冲区的大小或采用更高效的缓冲区分配策略。
6.2 数据包传输过程
当Web服务器处理完客户端的请求后,需要将响应数据包发送回客户端。服务器将响应数据包排队到设备队列中,设备调度器从队列中取出数据包,并调用硬件传输例程进行传输。
硬件传输例程为响应数据包构建链路层头部,并编程下一个可用的DMA Tx环形缓冲区指向要传输的帧。数据包传输完成后,设备的DMA控制器触发Tx中断,在中断处理程序中释放缓冲区并调整指针。
在传输过程中,如果DMA Tx环形缓冲区已满,服务器会停止设备以停止进一步的数据包调度。当缓冲区中的数据包传输完成后,在Tx中断处理程序中启用设备队列,并释放已成功传输但尚未从缓冲区中移除的缓冲区。
7. 总结与展望
通过对Linux网络软中断和数据包收发机制的详细分析,我们了解到这些机制在网络通信中起着至关重要的作用。软中断的并行调度和运行提高了系统的处理效率,DMA环形缓冲区的使用实现了数据包的快速传输,中断处理程序确保了数据包的正确处理。
然而,在实际应用中,我们也面临着一些挑战,如网络软中断可能导致的数据包处理顺序问题、DMA环形缓冲区的管理问题等。通过对这些机制的深入理解和优化,我们可以提高网络性能,减少数据包丢失和错误,为网络应用程序提供更稳定、高效的运行环境。
未来,随着网络技术的不断发展,如5G、物联网等的普及,对网络性能的要求将越来越高。我们需要进一步研究和优化Linux网络软中断和数据包收发机制,以适应不断变化的网络环境。例如,探索更高效的软中断调度算法、更智能的DMA缓冲区管理策略等,为未来的网络应用提供更好的支持。
以下是一个总结表格,展示了Linux网络软中断和数据包收发机制的关键信息:
| 机制 | 关键信息 |
| — | — |
| 网络软中断 | 支持四种内置软中断(HI_SOFTIRQ、NET_TX_SOFTIRQ、NET_RX_SOFTIRQ、TASKLET_SOFTIRQ),可并行调度,在
do_IRQ()
返回时执行,可本地禁用和启用,提供
raise_softirq()
和
softirq_open()
接口 |
| 数据包接收 | 使用DMA Rx环形缓冲区,通过Rx中断处理,将数据包排队到
softnet_data
数组元素中,触发网络Rx软中断 |
| 数据包传输 | 使用DMA Tx环形缓冲区,通过Tx中断处理,释放缓冲区并调整指针 |
| ETRAX网络控制器 | 使用
struct etrax_eth_descr
和
struct etrax_dma_descr
实现DMA环形缓冲区,在设备初始化时进行相关操作 |
最后,我们可以用一个mermaid流程图来总结整个网络数据包的收发流程:
graph LR;
A[客户端发送请求] --> B[网卡接收数据包];
B --> C[DMA传输到Rx缓冲区];
C --> D[触发Rx中断];
D --> E[处理数据包并排队到softnet_data];
E --> F[触发网络Rx软中断进行处理];
F --> G[服务器生成响应数据包];
G --> H[排队到设备队列];
H --> I[调度传输并编程Tx缓冲区];
I --> J[传输数据包];
J --> K[触发Tx中断];
K --> L[释放缓冲区并调整指针];
L --> M[响应数据包发送到客户端];
通过以上的分析和总结,我们对Linux网络软中断和数据包收发机制有了更深入的认识,希望这些内容能对大家在网络编程和系统优化方面有所帮助。
超级会员免费看
2

被折叠的 条评论
为什么被折叠?



