本页目录

TCP/IP 协议栈

覆盖: IPv4/IPv6 收发路径 → TCP 状态机 → 拥塞控制 (CUBIC/BBR) → 流控 (滑动窗口) → socket buffer (sk_wmem/sk_rmem) → TCP fast path 内核版本: 2.6 ~ 6.x

概述

Linux TCP/IP 栈是内核中优化最极致的子系统之一。在高速路径 (established sockets, 顺序到达的数据包),每个包的处理只有几十条指令。本文将聚焦 TCP 的接收快速路径和拥塞控制。

IPv4 收发

ip_rcv → ip_local_deliver (收包)

// net/ipv4/ip_input.c
ip_rcv()
  ├─ 验证: version==4, checksum OK, 长度合法
  ├─ netfilter NF_INET_PRE_ROUTING (iptables raw/mangle)
  └─ ip_rcv_finish()
      ├─ 查路由表: fib_lookup() → dst_entry
      │   → RTN_LOCAL: 给本机的 → ip_local_deliver()
      │   → RTN_UNICAST: 转发 → ip_forward()
      └─ ip_local_deliver()
          ├─ netfilter NF_INET_LOCAL_IN (iptables filter)
          └─ ip_local_deliver_finish()
              └─ ipprot->handler → tcp_v4_rcv() / udp_rcv()

ip_queue_xmit (发包)

// net/ipv4/ip_output.c
__ip_queue_xmit(sk)
  ├─ 查路由: ip_route_output_ports() → dst_entry + 源 IP
  ├─ 构造 IP header: protocol, TTL, DF flag, ... 
  ├─ netfilter NF_INET_LOCAL_OUT
  └─ ip_local_out()
      ├─ netfilter NF_INET_POST_ROUTING
      └─ dev_queue_xmit() → QoS qdisc → 网卡驱动 ndo_start_xmit()

TCP 快速路径: tcp_rcv_established

// net/ipv4/tcp_input.c
// 这是 TCP 收包的最热路径 (established socket, 顺序包)

tcp_rcv_established(sk, skb)
  // fast path (90%+ 的包走这里):
  ├─ 检查 header prediction:
  │   ├─ PSH bit? → 跳过
  │   ├─ 顺序到达? (seq == rcv_nxt) ✓
  │   ├─ 窗口非零? ✓
  │   └─ URG/RST/SYN? → 跳过
  │
  ├─ 拷贝数据到 receive queue: tcp_queue_rcv()
  │   └─ skb_copy_datagram_msg() → 直接到用户缓冲区? (如果是 MSG_DONTWAIT)
  │
  ├─ 更新 rcv_nxt, 窗口通告
  │
  └─ 如果数据已入 queue → sk_data_ready() → 唤醒 epoll/read

  // slow path:
  └─ OOO (乱序) / SACK / 窗口满 / FIN / RST → tcp_validate_incoming()

TCP 状态机

TCP 状态机:从三次握手到主动/被动关闭 CLOSED LISTEN SYN_RECV ESTABLISHED bind + listen accept SYN active close (FIN) FIN_WAIT1 FIN_WAIT2 CLOSE_WAIT (对方关了, 本地还没关) ACK CLOSING TIME_WAIT (2MSL) LAST_ACK CLOSED ESTABLISHED 之后两条路:主动关闭走 FIN_WAIT1→FIN_WAIT2→TIME_WAIT(2MSL),或同时关闭走 CLOSING; 被动关闭(对方先发 FIN)走 CLOSE_WAIT→LAST_ACK→CLOSED。

拥塞控制

// net/ipv4/tcp_cong.c
// 可插拔的拥塞控制模块:
struct tcp_congestion_ops {
    void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked);
    void (*ssthresh)(struct sock *sk);    // 丢包时重设慢启动门限
    u32  (*undo_cwnd)(struct sock *sk);   // 虚假重传检测 → 回滚 cwnd
};

// CUBIC (默认):
//   cwnd = C * (t - K)^3 + W_max
//   K = cube_root(W_max * beta / C)
//   优点: 快速恢复, 公平, 在高速链路上表现好

// BBR (Bottleneck Bandwidth and RTT, Google):
//   不基于丢包,基于 BDP (Bandwidth-Delay Product)
//   测量: max BW (最近 10 轮) 和 min RTT (最近 10 秒)
//   目标: 保持 inflight ≈ BDP
//   优点: 在 bufferbloated 链路上远优于 CUBIC

TCP Socket Buffer 调优

# 发送缓冲区 (默认 16KB, 自动增长到 max)
cat /proc/sys/net/ipv4/tcp_wmem  # min default max
# 接收缓冲区
cat /proc/sys/net/ipv4/tcp_rmem

# 自动调优 (默认开启):
#   sk_wmem 和 sk_rmem 根据 RTT 和带宽探测自动增长
#   → 高 BDP 链路不需要手动设置大 buffer

调试

# TCP 连接状态
ss -tianp   # 含 cwnd, rtt, rcv_mss, 所有统计

# 拥塞控制
sysctl net.ipv4.tcp_congestion_control
cat /proc/sys/net/ipv4/tcp_available_congestion_control

# 丢包/重传统计
nstat -a | grep -E 'TcpRetrans|TcpExt'
cat /proc/net/snmp | grep Tcp

# 追踪 TCP 状态
bpftrace -e 'kprobe:tcp_set_state { printf("%s: %d -> %d\n", comm, arg1, arg2); }'

参考

  • 源码⁠: net/ipv4/tcp_input.c, net/ipv4/tcp_output.c, net/ipv4/tcp_cong.c, net/ipv4/tcp_cubic.c, net/ipv4/tcp_bbr.c
  • RFC: RFC 793 (TCP), RFC 5681 (Congestion Control), RFC 8312 (CUBIC)
  • LWN: "TCP fast path", "BBR congestion control"

关键词: tcp_rcv_established, fast path, CUBIC, BBR, congestion control, socket buffer, TCP state machine