3.2 Linux 系统收包流程

本节,我们了解数据包进入网卡(eth0)后,Linux 内核中各个模块是如何相互协作的,对 Linux 系统下网络包的接收过程有个全局性的认识。

总结 Linux 系统收包流程,笔者绘制出图 3-1。


图 3-1 Linux 系统收包流程

  1. 当外部网络发送数据包到服务器时,首先由网卡 eth0 接收该数据包。
  2. 网卡通过 DMA(Direct Memory Access,直接内存访问)技术,将数据包直接拷贝到内核中的 RingBuffer(环形缓冲区)等待 CPU 处理。RingBuffer 是一种首尾相接的环形数据结构,它的主要作用是作为缓冲区,缓解网卡接收数据的速度快于 CPU 处理数据的速度问题。
  3. 数据包成功写入 RingBuffer 后,网卡产生 IRQ(Interrupt Request,硬件中断),通知内核有新的数据包到达。
  4. 内核收到硬件中断后,立即调用对应的中断处理函数。通常情况下,中断处理函数会简单地标记有新数据到达,并唤醒 ksoftirqd 内核线程来处理软中断(SoftIRQ)。
  5. 软中断处理过程中。内核调用网卡驱动提前在内核中注册的 NAPI(New API)poll 接口,从 RingBuffer 中提取数据包,并生成 skb(Socket Buffer)数据。skb 是 Linux 内核中用于管理网络数据包的主要结构。它包含了网络包的所有信息,包括头部、数据负载等,并在内核的各个网络协议层之间传递。
  6. skb 被传递到内核协议栈中进行处理。这里涉及多个网络层次的处理操作:
    • 网络层(L3 Network layer):根据主机中的路由表,判断数据包路由到哪一个网络接口(Network Interface)。这里的网络接口可能是稍后介绍的虚拟设备,也可能是物理网卡 eth0 接口。
    • 传输层(L4 Transport layer):如解/封数据包,处理网络地址转换(NAT)、连接跟踪(conntrack)等操作。
  7. 内核协议栈处理完成后,数据包被传递到 socket 接收缓冲区。应用程序随后利用系统调用(如 Socket API)从缓冲区中读取数据。至此,整个收包过程结束。

分析 Linux 系统处理网络数据包的过程,我们可以注意到潜在问题:数据包的处理流程过于冗长。整个处理流程涉及到多个网络层协议栈,如数据链路层、网络层、传输层和应用层。这些网络层之间传递数据需要封包/解包,以及频繁的操作系统上下文切换。

对于多数常规应用,Linux 内核的局限性通常无需特别关注。但对于处理大规模并发连接的网络密集型系统,Linux 内核造成的瓶颈就变得不可忽视。除了想办法优化内核网络,业界提出了“绕过内核”的技术思路,如图 3-1 所示的 XDP 和 DPDK 技术,笔者将在 3.4 节中详细介绍它们的原理与区别。

接下来,我们将继续深入 Linux 内核网络模块,研究 Linux 内核是如何过滤、修改和转发数据的。

总字数:841
Last Updated:
Contributors: isno