3. 分片重组机制:接收端分片重组流程、超时机制与资源管理

IP分片在发送端将大数据包切分为若干小片(Fragment),接收端则必须将这些片重新组装为完整的原始IP数据报。分片重组是网络协议栈中一个计算密集且状态敏感的过程,其效率直接影响大包传输的吞吐量,而超时与资源管理则决定了系统的健壮性与抗攻击能力。

3.1 接收端分片重组流程

Linux内核在IPv4协议栈中通过 ip_defrag() 函数完成分片重组。重组流程遵循以下核心步骤:

  1. 分片到达:网络设备驱动将数据包送入IP层,ip_local_deliver() 检测到 MF 标志或片偏移非零时,将分片交给 ip_defrag()。
  2. 查找重组队列:根据 (源IP, 目的IP, 标识符ID, 协议) 四元组哈希查找对应的 inet_frag_queue 队列。若不存在则新建队列。
  3. 分片插入与排序:将新分片按片偏移量插入队列中的红黑树(rbtree),同时更新已接收数据长度和分片位图。
  4. 完整性检查:当所有分片(包括首片和尾片)均已到达时,触发重组操作。
  5. 重组与提交:将各分片的数据载荷按偏移顺序拷贝到连续缓冲区,重建IP首部,然后提交给上层协议(TCP/UDP)。
关键数据结构: struct inet_frag_queue 是重组队列的核心,内部包含红黑树根节点、已接收长度、分片位图、定时器以及引用计数。每个分片以 struct sk_buff 形式挂载在红黑树上。
性能要点: 红黑树查找与插入的时间复杂度为 O(log n),相比早期内核使用的链表(O(n))在大分片数场景下性能提升显著。对于常见的小分片数(2-5片),红黑树与链表的差异不大,但在极端分片攻击场景下红黑树能有效防止CPU耗尽。
接收端分片重组流程 分片到达 IP 层 ip_defrag() 入口 查找/创建重组队列 红黑树插入分片 所有分片到达? 等待更多分片 重组并提交上层 定时器超时则丢弃整个队列

3.2 超时机制

分片重组不能无限等待。Linux内核为每个重组队列维护一个低精度定时器(基于jiffies),默认超时时间为 IP_FRAG_TIME(通常为30秒)。超时机制的设计要点如下:

参数 默认值 说明
IP_FRAG_TIME 30 秒 (HZ * 30) 分片重组队列的最大存活时间
sysctl net.ipv4.ipfrag_time 30 用户态可调参数,单位秒
sysctl net.ipv4.ipfrag_high_thresh 262144 (256KB) 分片内存使用上限(触发回收)
sysctl net.ipv4.ipfrag_low_thresh 196608 (192KB) 分片内存使用下限(停止回收)

超时处理流程:

  • 定时器到期时,调用 inet_frag_evictor() 回收该队列。
  • 回收操作释放所有已缓存的分片 sk_buff,并销毁队列。
  • 若系统内存压力大(分片总内存超过 high_thresh),内核会主动提前回收最老的队列,即使其定时器尚未到期。
安全风险: 分片超时机制是防范 分片攻击(Fragment Attack) 的第一道防线。攻击者发送大量不完整的分片流,消耗系统内存。Linux 通过 ipfrag_high_thresh 和 ipfrag_low_thresh 实现内存水位控制,当超过高水位时强制驱逐旧队列。

3.3 资源管理

分片重组的资源管理涉及内存分配、队列生命周期和哈希表结构三个维度。Linux内核使用 inet_frags 全局结构统一管理所有协议族(IPv4/IPv6)的分片资源。

3.3.1 内存管理策略

  • per-net 命名空间隔离:每个网络命名空间拥有独立的分片内存计数器,避免容器间相互影响。
  • 两级阈值回收:当已用内存超过 high_thresh 时,内核同步回收队列直到内存降至 low_thresh 以下。
  • 分片缓存复用:使用 skb 的 frag_list 链直接链接分片,避免大块内存拷贝(仅在重组最终阶段执行一次拷贝)。

3.3.2 哈希表与队列结构

分片队列通过哈希表组织,哈希键为 (src, dst, id, proto) 四元组。哈希表大小由 sysctl net.ipv4.ipfrag_hash_bits 控制(默认17,即131072个桶)。

分片资源管理架构 分片哈希表 (hash_bits=17, 131072 个桶) 桶[0] 桶[1] 桶[N] 队列A (src,dst,id) 队列B (src,dst,id) 队列C (src,dst,id) 单个 inet_frag_queue 内部结构 红黑树根节点 分片位图 定时器 引用计数 sk_buff 链表 已接收长度

3.4 性能调优关键参数

sysctl 参数 默认值 调优建议
net.ipv4.ipfrag_time 30 高延迟链路(如卫星)可增大到60-120;低延迟数据中心可减小到5-10
net.ipv4.ipfrag_high_thresh 262144 大并发分片场景可增大到1MB以上;注意与系统总内存的平衡
net.ipv4.ipfrag_low_thresh 196608 通常为 high_thresh 的 75%
net.ipv4.ipfrag_hash_bits 17 大流量场景可增大到19-20,减少哈希冲突
调优原则:
  1. 减少分片发生:优先通过路径MTU发现(PMTUD)避免分片,分片重组始终是性能损耗点。
  2. 匹配网络延迟:ipfrag_time 应略大于网络最大RTT,避免正常分片因超时被丢弃。
  3. 内存与性能平衡:增大 high_thresh 可减少因内存压力导致的队列驱逐,但会增加内存占用。
  4. 哈希表大小:hash_bits 每增加1,桶数翻倍,内存开销约增加8KB(64位系统),但能显著降低链式冲突。

3.5 分片重组与GRO的交互

在启用GRO(Generic Receive Offload)的网卡上,分片重组发生在GRO之后、IP层之前。GRO会尝试合并同一流的小包,但不会合并分片——分片必须保持独立直到IP层重组。这种设计避免了GRO层处理分片逻辑的复杂性,但也意味着分片无法享受GRO的合并收益。

实践建议: 在高速网络(10Gbps+)中,应尽量避免IP分片。如果必须使用分片(如IPsec隧道场景),建议增大 ipfrag_high_thresh 并配合RPS(Receive Packet Steering)将分片处理分散到多个CPU核心,避免单核瓶颈。