数据包处理流程(接收路径)

假设一个 IP 包到达网卡:

  1. 网卡驱动接收包
    • DMA buffer → skb
    • 调用 napi_schedule() 安排软中断处理(发送也是发接收软中断)
  2. 软中断上下文执行
    • NET_RX_SOFTIRQnet_rx_action()
    • 遍历 per-CPU softnet_data->poll_list
    • 调用 napi_poll() → 驱动的 poll 函数处理包
    • skb 被交给协议栈 (__netif_receive_skb_core())
  3. 分发到协议处理器
    • 先通过 ptype_base 找到 IP 层处理函数 ip_rcv()
    • ip_rcv() 根据 IP 协议号(TCP/UDP/ICMP)去 inet_protos 找对应处理函数
      • TCP → tcp_v4_rcv()
      • UDP → udp_rcv()
  4. 广播给抓包工具
    • 遍历 ptype_all 链表
    • 调用 deliver_skb() 给每个注册的 packet_type
    • tcpdump 注册的 AF_PACKET socket 就在这里获取 skb 可以简化成和你前面一样的风格:
  5. 递交到socket
    • ip_rcv_finish()ip_local_deliver_finish()
    • 根据协议调用 tcp_v4_rcv() / udp_rcv()
    • 找到对应 socket,将 skb 放入 socket 接收队列
  6. 用户态读取
    • 用户调用 recvfrom()(glibc)
    • 触发系统调用 sys_recvfrom()sock_recvmsg()
    • socket 接收队列 取出数据返回给用户程序

次数 位置 类型
第一次 用户态 → 内核 深拷贝
第二次 TCP → IP 浅拷贝(skb_clone)
第三次 IP 分片 深拷贝(fragmentation)

参考