「Linux」- 网络栈

Linux 网络栈

数据包的发送过程(概览)

在进行网络传输时,数据包就会按照协议栈:
1)对上层发来的数据,根据网络协议而封装该层的协议头(即增加固定格式的元数据),但不会修改原始数据;
2)再发送给下一层;

在 Linux Kernel 中的网络栈

应用程序 => 系统调用 => 套接字接口 => 传输层/网络层/接口层 => 网卡驱动程序/物理网卡设备。

网卡是发送和接收网络包的基本设备。在系统启动过程中,网卡通过内核中的网卡驱动程序注册到系统中,在网络收发过程中,内核通过中断跟网卡进行交互。

网络包的接收流程 与 网络包的发送流程

网络包的发送流程

1)应用程序 => Socket API(系统调用,陷入到内核态的套接字层),套接字层会把数据包放到 Socket 发送缓冲区
2)网络协议栈从 Socket 发送缓冲区中取出数据包,分别为其增加 TCP 头和 IP 头,执行路由查找确认下一跳的 IP,并按照 MTU 大小进行分片。
3)分片后的网络包,再送到网络接口层,进行物理地址寻址,以找到下一跳的 MAC 地址,然后添加帧头和帧尾,放到发包队列中。
4)这一切完成后,会有软中断通知驱动程序:发包队列中有新的网络帧需要发送。
5)驱动程序通过 DMA ,从发包队列中读出网络帧,并通过物理网卡把它发送出去

网络包的接收流程

1)网络帧到达网卡后,网卡会通过 DMA 方式,把这个网络包放到收包队列中,然后通过硬中断,告诉中断处理程序已经收到了网络包。
2)网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到 sk_buff 缓冲区中;然后再通过软中断,通知内核收到了新的网络帧
3)内核协议栈从缓冲区中取出网络帧,并通过网络协议栈,从下到上逐层处理这个网络帧

A)在链路层检查报文的合法性,找出上层协议的类型(比如 IPv4 还是 IPv6),再去掉帧头、帧尾,然后交给网络层。

B)网络层取出 IP 头,判断网络包下一步的走向,比如是交给上层处理还是转发。当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(比如 TCP 还是 UDP),去掉 IP 头,再交给传输层处理。

C)传输层取出 TCP 头或者 UDP 头后,根据 < 源 IP、源端口、目的 IP、目的端口 > 四元组作为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓存中

4)应用程序就可以使用 Socket 接口,读取到新接收到的数据

DMA

1)内核分配一个主内存地址段(DMA缓冲区),网卡设备可以在DMA缓冲区中读写数据
2)当来了一个网络包,网卡将网络包写入DMA缓冲区,写完后通知CPU产生硬中断
3)硬中断处理程序锁定当前DMA缓冲区,然后将网络包拷贝到另一块内存区,清空并解锁当前DMA缓冲区,然后通知软中断去处理网络包。

当发送数据包时,与上述相反。链路层将数据包封装完毕后,放入网卡的DMA缓冲区,并调用系统硬中断,通知网卡从缓冲区读取并发送数据。

常见问题

How many socket connections can a web server handle?
Is a TCP server limited to 65535 clients?

参考文献

33 | 关于 Linux 网络,你必须知道这些(上)