近期开始好好学习下Linux网络,那就先从物理网络路径和Linux协议栈开始,一步步来学习。
通信数据在物理线路上传输,网卡收到电信号或光信号后,将其还原成数字信号,并剥离掉前导码和帧起始限定符,此时网卡拿到了一个以太网帧。
1、标准网卡NIC做二层处理
标准网卡NIC用ASIC/FPGA硬件芯片,会做两件事:
1)校验 CRC/FCS:检查数据在传输中是否损坏,用 `ip -s link show eth0`命令或 `ethtool -S eth0`检查
2)检查目的MAC地址:
如果目的 MAC 是自己、或者是广播全F、或属于加入的多播组,网卡就会收下这个包,发现为arp协议等二层会送往内核的ARP子系统处理,其他则发送到linux内核中三层IP处理流程;
如果目的 MAC 不是本机且开启二层桥接或ovs等,会检查自己的MAC地址表FDB,用 `bridge fdb show`命令查看,内核会原封不动或修改vlan tag后从另外一个网卡中转发出去;
如果都不是,会drop丢弃这个包,也是用 `ip -s link show eth0` 命令或 `ethtool -S eth0` 检查。
一旦确认 MAC 地址无误,传统网卡就会通过 DMA(直接内存访问)把这个二层帧拷贝到主内存的系统缓冲区中,并向 CPU 触发一个硬中断。
2、现代高性能网卡做三四层处理
现代高性能网卡SmartNIC/DPU用MAC/PHY 层芯片,把数据拆开到三层、四层进行处理,主要处理包括:
1)前置校验和卸载:网卡芯片的硬件电路在收到包的同时,顺手就把 IP 头部的 Checksum 和 TCP/UDP 的 Checksum 算好了;
发现错误,直接丢弃不给linux内核处理;
发现正确,则在包的描述符里打个标记,让CPU看到后跳过校验和计算。
2)GRO/LRO大包接收卸载:网卡收到一堆连续的、属于同一个 TCP 连接的切片包,网卡主动拆开三层和四层,把这些包的 TCP Payload(有效载荷)拼接在一起,重新封装成一个“超级大包”,再发送至CPU内核。
3、更加高阶的终极演进:绕过内核栈
在当今的数据中心基础设施中,为了追求极致的低延迟和高吞吐,业界甚至更进一步——彻底不进 Linux 协议栈。这里有两个方案,DPDK是绕过 Linux 协议栈、XDP是部分绕 Linux 协议栈。
1)DPDK核心是内核旁路(Kernel Bypass)和 用户态轮询。
数据包到达网卡后,通过 DMA 直接写到用户态内存(User Space)中。
整个过程中,Linux 内核的IP栈、iptables、网卡中断机制全部被绕过。
用户态的应用程序(如高性能网关、VPP、或者智能网卡上的数据面程序)通过 CPU 核心死循环去轮询Poll网卡,发现有包就直接在用户态解包处理。
2)XDP(eBPF Express Data Path)在内核协议栈的大门口设了个“安检关卡”。当网卡收到包,XDP 脚本(eBPF 程序)在最前端截获包后,可以给这个包指定三种不同的命运:
- 识别为给非本机流量,发现是负载转发到后端服务,就直接修改目的MAC地址和IP地址,原路从网卡扔回去
- 识别为给本机流量,走传统通道,放行到linux协议栈;走极速通道,直接把包通过内存映射(MMAP)塞给本机的专用应用,绕过协议栈
4、长久且全能的Linux协议栈
在网络包达到Linux协议栈时,将进入四表五链中进行处理:
1)数据包刚从网卡进来,还没决定路由走向,经过PREROUTING链,依次经过三张表:Raw表(是否绕过连接跟踪conntrack)-> Mangle表(修改TOS/DSCP/TTL/MARK等元信息字段)-> NAT表(DNAT、NPAT),然后进入路由表决策,其中有MARK并配置策略路由(Policy Routing)、用 `ip rule show`命令查看,或者直接查看路由表 `ip route`命令;
2)如果路由指向本机时,进入INPUT链,依次经过 Mangle表(很少用、修改TOS/DSCP/TTL/MARK等元信息字段)-> Filter表(访问控制),然后上送到应用程序;
3)如果路由指向非本机时(内核要开启 IP 转发net.ipv4.ip_forward = 1),进入FORWARD链,依次经过 Mangle表(修改TOS/DSCP/TTL/MARK等元信息字段) -> Filter表(访问控制),后续数据推送至POSTROUTING链;
4)应用程序向外推送数据时,进入OUTPUT链,依次经过四张表:Raw表-> Mangle表-> NAT表-> Filter表,功能和上面的大同小异,后续要再次路由决策(确定出口网卡和下一跳),数据再推送至POSTROUTING链;
4)数据最后发送出去前,经过POSTROUTING链,依次经过Mangle表-> NAT表(SNAT、NPAT)。
下图是学习时的手稿:
GPT给的图: