从一根网线到一个 skb:RK3588 STMMAC 与 RTL8211F 网卡驱动全景解析
很多网卡问题都有一种迷惑性: MDIO 能读到 PHY ID,但接口始终 NO-CARRIER; ethtool 显示 1000 Mbps、Link detected: yes,却 ping 不通; 百兆稳定,千兆一跑 iperf3 就出现 CRC error; 开机前几秒能收包,随后 RX 停止; 低流量正常,并发或大包时 TX timeout; 关闭 checksum/TSO/GRO 后“神奇恢复”。 这些现象之所以难排,是因为我们口中的“网卡驱动”其实横跨多个软硬件层:RK3588 内部的 Synopsys DWMAC、Rockchip 的 GRF/clock/reset glue、外置 RTL8211F PHY、RGMII 数据总线、MDIO 管理总线、Linux stmmac、phylink/phylib、NAPI、DMA 和网络协议栈。 如果只盯着 stmmac_main.c 的某一个函数,或者只盯着 PHY 的 link 状态,就很容易在错误的层次上修问题。 本文以本地 Firefly RK3588 SDK 的 ...
Linux sk_buff 深度解析(八):Socket 内存、零拷贝、丢包与版本演进
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 从 socket truesize/owner、MSG_ZEROCOPY、error queue、drop reason 讲到 Linux 5.10 与 6.1 的 skb 演进,并总结 RK3588 BSP 的验证边界。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持...
Linux sk_buff 深度解析(七):VLAN、隧道、分片与重组
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 解释 VLAN metadata、inner/outer header、encapsulation、隧道 GSO/checksum,以及 IPv4/IPv6 分片队列和 frag_list 重组后的非线性布局。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? ...
Linux sk_buff 深度解析(六):Netfilter、tc、eBPF 与 XDP
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 从 Hook、verdict 和所有权出发,比较 Netfilter/Conntrack/NAT、tc action、eBPF __sk_buff 视图,以及 XDP 进入 skb 世界前后的边界。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb s...
Linux sk_buff 深度解析(五):GRO、GSO、Checksum 与多核流调度
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 把 GRO/GSO/TSO、checksum 四态以及 RSS/RPS/RFS/XPS 放在同一性能模型下,解释 skb 元数据如何替代重复解析和拷贝。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb shell、hea...
Linux sk_buff 深度解析(四):从 sendmsg 到 TX completion
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 打通 UDP/TCP sendmsg、IPv4 output、qdisc、ndo_start_xmit、stmmac DMA 映射与 TX clean,重点解释队列和驱动的 skb 所有权契约。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb shell、he...
Linux sk_buff 深度解析(三):从网卡 DMA 到 Socket 的 RX 路径
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 以 RK3588 stmmac 为驱动实例,追踪 DMA page 构造 skb、NAPI/GRO/RPS、IPv4、TCP/UDP 到 Socket 接收队列的完整所有权变化。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb shell、...
Linux sk_buff 深度解析(二):非线性数据、引用计数与生命周期
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 深入 linear、frags、frag_list、users、dataref、page ref,串联 sk_buff 的分配、clone、copy、COW 与分层释放。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb shell、head、frag page 以及 s...
Linux sk_buff 深度解析(一):数据结构、四指针与核心字段
写在前面sk_buff 是 Linux 网络栈最核心、也最容易被误解的数据结构之一。它并不是“装着一个完整网络包的结构体”,而是贯穿驱动、协议栈、队列、Socket、Netfilter、tc、BPF 与硬件 offload 的控制对象和所有权载体。 从 sk_buff 为什么不是一个简单 buffer 出发,系统解释 skb shell、linear head、shared info、四指针、header offset、核心字段与数据区操作。 本文以本地 Linux 5.10.209 源码为主线;涉及演进时对照 Linux 6.1.99,涉及网卡驱动时结合 Firefly RK3588 SDK Linux 5.10.198。本文是源码分析,不把尚未执行的 QEMU、tracepoint 或开发板实验写成已验证结论。 阅读前先建立四个问题阅读任何 skb 代码路径,都建议反复追问: 当前 skb->data 指向哪一层协议头,linear 与 non-linear 数据分别在哪里? 哪些字段刚被修改,下一层为什么依赖这些字段? 当前谁持有 skb shell、head、f...
Linux 内核 NAPI 机制深度解析:从硬中断到软中断轮询
写在前面如果你曾经好奇——网卡每秒收到几十万个包,为什么系统没有崩溃?为什么 Linux 网络栈在高 PPS 下仍能保持吞吐?答案的核心之一就是 NAPI(New API)。 NAPI 不是某个单一函数,而是一套”中断触发、软中断批量轮询、按预算公平调度”的收包负载控制框架。理解它,是读懂 Linux 网络收包路径的必经之路。 本文以 Linux 5.10 为主线,6.1 做对比,结合 e1000 和 RK3588 stmmac 驱动实例,从问题动机到源码细节,完整拆解 NAPI 机制。 一、问题:为什么不能每个包一个硬中断?千兆/万兆网卡可能每秒产生几十万到数百万个包。如果每个包都触发一次硬中断,CPU 会进入 interrupt livelock——看起来一直忙,但业务处理反而推进很少。具体问题包括: 中断频率过高:CPU 主要时间花在中断入口/出口、寄存器保存恢复、上下文切换上,而不是协议栈本身。 硬中断上下文限制多:不能睡眠,不适合做复杂协议栈处理、内存回收和大批量逻辑。 缓存局部性差:每个包独立打断当前执行流,频繁污染 I-cache/D...
