一、源码目录分析

1.1 网络子系统核心目录结构

linux-5.10/net/                          # 网络子系统根目录
│
├── socket.c                             # Socket 层核心实现
├── sysctl_net.c                         # 网络 sysctl 接口
│
├── core/                                # 核心网络基础设施
│   ├── skbuff.c                         # SKB 缓冲区管理
│   ├── sock.c                           # Socket 通用操作
│   ├── dev.c                            # 网络设备核心
│   ├── netpoll.c                        # 网络轮询
│   ├── rtnetlink.c                      # 路由 netlink 接口
│   ├── neighbour.c                      # 邻居协议 (ARP/NDP)
│   ├── net-sysfs.c                      # sysfs 接口
│   ├── net-procfs.c                     # procfs 接口
│   ├── datagram.c                       # 数据报 socket 操作
│   ├── stream.c                         # 流 socket 操作
│   ├── filter.c                         # Socket 过滤器 (BPF)
│   ├── request_sock.c                   # 请求 socket 管理
│   └── dev_ioctl.c                      # 网络设备 ioctl 接口
│
├── ipv4/                                # IPv4 协议栈
│   ├── af_inet.c                        # IPv4 socket 族
│   ├── ip_input.c                       # IPv4 输入处理
│   ├── ip_output.c                      # IPv4 输出处理
│   ├── ip_forward.c                     # IPv4 转发
│   ├── tcp.c                            # TCP 核心
│   ├── tcp_input.c                      # TCP 输入处理
│   ├── tcp_output.c                     # TCP 输出处理
│   ├── tcp_timer.c                      # TCP 定时器
│   ├── tcp_ipv4.c                       # TCP IPv4 专用
│   ├── tcp_cong.c                       # TCP 拥塞控制框架
│   ├── tcp_cubic.c                      # CUBIC 拥塞控制算法(默认)
│   ├── tcp_bbr.c                        # BBR 拥塞控制算法
│   ├── tcp_nv.c                         # TCP-NV 数据中心拥塞控制
│   ├── tcp_vegas.c                      # Vegas 拥塞控制算法
│   ├── tcp_dctcp.c                      # DCTCP 数据中心 TCP
│   ├── tcp_westwood.c                   # Westwood 无线优化
│   ├── tcp_hybla.c                      # Hybla 卫星链路优化
│   ├── udp.c                            # UDP 实现
│   ├── icmp.c                           # ICMP 实现
│   ├── route.c                          # IPv4 路由
│   ├── fib_trie.c                       # FIB 路由表
│   ├── inet_fragment.c                  # IP 分片重组
│   ├── ping.c                           # ICMP echo
│   ├── raw.c                            # RAW socket
│   ├── syncookies.c                     # SYN Cookie 防攻击
│   └── sysctl_net_ipv4.c                # IPv4 sysctl
│
├── ipv6/                                # IPv6 协议栈
│   ├── af_inet6.c                       # IPv6 socket 族
│   ├── ip6_input.c                      # IPv6 输入
│   ├── ip6_output.c                     # IPv6 输出
│   ├── tcp_ipv6.c                       # TCP over IPv6
│   ├── udp.c                            # UDP over IPv6
│   ├── icmp.c                           # ICMPv6
│   ├── ndisc.c                          # 邻居发现
│   ├── route.c                          # IPv6 路由
│   ├── addrconf.c                       # 地址配置
│   └── sysctl_net_ipv6.c                # IPv6 sysctl
│
├── netfilter/                           # Netfilter 防火墙
│   ├── core.c                           # Netfilter 核心
│   ├── nf_conntrack_core.c              # 连接跟踪
│   ├── nf_conntrack_proto_tcp.c         # TCP 连接跟踪
│   ├── nf_tables_api.c                  # nftables 框架
│   └── x_tables.c                       # iptables 框架
│
├── sched/                               # 流量控制 (QoS)
│   ├── sch_generic.c                    # 通用调度器
│   ├── sch_fifo.c                       # FIFO 调度器
│   ├── sch_prio.c                       # 优先级调度器
│   ├── sch_htb.c                        # HTB 令牌桶
│   ├── sch_cake.c                       # CAKE 队列管理 
│   ├── sch_red.c                        # RED 主动队列管理
│   ├── sch_sfq.c                        # SFQ 公平队列
│   ├── sch_tbf.c                        # TBF 令牌桶过滤器
│   ├── sch_netem.c                      # 网络模拟器
│   └── cls_api.c                        # 分类器 API
│
├── netlink/                             # Netlink 通信
│   ├── af_netlink.c                     # Netlink socket
│   ├── genetlink.c                      # 通用 netlink
│   └── policy.c                         # 策略
│
├── bridge/                              # 网桥
│   ├── br.c                             # 网桥核心
│   ├── br_input.c                       # 网桥输入
│   ├── br_forward.c                     # 网桥转发
│   └── br_fdb.c                         # 转发数据库
│
├── unix/                                # UNIX domain socket
│   └── af_unix.c                        # AF_UNIX 实现
│
├── packet/                              # AF_PACKET
│   └── af_packet.c                      # 原始套接字
│
├── wireless/                            # 无线网络
│   ├── nl80211.c                        # 无线 netlink
│   └── cfg80211.c                       # 无线配置
│
├── xfrm/                                # IPsec XFRM
│   ├── xfrm_input.c                     # IPsec 输入
│   └── xfrm_output.c                    # IPsec 输出
│
└── mptcp/                               # Multipath TCP
    ├── mptcp.c                          # MPTCP 核心
    └── subflow.c                        # 子流管理

1.2 驱动与硬件抽象层

linux-5.10/drivers/net/ethernet/        # 网卡驱动
├── intel/
│   ├── igb/                            # Intel I350 1G 驱动
│   │   ├── igb_main.c                  # 驱动主逻辑
│   │   ├── igb_lib.c                   # 队列管理、中断处理
│   │   └── igb_ethtool.c               # ethtool 接口
│   └── ixgbe/                          # Intel 10G 驱动
│       ├── ixgbe_main.c
│       └── ixgbe_lib.c
├── broadcom/
│   └── bnxt/                           # Broadcom NetXtreme
└── mellanox/
    └── mlx5/                           # Mellanox ConnectX

1.3 关键头文件

linux-5.10/include/
├── linux/
│   ├── netdevice.h                     # 网络设备结构
│   ├── skbuff.h                        # SKB 结构
│   ├── sock.h                          # Socket 结构
│   ├── netdev_features.h               # 硬件卸载特性标志
│   └── netfilter.h                     # Netfilter
├── net/
│   ├── sock.h                          # Socket 内部
│   ├── tcp.h                           # TCP 内部
│   ├── tcp_states.h                    # TCP 状态定义
│   ├── ip.h                            # IP 内部
│   ├── flow.h                          # 流
│   ├── flow_dissector.h                # 流解析器
│   ├── pkt_sched.h                     # 调度器
│   └── net_namespace.h                 # 网络命名空间
└── uapi/linux/                         # 用户空间 API
    ├── if.h                            # 网络接口
    ├── in.h                            # IPv4
    ├── in6.h                           # IPv6
    └── tcp.h                           # TCP

二、数据结构分析

2.1 核心数据结构层次图

┌─────────────────────────────────────────────────────────────────────────────────────┐
│                           网络子系统核心数据结构                                     │
├─────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct sk_buff (include/linux/skbuff.h)                                      │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  SKB - 网络数据包核心结构                                               │ │ │
│  │  ├──────────────────────────────────────────────────────────────────────────┤ │ │
│  │  │  /* 链表指针 */                                                         │ │ │
│  │  │  struct sk_buff      *next;          // 下一个SKB                        │ │ │
│  │  │  struct sk_buff      *prev;          // 上一个SKB                        │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 数据指针 */                                                         │ │ │
│  │  │  unsigned char       *head;          // 缓冲区起始                       │ │ │
│  │  │  unsigned char       *data;          // 数据起始                         │ │ │
│  │  │  unsigned char       *tail;          // 数据结束                         │ │ │
│  │  │  unsigned char       *end;           // 缓冲区结束                       │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 长度信息 */                                                         │ │ │
│  │  │  unsigned int        len;            // 总数据长度                       │ │ │
│  │  │  unsigned int        data_len;       // 非线性数据长度                   │ │ │
│  │  │  unsigned int        truesize;       // 实际分配大小                     │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 协议信息 */                                                         │ │ │
│  │  │  __be16              protocol;       // 三层协议类型                     │ │ │
│  │  │  unsigned short      transport_header; // 传输头偏移                     │ │ │
│  │  │  unsigned short      network_header;   // 网络头偏移                     │ │ │
│  │  │  unsigned short      mac_header;       // MAC头偏移                      │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 控制信息 */                                                         │ │ │
│  │  │  struct dst_entry    *dst;           // 路由目标                        │ │ │
│  │  │  struct sock         *sk;            // 所属socket                       │ │ │
│  │  │  unsigned int        hash;           // 包哈希                          │ │ │
│  │  │  unsigned int        cb[48];         // 控制块                          │ │ │
│  │  │  __u32               priority;       // 优先级                          │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct sock (include/net/sock.h)                                             │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  Socket 核心结构                                                        │ │ │
│  │  ├──────────────────────────────────────────────────────────────────────────┤ │ │
│  │  │  /* 接收队列 */                                                         │ │ │
│  │  │  struct sk_buff_head    sk_receive_queue;  // 接收队列                   │ │ │
│  │  │  struct sk_buff_head    sk_backlog;        // 后备队列                   │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 发送队列 */                                                         │ │ │
│  │  │  struct sk_buff_head    sk_write_queue;    // 发送队列                   │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 缓冲区大小 */                                                       │ │ │
│  │  │  int                    sk_rcvbuf;         // 接收缓冲区大小             │ │ │
│  │  │  int                    sk_sndbuf;         // 发送缓冲区大小             │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 状态信息 */                                                         │ │ │
│  │  │  unsigned long          sk_state;          // socket状态                 │ │ │
│  │  │  unsigned long          sk_flags;          // 标志位                     │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 操作函数 */                                                         │ │ │
│  │  │  struct proto           *sk_prot;          // 协议操作                   │ │ │
│  │  │  const struct proto_ops *sk_proto_ops;     // socket操作                 │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 定时器 */                                                           │ │ │
│  │  │  struct timer_list      sk_timer;          // 定时器                     │ │ │
│  │  │                                                                          │ │ │
│  │  │  /* 引用计数 */                                                         │ │ │
│  │  │  atomic_t               sk_refcnt;         // 引用计数                   │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct tcp_sock (include/linux/tcp.h)                                        │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  TCP 扩展结构                                                           │ │ │
│  │  ├──────────────────────────────────────────────────────────────────────────┤ │ │
│  │  │  u32    rcv_nxt;            // 下一个期望接收的序列号                    │ │ │
│  │  │  u32    snd_nxt;            // 下一个要发送的序列号                      │ │ │
│  │  │  u32    snd_una;            // 最早未确认的序列号                        │ │ │
│  │  │  u32    snd_wnd;            // 发送窗口                                  │ │ │
│  │  │  u32    rcv_wnd;            // 接收窗口                                  │ │ │
│  │  │  u32    snd_cwnd;           // 拥塞窗口                                  │ │ │
│  │  │  u32    snd_ssthresh;       // 慢启动阈值                                │ │ │
│  │  │  u32    srtt_us;            // 平滑 RTT(微秒)                          │ │ │
│  │  │  u32    mss_cache;          // 缓存的 MSS                                │ │ │
│  │  │  u32    reordering;         // 重排序阈值                                │ │ │
│  │  │  u8     ecn_flags;          // ECN 标志                                  │ │ │
│  │  │  struct sk_buff_head out_of_order_queue; // 乱序队列                     │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct net_device (include/linux/netdevice.h)                                │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  网络设备结构                                                           │ │ │
│  │  ├──────────────────────────────────────────────────────────────────────────┤ │ │
│  │  │  char                   name[IFNAMSIZ];    // 设备名 (eth0)              │ │ │
│  │  │  unsigned long          state;             // 设备状态                   │ │ │
│  │  │  struct netdev_queue    *_tx;              // 发送队列                   │ │ │
│  │  │  unsigned int           num_tx_queues;     // TX队列数量                 │ │ │
│  │  │  unsigned int           real_num_tx_queues;// 实际TX队列数               │ │ │
│  │  │  unsigned int           mtu;               // 最大传输单元               │ │ │
│  │  │  const struct net_device_ops *netdev_ops;  // 设备操作                   │ │ │
│  │  │  netdev_features_t      features;          // 设备特性                   │ │ │
│  │  │  struct in_device       *ip_ptr;           // IPv4配置                   │ │ │
│  │  │  struct inet6_dev       *ip6_ptr;          // IPv6配置                   │ │ │
│  │  │  struct napi_struct     *napi_list;        // NAPI列表                   │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct softnet_data (net/core/dev.c) - Per-CPU 结构                          │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  软中断数据处理结构                                                     │ │ │
│  │  ├──────────────────────────────────────────────────────────────────────────┤ │ │
│  │  │  struct list_head poll_list;          // NAPI 轮询列表                   │ │ │
│  │  │  struct sk_buff_head process_queue;   // 待处理 SKB 队列                 │ │ │
│  │  │  unsigned int processed;              // 已处理包计数                   │ │ │
│  │  │  unsigned int time_squeeze;           // 预算耗尽次数(丢包标志)       │ │ │
│  │  │  struct sk_buff_head input_pkt_queue; // RPS 队列                        │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────────────┐ │
│  │  struct tcpnv (net/ipv4/tcp_nv.c) - TCP-NV 拥塞控制参数           │ │
│  │  ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│  │  │  u32 nv_min_rtt;               // 当前最小 RTT                          │ │ │
│  │  │  u32 nv_base_rtt;              // 拥塞阈值 RTT                          │ │ │
│  │  │  u32 nv_lower_bound_rtt;       // RTT 下界(base_rtt 的 80%)           │ │ │
│  │  │  u8 nv_allow_cwnd_growth:1;    // 是否允许窗口增长                      │ │ │
│  │  │  u8 nv_catchup:1;              // 追赶模式标志                          │ │ │
│  │  │  u8 nv_eval_call_cnt;          // 评估周期计数                          │ │ │
│  │  └──────────────────────────────────────────────────────────────────────────┘ │ │
│  └────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                      │
└─────────────────────────────────────────────────────────────────────────────────────┘

2.2 TCP 状态机定义

// include/net/tcp_states.h
enum {
    TCP_ESTABLISHED = 1,   // 已建立连接
    TCP_SYN_SENT,          // 已发送 SYN
    TCP_SYN_RECV,          // 已收到 SYN
    TCP_FIN_WAIT1,         // 等待 FIN
    TCP_FIN_WAIT2,         // 等待 FIN
    TCP_TIME_WAIT,         // 等待 2MSL
    TCP_CLOSE,             // 关闭
    TCP_CLOSE_WAIT,        // 等待关闭
    TCP_LAST_ACK,          // 等待最后 ACK
    TCP_LISTEN,            // 监听
    TCP_CLOSING,           // 同时关闭
    TCP_NEW_SYN_RECV,      // 新 SYN 接收
};

三、初始化与设备注册流程

3.1 内核引导时的网络初始化

start_kernel()
    │
    └── net_dev_init()                    [net/core/dev.c]
            │
            ├── for_each_possible_cpu(cpu) {
            │       struct softnet_data *sd = &per_cpu(softnet_data, cpu);
            │       skb_queue_head_init(&sd->input_pkt_queue);
            │       skb_queue_head_init(&sd->process_queue);
            │       INIT_LIST_HEAD(&sd->poll_list);
            │   }
            │
            ├── open_softirq(NET_TX_SOFTIRQ, net_tx_action);
            ├── open_softirq(NET_RX_SOFTIRQ, net_rx_action);
            │
            └── register_pernet_subsys(&netdev_net_ops);  // 网络命名空间

3.2 网卡设备驱动初始化(PCI 探测)

驱动模块加载
    │
    └── module_init(igb_init_module)
            │
            └── pci_register_driver(&igb_driver)
                    │
                    └── igb_probe()                  [drivers/net/ethernet/intel/igb/igb_main.c]
                            │
                            ├── pci_enable_device()
                            ├── pci_request_regions()
                            ├── dma_set_mask()
                            │
                            ├── netdev = alloc_etherdev_mq(sizeof(struct igb_adapter),
                            │                                    num_tx_queues, num_rx_queues)
                            │
                            ├── netdev->netdev_ops = &igb_netdev_ops;
                            │   // ndo_open → igb_open
                            │   // ndo_start_xmit → igb_xmit_frame
                            │   // ndo_set_features → igb_set_features
                            │
                            └── register_netdev(netdev)       // 注册到网络核心

3.3 网卡启动与 NAPI 初始化

igb_open()                               [驱动层]
    │
    ├── igb_alloc_queues()               // 分配 RX/TX 队列
    │
    ├── igb_configure()                  // 配置网卡寄存器
    │
    ├── igb_setup_all_rx_resources()     // 设置 RX ring buffer
    │
    ├── igb_request_irq()                // 注册中断处理函数
    │       │
    │       └── request_irq(irq, igb_msix_ring, ...)
    │
    └── napi_enable(&adapter->napi)      // 启用 NAPI

3.4 通知链机制

当网卡状态变化时(up/down、地址变化),通过通知链通知其他模块:

// 注册监听
int register_netdevice_notifier(struct notifier_block *nb);
​
// 事件类型
#define NETDEV_UP       0x0001   // 设备启用
#define NETDEV_DOWN     0x0002   // 设备停用
#define NETDEV_CHANGE   0x0004   // 设备状态变化
#define NETDEV_REGISTER 0x0008   // 设备注册
#define NETDEV_UNREGISTER 0x0010 // 设备注销

四、NAPI 与 GRO 完整生命周期

4.1 NAPI 收包完整流程

网卡 DMA 写入 RX Ring Buffer
    │
    ▼
硬中断 IRQ Handler (igb_msix_ring)      [驱动层]
    │
    ├── 读取中断状态寄存器
    ├── 禁用当前 RX 队列的中断
    └── napi_schedule()                  // 将 napi 加入 poll_list
            │
            └── __raise_softirq_irqoff(NET_RX_SOFTIRQ)   // 触发软中断
                    │
                    ▼
软中断处理 net_rx_action()              [net/core/dev.c]
    │
    ├── budget = netdev_budget;          // 默认 300
    ├── time_limit = netdev_budget_usecs; // 默认 2000us
    │
    └── while (budget > 0 && !time_after(jiffies, time_limit)) {
            for_each_napi_in_list() {
                work = napi_poll(napi, budget);
                budget -= work;
                if (work < napi->weight) {
                    napi_complete_done(napi, work);  // 完成轮询,重新启用中断
                }
            }
        }

4.2 GRO 合并与批量提交

驱动 poll() 函数收包
    │
    ├── napi_gro_receive(skb)           // GRO 入口
    │       │
    │       ├── 计算包的 hash 值(五元组)
    │       ├── 在 gro_list 中查找相同流的数据包
    │       ├── 如果可以合并 → gro_receive() 合并
    │       └── 如果无法合并或超时 → netif_receive_skb()
    │
    └── napi_complete_done(napi, work)
            │
            └── gro_normal_list(napi)   // 批量提交合并后的包

4.3 关键调优参数

# 控制 NAPI 单次处理的包预算
sysctl net.core.netdev_budget=300
# 控制 NAPI 单次处理的时间上限(微秒)
sysctl net.core.netdev_budget_usecs=2000
# 控制 GRO 批量提交的大小
sysctl net.core.gro_normal_batch=8

五、硬件卸载与多队列优化

5.1 多队列与 RSS(Receive Side Scaling)

RSS 通过硬件哈希将流量分散到多个 RX 队列,每个队列绑定不同 CPU,实现并行处理。

# 查看当前队列配置
ethtool -l eth0
​
# 修改队列数量
ethtool -L eth0 combined 8
​
# 查看 RSS 哈希分配表
ethtool -x eth0
​
# 设置权重(队列0权重6,队列1权重2)
ethtool -X eth0 weight 6 2
​
# 修改 RSS 哈希字段(加入端口信息)
ethtool -N eth0 rx-flow-hash udp4 sdfn

5.2 硬件卸载类型与配置

卸载特性 标志 启用命令 作用
TSO tx-tcp-segmentation ethtool -K eth0 tso on 硬件处理 TCP 分片
GRO rx-gro ethtool -K eth0 gro on 硬件合并小包
RX Checksum rx-checksumming ethtool -K eth0 rx on 硬件校验和
aRFS ntuple ethtool -K eth0 ntuple on 硬件流定向
# 开启硬件流定向(aRFS)
ethtool -K eth0 ntuple on
# 添加规则:目标端口 80 的 TCP 包送到 RX 队列 2
ethtool -U eth0 flow-type tcp4 dst-port 80 action 2

5.3 RPS/RFS(软件多队列)

当硬件不支持多队列时,可用 RPS(Receive Packet Steering)在软件层实现负载均衡:

# 启用 RPS:将 CPU 掩码设为 0x0f(CPU 0-3)
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus
​
# 启用 RFS:设置流表大小
sysctl net.core.rps_sock_flow_entries=32768
echo 4096 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt

六、数据包接收完整路径

═══════════════════════════════════════════════════════════════════════════════════════
                              数据包接收完整流程
═══════════════════════════════════════════════════════════════════════════════════════
​
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 硬件层                                                                              │
│ 1. 网卡接收电信号,进行 CRC 校验                                                     │
│ 2. DMA 将数据写入 RX Ring Buffer(Descriptor 指向的内存)                           │
│ 3. 更新 RX 描述符状态,触发 MSI-X 中断                                              │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 驱动层 - 硬中断处理                                                                 │
│ igb_msix_ring()                                                                     │
│   1. 读取中断状态寄存器,确认是 RX 完成中断                                         │
│   2. 禁用该 RX 队列的中断(避免嵌套中断)                                           │
│   3. napi_schedule(&adapter->napi[queue_id])                                       │
│   4. 触发 NET_RX_SOFTIRQ 软中断                                                    │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 核心层 - 软中断处理(NAPI)                                                         │
│ net_rx_action() [net/core/dev.c]                                                   │
│   budget = netdev_budget (默认 300)                                                │
│   for each napi in poll_list:                                                     │
│       work = napi->poll(napi, budget)                                             │
│       budget -= work                                                               │
│       if (work < napi->weight) {                                                  │
│           napi_complete_done(napi, work)  // 重新启用中断                          │
│       }                                                                             │
│                                                                                    │
│ 驱动 poll() 函数 (igb_poll):                                                        │
│   1. 从 RX Ring Buffer 取出 skb                                                   │
│   2. 设置 skb->protocol = eth_type_trans(skb, netdev)                             │
│   3. napi_gro_receive(skb)  // GRO 合并                                           │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ GRO 层                                                                             │
│ napi_gro_receive() → netif_receive_skb() 或 gro_normal_list()                     │
│   1. 计算数据包哈希值(五元组)                                                    │
│   2. 在 gro_list 中查找相同流的数据包                                              │
│   3. 如果可合并 → gro_receive() 将小包合并到大包                                    │
│   4. 如果不可合并或超时 → netif_receive_skb()                                      │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 协议栈入口(L2 处理)                                                              │
│ __netif_receive_skb_core() [net/core/dev.c]                                       │
│   1. 处理 VLAN 标签 (vlan_do_receive)                                             │
│   2. 处理网桥 (br_handle_frame)                                                   │
│   3. ptype_all 协议嗅探器(tcpdump 抓包点在这里!)                               │
│   4. 根据 protocol 查找 ptype_base 中的处理函数                                   │
│   5. 调用 ip_rcv() 或 arp_rcv()                                                   │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Netfilter 钩子点                                                                   │
│ ip_rcv() 中执行 NF_INET_PRE_ROUTING 钩子                                           │
│ ip_local_deliver() 中执行 NF_INET_LOCAL_IN 钩子                                    │
│ ip_forward() 中执行 NF_INET_FORWARD 钩子                                           │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ IPv4 层                                                                           │
│ ip_rcv() [net/ipv4/ip_input.c]                                                    │
│   1. 检查 IP 头版本和长度                                                          │
│   2. 计算 IP 头校验和                                                              │
│   3. ip_rcv_finish()                                                              │
│        ├── ip_route_input_noref()  // 查找路由                                    │
│        └── 根据目的地址决定:                                                      │
│            - 本地接收 → ip_local_deliver()                                        │
│            - 转发 → ip_forward()                                                  │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 传输层(TCP)                                                                      │
│ tcp_v4_rcv() [net/ipv4/tcp_ipv4.c]                                                │
│   1. __inet_lookup_skb() 查找 socket                                             │
│   2. 根据 socket 状态分发:                                                        │
│        - TCP_ESTABLISHED → tcp_rcv_established()                                  │
│        - TCP_LISTEN → tcp_v4_do_rcv() (三次握手)                                  │
│        - 其他 → tcp_rcv_state_process()                                           │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ Socket 层                                                                         │
│ tcp_rcv_established() [net/ipv4/tcp_input.c]                                     │
│   1. tcp_ack() 更新发送窗口和 RTT                                                 │
│   2. 处理乱序包:放入 out_of_order_queue                                          │
│   3. 将数据加入 sk_receive_queue                                                  │
│   4. sk->sk_data_ready(sk) 唤醒等待进程                                           │
└─────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 用户空间                                                                          │
│ recv() / read() 系统调用返回数据                                                   │
└─────────────────────────────────────────────────────────────────────────────────────┘

七、TCP 三次握手与四次挥手

7.1 三次握手完整流程

客户端 (主动连接)                          服务端 (被动连接)
─────────────────                        ─────────────────
CLOSED                                    CLOSED
    │                                         │
    │ socket()                                │ socket()
    │ bind()(可选)                          │ bind()
    │                                         │ listen()
    │                                         │ LISTEN
    │                                         │
    │ connect()                               │
    │ SYN_SENT                                │
    │     │                                   │
    │     └───────── SYN (seq=x) ────────────►│
    │                                         │ SYN_RCVD
    │                                         │     │
    │     ◄──────── SYN+ACK (seq=y, ack=x+1) ─┘     │
    │                                         │     │
    │ ESTABLISHED                             │     │
    │     │                                   │     │
    │     └───────── ACK (ack=y+1) ──────────►│     │
    │                                         │ ESTABLISHED
    │                                         │
    │     ◄───────── 数据传输 ────────────────►     │

7.2 三次握手的意义

握手次数 方向 SYN ACK 验证的能力
第一次 C→S 1 0 客户端发送能力、服务端接收能力
第二次 S→C 1 1 服务端发送能力、客户端接收能力
第三次 C→S 0 1 确认双方接收正常

为什么需要三次握手?

  1. 防止历史连接请求:网络中延迟的旧 SYN 包可能被服务端误认为是新连接请求

  2. 同步初始序列号:需要三次交互才能让双方都确认对方的序列号

  3. 避免资源浪费:二次握手会导致服务端在不确定客户端是否收到 SYN+ACK 时就分配资源

7.3 四次挥手完整流程

主动关闭方                              被动关闭方
────────────────                        ────────────────
ESTABLISHED                              ESTABLISHED
    │                                         │
    │ close()                                 │
    │ FIN_WAIT_1                              │
    │     │                                   │
    │     └───────── FIN (seq=u) ────────────►│
    │                                         │ CLOSE_WAIT
    │     ◄───────── ACK (ack=u+1) ──────────┘     │
    │ FIN_WAIT_2                              │     │
    │                                         │     │ (可能继续发送数据)
    │                                         │     │
    │                                         │ close()
    │                                         │ LAST_ACK
    │     ◄───────── FIN (seq=w) ─────────────┘     │
    │ TIME_WAIT                               │     │
    │ (等待 2MSL)                             │     │
    │     │                                   │     │
    │     └───────── ACK (ack=w+1) ──────────►│     │
    │                                         │ CLOSED
    │ CLOSED                                  │

7.4 四次挥手的意义

挥手次数 方向 FIN ACK 状态转换
第一次 A→B 1 0 ESTABLISHED → FIN_WAIT_1
第二次 B→A 0 1 ESTABLISHED → CLOSE_WAIT
第三次 B→A 1 1 CLOSE_WAIT → LAST_ACK
第四次 A→B 0 1 TIME_WAIT → CLOSED

为什么需要四次挥手?

  1. TCP 全双工特性:需要分别关闭两个方向的数据流

  2. ACK 和 FIN 触发时机不同:ACK 由内核立即回复,FIN 由应用程序调用 close() 触发

  3. 被动方可能还有数据要发送:收到 FIN 后只是表示主动方不再发送数据

7.5 关键状态详解

状态 含义 常见问题
LISTEN 服务端等待连接 正常
SYN_RECV 收到 SYN,等待 ACK 半连接队列满(SYN Flood)
ESTABLISHED 连接已建立 正常
FIN_WAIT_2 主动方等待被动方 FIN 可调 tcp_fin_timeout
TIME_WAIT 等待 2MSL(60秒) 过多需启用 tcp_tw_reuse
CLOSE_WAIT 被动方等待 close() ⚠️ 应用未调用 close()
LAST_ACK 等待最后 ACK 正常

7.6 四次挥手异常场景分析

乱序导致超时重传

同时关闭的场景,server 和 client 几乎同时发送 fin 包。
​
问题现象:
1. client 先收到 server 的 fin 包,并回传 ack 包
2. server 处发生乱序,先收到 client 的 ack 包,后收到 fin 包
3. server 未能正确处理 client 的 fin 包,未能返回正确的 ack 包
4. client 没收到 ack,等待超时后重传 fin 包,之后才正常关闭
​
根本原因:内核在 FIN_WAIT_1 状态收到乱序包时,对 fin 包的处理有特定逻辑,
          导致 fin 包未被正确接收,需要超时重传。

7.7 SYN Cookie 防攻击机制

当半连接队列满时,内核启用 SYN Cookie 机制:

// net/ipv4/syncookies.c
// 收到 SYN 时,不立即分配资源
// 根据源/目的 IP、端口、时间等计算 cookie 值作为 seq
// 第三次握手时验证 cookie 有效性,确认后才分配资源

八、TCP 拥塞控制算法体系

8.1 拥塞控制算法架构

Linux 5.10 实现了可插拔的拥塞控制框架:

net/ipv4/tcp_cong.c              # 拥塞控制框架核心
net/ipv4/tcp_cubic.c             # CUBIC(默认算法)
net/ipv4/tcp_bbr.c               # BBR(Google)
net/ipv4/tcp_nv.c                # NV(数据中心优化)
net/ipv4/tcp_vegas.c             # Vegas(延迟感知)
net/ipv4/tcp_dctcp.c             # DCTCP(数据中心 ECN)
net/ipv4/tcp_westwood.c          # Westwood(无线优化)
net/ipv4/tcp_hybla.c             # Hybla(卫星链路)

8.2 拥塞控制算法对比

算法 拥塞检测方式 适用场景 特点
CUBIC 丢包 通用(默认) 三次函数窗口增长,高带宽友好
BBR 延迟/带宽 高延迟高带宽 基于带宽估计,不依赖丢包
Reno 丢包 传统网络 AIMD,基础算法
Vegas RTT变化 低延迟要求 主动避免拥塞,提前降速
NV 队列积压 数据中心 Vegas后继,预测 cwnd
DCTCP ECN标记 数据中心 配合 ECN,低延迟
Westwood 带宽估计 无线网络 利用 ACK 速率估计带宽
Hybla 丢包 卫星/长胖网络 补偿高延迟环境

8.3 TCP-NV 算法详解

TCP-NV 是专门为数据中心设计的拥塞控制算法:

// net/ipv4/tcp_nv.c
static int nv_pad __read_mostly = 10;           // 允许的最大网络排队包数
static int nv_cong_dec_mult __read_mostly = 30 * 128 / 100; // 拥塞降窗 30%
static int nv_loss_dec_factor __read_mostly = 819; // 丢包时窗口乘数(≈80%)
static int nv_rtt_factor __read_mostly = 128;   // RTT 平均因子(1/2+1/2)

NV 核心机制

  • 检测队列积压而非丢包(类似 Vegas)

  • 当 RTT 超过 base_rtt 时判定为拥塞

  • 按比例减少 cwnd

  • 适用于全 NV 流的数据中心环境

九、CAKE 队列管理(Common Applications Kept Enhanced)

CAKE 是一个先进的队列管理算法,结合了流量整形、AQM 和公平队列:

// net/sched/sch_cake.c
#define CAKE_SET_WAYS (8)
#define CAKE_MAX_TINS (8)
#define CAKE_QUEUES (1024)
​
struct cobalt_params {
    u64 interval;      // codel 初始丢包率
    u64 target;        // 最大持续停留时间
    u64 mtu_time;      // 最大包串行化延迟
    u32 p_inc;         // blue 丢包概率增量
    u32 p_dec;         // blue 丢包概率减量
};

CAKE 核心特性

  1. 带宽整形器:赤字模式,无需突发参数

  2. Diffserv 感知优先级队列:按优先级分类

  3. Flow Queue 隔离:防止单流增加延迟

  4. Cobalt AQM:Codel + Blue 组合算法

十、数据包发送路径

用户空间 send()/write()
    │
    ▼
sock_sendmsg() [net/socket.c]
    │
    ▼
inet_sendmsg() [net/ipv4/af_inet.c]
    │
    ▼
tcp_sendmsg() [net/ipv4/tcp.c]
    │
    ├── alloc_skb() [net/core/skbuff.c]     // 分配 SKB
    ├── skb_copy_from_user()                // 复制用户数据
    └── tcp_push() [net/ipv4/tcp.c]
            │
            ▼
tcp_write_xmit() [net/ipv4/tcp_output.c]
    │
    ├── 拥塞控制检查(cwind > snd_cwnd)
    ├── tcp_transmit_skb()                  // 构建 TCP 头
    │
    ▼
ip_queue_xmit() [net/ipv4/ip_output.c]
    │
    ├── ip_route_output_flow()              // 查找路由
    ├── ip_finish_output()
    │
    ▼
neigh_output() [net/core/neighbour.c]
    │
    ├── 查找邻居缓存
    ├── 如果 MAC 未知 → 触发 ARP 请求
    │
    ▼
dev_queue_xmit() [net/core/dev.c]
    │
    ├── 选择发送队列 (netdev_pick_tx)
    ├── 应用 QoS 规则 (QDisc)
    │
    ▼
__dev_xmit_skb() [net/sched/sch_generic.c]
    │
    ├── qdisc_enqueue_root()                // 入队
    └── __qdisc_run()                       // 出队
            │
            └── qdisc_restart()
                    │
                    ▼
dev_hard_start_xmit() [net/core/dev.c]
    │
    ▼
ndo_start_xmit() [驱动层]
    │
    ├── 将 skb 映射到 DMA 地址
    ├── 将发送描述符加入 TX Ring Buffer
    └── 通知网卡发送

十一、关键调优参数汇总

11.1 驱动/网卡层

参数 查看/修改命令 默认值 作用
RX 队列数量 ethtool -l eth0 硬件决定 多队列并行收包
RX 队列大小 ethtool -g eth0 512 Ring buffer 大小
中断合并 ethtool -c eth0 动态 降低中断频率
硬件卸载 ethtool -k eth0 开启 TSO/GRO/RX 校验和

11.2 软中断/NAPI 层

参数 路径 默认值 作用
netdev_budget /proc/sys/net/core/netdev_budget 300 单次软中断处理包上限
netdev_budget_usecs /proc/sys/net/core/netdev_budget_usecs 2000 单次软中断时间上限(us)
gro_normal_batch /proc/sys/net/core/gro_normal_batch 8 GRO 批量提交大小

11.3 TCP 协议栈层

参数 路径 默认值 作用
tcp_rmem /proc/sys/net/ipv4/tcp_rmem 4096 87380 6291456 TCP 接收缓冲区
tcp_wmem /proc/sys/net/ipv4/tcp_wmem 4096 16384 4194304 TCP 发送缓冲区
tcp_congestion_control /proc/sys/net/ipv4/tcp_congestion_control cubic 拥塞控制算法
tcp_max_syn_backlog /proc/sys/net/ipv4/tcp_max_syn_backlog 1024 半连接队列大小
somaxconn /proc/sys/net/core/somaxconn 128 全连接队列大小
tcp_fin_timeout /proc/sys/net/ipv4/tcp_fin_timeout 60 FIN_WAIT_2 超时(秒)
tcp_syn_retries /proc/sys/net/ipv4/tcp_syn_retries 6 SYN 重试次数

11.4 RPS/RFS 层

参数 路径 默认值 作用
rps_cpus /sys/class/net/eth0/queues/rx-0/rps_cpus 0 RPS CPU 掩码
rps_flow_cnt /sys/class/net/eth0/queues/rx-0/rps_flow_cnt 0 RFS 流表大小
rps_sock_flow_entries /proc/sys/net/core/rps_sock_flow_entries 0 全局 RFS 流表

十二、监控与调试工具链

12.1 关键监控指标

监控层级 指标 数据源 异常阈值
硬件层 CRC 错误、FCS 错误 ethtool -S eth0 > 0 表示链路质量问题
驱动层 RX dropped、ring full /sys/class/net/eth0/statistics/rx_dropped 持续增长需增大 ring buffer
软中断层 time_squeeze /proc/net/softnet_stat 第2列 持续增长需调整 budget
协议栈 ListenOverflows/ListenDrops netstat -s 增长需增大 backlog
TCP层 重传段、丢包重传 netstat -s 增长需检查链路或调优

12.2 /proc/net/softnet_stat 详解

$ cat /proc/net/softnet_stat
0002b45a 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
0002c4e3 00000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000
含义 解读
1 处理的总包数 正常增长
2 time_squeeze net_rx_action 预算耗尽次数 ⚠️ 高表示 CPU 过载
3 CPU collision CPU 冲突次数
4 接收包数 实际接收包数

12.3 监控命令速查

# 硬件/驱动层
ethtool -S eth0 | grep -E "drop|error"
cat /sys/class/net/eth0/statistics/rx_dropped
​
# 软中断层
cat /proc/net/softnet_stat | awk '{print $2}'  # time_squeeze
cat /proc/softirqs | grep NET_RX
​
# 协议栈
netstat -s | grep -E "overflow|dropped|rejected|pruned"
netstat -s | grep -E "retrans|loss"
​
# Socket 层
ss -tunlp
ss -ti | grep -E "cwnd|rtt"
​
# 中断分布
cat /proc/interrupts | grep -E "eth|igb|ixgbe"

12.4 性能调优决策树

观测到丢包
    │
    ├─► `ethtool -S eth0` 有 CRC/FIFO 错误
    │       └─► 硬件问题:检查网卡、线缆、交换机
    │
    ├─► `/sys/class/net/eth0/statistics/rx_dropped` 增长
    │       └─► 驱动层丢包:增大 ring buffer (ethtool -G)
    │
    ├─► `/proc/net/softnet_stat` time_squeeze 增长
    │       └─► 软中断过载:增大 netdev_budget,或开启 RPS/RFS
    │
    ├─► `netstat -s` ListenDrops 增长
    │       └─► 应用层过载:增大 net.core.somaxconn
    │
    └─► `netstat -s` TCP 重传增长
            └─► 网络拥塞:检查带宽,考虑更换拥塞控制算法

12.5 动态追踪(ftrace/kprobe)

# 追踪特定函数调用
echo tcp_rcv_established > /sys/kernel/debug/tracing/set_ftrace_filter
echo function > /sys/kernel/debug/tracing/current_tracer
cat /sys/kernel/debug/tracing/trace
​
# 使用 kprobe 追踪函数参数
echo 'p:my_tcp_ack tcp_ack ack=%r2' > /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/my_tcp_ack/enable
​
# perf 追踪网络 tracepoint
perf record -e net:netif_receive_skb -a -g -- sleep 10
perf report
​
# 追踪所有网络事件
echo 1 > /sys/kernel/debug/tracing/events/enable
cat /sys/kernel/debug/tracing/trace

十三、总结

分析维度 核心内容
源码目录 net/ 下有 core/, ipv4/, ipv6/, netfilter/, sched/
核心数据结构 sk_buff, sock, tcp_sock, net_device, softnet_data
初始化流程 net_dev_init() Per-CPU 初始化、PCI 驱动探测、通知链
NAPI 生命周期 硬中断 → 软中断 → poll 轮询 → budget 控制
GRO 批量处理 gro_normal_batch 控制批量提交
硬件卸载 TSO/GRO/RSS/RFS/aRFS,多队列并行处理
TCP 三次握手 SYN → SYN+ACK → ACK,状态转换,SYN Cookie 防攻击
TCP 四次挥手 FIN → ACK → FIN → ACK,TIME_WAIT 意义,异常场景
拥塞控制算法 CUBIC/BBR/NV/Vegas/DCTCP,可插拔框架
CAKE 队列 带宽整形 + Diffserv + Flow Queue + Cobalt AQM
关键调优参数 netdev_budget, tcp_rmem, tcp_congestion_control
监控指标 softnet_stat, ethtool -S, netstat -s
调试工具 ftrace、kprobe、perf、tcpdump
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐