3.2 Linux 系统收包流程
本节,我们了解数据包进入网卡(eth0)后,Linux 内核中各个模块是如何相互协作的,对 Linux 系统下网络包的接收过程有个全局性的认识。
Linux 系统收包流程,如图 3-1 所示。
图 3-1 Linux 系统收包流程
- 外部数据包到达主机时,首先由网卡 eth0 接收。
- 网卡通过 DMA(Direct Memory Access,直接内存访问)技术,将数据包拷贝到内核中的 RingBuffer(环形缓冲区)等待 CPU 处理。RingBuffer 是一种首尾相接的环形数据结构,它作为缓冲区,缓解网卡接收数据的速度快于 CPU 处理数据的速度问题。
- 接着,网卡产生 IRQ(Interrupt Request,硬件中断),通知内核有新的数据包到达。
- 内核调用中断处理函数,标记新数据到达。接着,唤醒 ksoftirqd 内核线程,执行软中断(SoftIRQ)处理。
- 软中断处理中,内核调用网卡驱动的 NAPI(New API)poll 接口,从 RingBuffer 中提取数据包,并转换为 skb(Socket Buffer)格式。skb 网络子系统中用于描述网络数据包的核心数据结构。数据包的发送、接收还是转发,内核都会通过 skb 来处理。
- skb 被传递到内核协议栈,在多个网络层次间处理:
- 网络层(L3 Network layer):根据主机中的路由表,判断数据包路由到哪一个网络接口(Network Interface)。这里的网络接口可能是稍后介绍的虚拟设备,也可能是物理网卡 eth0 接口。
- 传输层(L4 Transport layer):处理网络地址转换(NAT)、连接跟踪(conntrack)等。
- 内核协议栈处理完成后,数据包被传递到 socket 接收缓冲区。应用程序利用系统调用(如 Socket API)从缓冲区读取数据。至此,整个收包过程结束。
分析 Linux 系统处理网络数据包的过程,我们注意到潜在问题:数据包的处理流程过于冗长。处理流程涉及到多个网络层协议栈(如数据链路层、网络层、传输层和应用层),网络层协议栈之间需要封包/解包,还有频繁的上下文切换(Context Switch),都让 Linux 内核的瓶颈不可忽视。对于设计网络密集型系统,优化内核参数是不可或缺的一环。
除了想办法优化内核参数,业界提出了“绕过内核”的技术思路,如图 3-1 所示的 XDP 和 DPDK 技术,笔者将在 3.4 节中详细介绍它们的原理与区别。
接下来,我们将继续深入 Linux 内核网络模块,研究 Linux 内核是如何过滤、修改和转发数据的。
总字数:714字