网络传输过程
数据包处理流程(接收路径)
假设一个 IP 包到达网卡:
- 网卡驱动接收包
- DMA buffer → skb
- 调用
napi_schedule()安排软中断处理(发送也是发接收软中断)
- 软中断上下文执行
NET_RX_SOFTIRQ→net_rx_action()- 遍历 per-CPU
softnet_data->poll_list - 调用
napi_poll()→ 驱动的 poll 函数处理包 - skb 被交给协议栈 (
__netif_receive_skb_core())
- 分发到协议处理器
- 先通过
ptype_base找到 IP 层处理函数ip_rcv() ip_rcv()根据 IP 协议号(TCP/UDP/ICMP)去inet_protos找对应处理函数- TCP →
tcp_v4_rcv() - UDP →
udp_rcv()
- TCP →
- 先通过
- 广播给抓包工具
- 遍历
ptype_all链表 - 调用
deliver_skb()给每个注册的 packet_type - tcpdump 注册的 AF_PACKET socket 就在这里获取 skb 可以简化成和你前面一样的风格:
- 遍历
- 递交到socket
ip_rcv_finish()→ip_local_deliver_finish()- 根据协议调用
tcp_v4_rcv()/udp_rcv() - 找到对应 socket,将 skb 放入 socket 接收队列
- 用户态读取
- 用户调用
recvfrom()(glibc) - 触发系统调用
sys_recvfrom()→sock_recvmsg() - 从 socket 接收队列 取出数据返回给用户程序
- 用户调用
| 次数 | 位置 | 类型 |
|---|---|---|
| 第一次 | 用户态 → 内核 | 深拷贝 |
| 第二次 | TCP → IP | 浅拷贝(skb_clone) |
| 第三次 | IP 分片 | 深拷贝(fragmentation) |