Linux网络协议栈采用三级架构:Socket层→协议处理层→驱动层,以skb为载体、函数指针和回调机制实现零拷贝高效流转,数据收发均经NAPI、路由、邻居子系统及net_device抽象,Netfilter钩子支撑扩展。

Linux内核网络协议栈的核心分层结构
Linux网络协议栈并非严格遵循OSI七层模型,而是以BSD socket为接口、以协议无关接口(AF_INET/AF_PACKET等)为枢纽,构建起“用户空间 ↔ 内核协议栈 ↔ 驱动层”的三级架构。核心层级自上而下包括:Socket层(提供统一API)、协议处理层(TCP/UDP/ICMP/IP等)、IP层(路由、转发、分片重组)、邻居子系统(ARP/NDP)、网络设备子系统(net_device抽象)以及驱动收发队列(ring buffer + NAPI poll)。各层通过函数指针、回调机制和skb(struct sk_buff)传递数据,而非内存拷贝——这是性能关键。
数据包从网卡到应用的完整流转路径(接收方向)
以IPv4 TCP包进入本机为例,典型路径如下:
- 硬件中断触发:网卡DMA写入报文至RX ring buffer,发出IRQ;内核执行中断处理程序(如igb_irq),快速禁用该RX队列中断,唤醒NAPI softirq
-
NAPI轮询收包:软中断上下文调用驱动poll方法(如igb_poll),批量从ring中取出skb,经
netif_receive_skb()送入协议栈入口 -
协议栈逐层递交:skb经
__netif_receive_skb_core()→ip_rcv()(校验、去首部、路由查表)→ip_local_deliver()→tcp_v4_rcv()或udp_v4_rcv() -
交付至socket接收队列:协议处理完成后,调用
sk->sk_data_ready(sk)唤醒阻塞进程;数据最终拷贝至用户空间recv缓冲区(通过copy_to_user())
数据包从应用到网卡的完整流转路径(发送方向)
以TCP send()调用出发,路径强调“零拷贝”与“延迟发送”设计:
-
用户态准备:应用调用send() → 经glibc封装 → 进入内核
sys_sendto()→ 定位对应socket(struct sock) -
TCP协议封装:进入
tcp_sendmsg(),将用户数据切分为MSS段,分配skb并填充TCP/IP首部;若开启TSO/GSO,仅在最后驱动层才分段 -
路由与邻居解析:调用
ip_route_output_ports()获取dst_entry;若下一跳MAC未知,触发arp_bind_neighbour()异步ARP请求,skb暂挂于output队列 -
驱动发送:经
dev_queue_xmit()→ 流量控制(qdisc)→__dev_xmit_skb()→ 驱动xmit方法(如igb_xmit_frame)→ DMA映射 → 启动网卡发送
关键数据结构与钩子点:理解可扩展性的基础
协议栈灵活性依赖三大机制:
-
skb(struct sk_buff):贯穿全程的数据载体,含head/tail/data/len等指针,支持线性/非线性布局;通过
skb_pull/skb_push/skb_reserve动态调整首尾偏移,避免频繁拷贝 - net_device_ops:驱动注册的操作集(如.ndo_start_xmit、.ndo_open),是协议栈与硬件的唯一契约接口
- Netfilter钩子:在5个关键点(NF_INET_PRE_ROUTING、LOCAL_IN、FORWARD、LOCAL_OUT、POST_ROUTING)插入回调,iptables/nftables、conntrack、ebpf tc均基于此实现










