2. 网络协议栈分层模型:OSI七层模型与TCP/IP四层模型回顾、Linux内核网络子系统的分层架构

2.1 分层模型的核心思想

网络协议栈采用分层设计,每一层只关注特定的通信功能,并为上层提供清晰的服务接口。这种设计带来了以下关键优势:

  • 模块化:各层独立开发与优化,降低系统复杂度。
  • 标准化:层间接口固定,允许不同厂商实现互操作。
  • 可替换性:修改某一层的实现不影响其他层。
学习提示: 理解分层模型是深入Linux内核网络协议栈的基石。内核中的网络子系统严格遵循分层原则,但为了性能进行了大量优化和合并。

2.2 OSI七层模型回顾

OSI(Open Systems Interconnection)模型由ISO制定,是理论上的网络通信标准框架。它从下到上分为七层:

层次 名称 核心功能 典型协议/设备
7 应用层 为用户应用提供网络服务接口 HTTP, FTP, SMTP, DNS
6 表示层 数据格式转换、加密、压缩 SSL/TLS, JPEG, ASCII
5 会话层 建立、管理和终止会话 NetBIOS, RPC
4 传输层 端到端连接、可靠传输、流量控制 TCP, UDP
3 网络层 路由选择、逻辑寻址、分组转发 IP, ICMP, 路由器
2 数据链路层 帧封装、介质访问控制、差错检测 Ethernet, PPP, 交换机
1 物理层 比特流传输、电气信号、机械接口 RJ45, 光纤, 集线器
关键概念: OSI模型是“法律上的标准”,而TCP/IP模型是“事实上的标准”。Linux内核的实现更贴近TCP/IP模型,但理解OSI有助于厘清各层职责边界。

2.3 TCP/IP四层模型回顾

TCP/IP模型是互联网实际运行的协议栈,它将OSI的上三层合并为应用层,并将数据链路层和物理层合并为网络接口层:

  • 应用层:对应OSI的5-7层,包含所有用户态网络应用协议。
  • 传输层:提供端到端的通信服务,核心协议为TCP(可靠、面向连接)和UDP(不可靠、无连接)。
  • 网络层:核心是IP协议,负责数据包的路由和转发。
  • 网络接口层:负责将IP数据包封装成帧,并通过物理介质发送。

以下是TCP/IP模型与OSI模型的对应关系图:

OSI七层模型 vs TCP/IP四层模型 OSI 七层模型 7. 应用层 6. 表示层 5. 会话层 4. 传输层 3. 网络层 2. 数据链路层 1. 物理层 TCP/IP 四层模型 应用层 (HTTP, FTP, DNS, SSH) 传输层 (TCP, UDP) 网络层 (IP, ICMP, ARP) 网络接口层

2.4 Linux内核网络子系统的分层架构

Linux内核的网络子系统在实现上借鉴了TCP/IP模型,但为了兼顾性能和灵活性,其内部架构更为精细。从内核源码视角看,网络子系统主要分为以下几层:

  1. 系统调用接口层:用户态程序通过socket API(如 socket(), send(), recv())陷入内核,该层负责将系统调用转换为内核协议栈的操作。
  2. 协议无关层:提供通用的socket管理机制,如 struct socket 和 struct sock。它不关心具体是TCP还是UDP,只提供统一的接口。
  3. 传输层协议实现:包含TCP、UDP、SCTP等协议的实现。核心数据结构是 struct tcp_sock 和 struct udp_sock,它们都内嵌了通用的 struct sock。
  4. 网络层协议实现:主要实现IPv4和IPv6协议,包括路由查找、分片与重组、ICMP处理等。核心数据结构是 struct sk_buff,它贯穿整个协议栈。
  5. 邻居子系统:负责IP地址到链路层地址的映射,即ARP(IPv4)和NDISC(IPv6)的实现。
  6. 网络设备层:抽象了物理和虚拟网络设备,通过 struct net_device 表示。该层负责将数据包传递给具体的设备驱动程序。
  7. 设备驱动程序层:直接与硬件交互,负责数据的收发。
性能关键点: 在Linux内核中,sk_buff 是唯一贯穿所有层次的数据结构。理解其内存布局、头部预留、数据指针操作是掌握协议栈性能优化的核心。

以下是Linux内核网络子系统分层架构的详细示意图:

Linux内核网络子系统分层架构 用户空间 (User Space) — 应用程序 / Socket API 内核空间 (Kernel Space) 系统调用接口层 (sys_socket, sys_send, sys_recv) 协议无关层 (struct socket, struct sock, VFS操作) 传输层 (TCP / UDP / SCTP) struct tcp_sock, struct udp_sock, 拥塞控制, 流量控制 网络层 (IPv4 / IPv6) 路由查找 (FIB), 分片与重组, ICMP, 邻居子系统 (ARP/NDISC) 网络设备层 (struct net_device, dev_queue_xmit, netif_rx) 设备驱动程序层 (hard_start_xmit, 中断处理, NAPI) 物理硬件 (NIC, 网卡) sk_buff 数据流

2.5 分层架构中的数据封装与传递

当应用程序发送数据时,数据在协议栈中从上到下逐层传递,每一层都会添加自己的头部信息(封装)。接收数据时则相反,从下到上逐层剥离头部。这个过程在Linux内核中通过操作 sk_buff 结构体中的指针来实现,避免了大量的数据拷贝。

核心机制: Linux内核通过 sk_buff 中的 head, data, tail, end 四个指针来管理协议头。发送时,data 指针前移并写入新头部;接收时,data 指针后移以剥离头部。这种“零拷贝”头部操作是内核网络高性能的关键。

以下是数据发送时的头部封装流程:

阶段 操作层 添加/操作的内容 sk_buff 指针变化
1 应用层 用户数据 (payload) data 指向 payload 起始
2 传输层 (TCP) TCP 头部 (源端口、目的端口、序列号等) data 前移,写入 TCP 头
3 网络层 (IP) IP 头部 (源IP、目的IP、TTL等) data 前移,写入 IP 头
4 网络设备层 链路层头部 (MAC地址、EtherType) data 前移,写入 MAC 头
5 设备驱动 将完整的帧发送到物理介质 sk_buff 传递给驱动
深入思考: 为什么Linux内核不直接使用OSI七层模型?因为OSI模型过于理论化,分层过多会导致函数调用开销剧增。Linux内核在保证模块化的前提下,通过合并层(如将表示层和会话层合并到应用层)和优化数据传递路径(如使用NAPI轮询替代传统中断)来追求极致的网络吞吐性能。