首页/目录/全部文章

全部文章

八个专题的源码、算法与协议笔记都在这里。

笔记列表

01 net/core 核心机制与实现详解

01 net/core 核心机制与实现详解

1. 地位

net/core/(约 57 文件)是 所有协议族的公共底座:没有它,ipv4bridgemac80211 无法共享 sk_buffnet_device 语义。

2. 数据面主干:sk_buff

skbuff.c 管理:

  • 分配/释放(alloc_skbkfree_skb);
  • skb_clone / pskb_copy(广播、转发、Netfilter);
  • 队列:skb_queue_tailsk_receive_queue
  • 头部推拉:skb_push/skb_pull(各层加解封装);
  • offload 标记:skb->ip_summedhw_features

RK3588 千兆/2.5G 驱动性能调优常看 GRO/LROskb 分配 NUMAnetdev_alloc_skb)。

3. 控制面:socket 与 sock

sock.c(core 部分)与顶层 socket.c 分工:

文件 职责
系统调用 net/socket.c SYSCALL_DEFINE、fd 与 struct socket
协议无关 net/core/sock.c 锁、队列、回调、diag

struct sock 通过 struct proto_ops 挂接 inet_stream_ops 等。

4. 网络设备:dev.c

dev.c 核心能力:

  • register_netdev / unregister_netdev
  • dev_queue_xmit 发送入口;
  • netif_receive_skb / __netif_receive_skb_core 接收入口;
  • NAPInetif_napi_addnapi_schedule(详见 09-NAPI收包轮询机制与实现详解.md);
  • netdev_rx_handler(bridge、vlan、macvlan);
  • 统计:dev->stats、RTNL 查询。

与驱动边界:ndo_open/stop/xmit 在驱动,队列调度与 qdisc 在 core/sched。

5. 路由与邻居

文件 作用
dst.c dst_entry 缓存、过期、回调到 neighbour
neighbour.c 通用邻居表;ARP/ND 在 ipv4/ipv6 子模块注册
fib_notifier.c FIB 变更通知(BPF、IOAM 等订阅)

rtnetlink.c 实现 NETLINK_ROUTE(建立在 net/netlink/ 框架上,详见 10-netlink内核用户通信机制与实现详解.md):

  • 链路增删(RTM_NEWLINK);
  • 地址(RTM_NEWADDR);
  • 路由(RTM_NEWROUTE);
  • iproute2ip link/ip route)一一对应。

网络命名空间:struct net 隔离 RTNL 表项。

7. 性能路径:GRO / XDP / flow_offload

机制 文件 说明
GRO gro.c 合并小包减中断开销
XDP xdp.c 驱动早丢弃/转发;与 net/xdp AF_XDP 配合
flow_offload flow_offload.c 硬件流表卸载(switchdev、DSA)
TSO tso.c TCP 分段 offload

8. BPF 挂钩(core 内)

CONFIG_BPF_SYSCALL 时:

  • sock_map.c — BPF map 与 socket 绑定;
  • bpf_sk_storage.c — per-socket BPF 存储;
  • filter.c — 经典 BPF socket filter。

完整 BPF 指令集在 kernel/bpf/ + net/bpf/ 测试桩。

9. 小结

net/core = skb + dev + dst + neighbour + rtnl + NAPI/GRO/XDP。RK3588 网络问题(丢包、延迟、软中断 CPU)多数需结合 core 统计与 驱动 NAPI 同看。

专文:rk3588-kernel-6.1-net-core分析_zh.md

02 IPv4 与传输层机制与实现详解

02 IPv4 与传输层机制与实现详解

1. 目录与配置

net/ipv4/~135 文件),依赖 CONFIG_INET

提供 AF_INETPF_INET):IPv4 地址族、TCP/UDP/RAW/ICMPIGMPARPFIB 路由

2. 协议注册

af_inet.c 在初始化时注册 inet_proto_ops

  • socketinet_create
  • 协议号映射到 tcp_protudp_protraw_protstruct proto

3. 传输层

协议 主要源文件 要点
TCP tcp_*.c(ipv4 + 通用) 状态机、拥塞控制(可插拔 CC)、timewait、SACK
UDP udp.c 无连接、udp_sendmsg/udp_recvmsg
RAW raw.c 原始 IP 访问
ICMP icmp.c ping、差错报文

MPTCPnet/mptcp/ 扩展 TCP(CONFIG_MPTCP)。

数据路径(发送简化):

1
sock_sendmsg → tcp_sendmsg → ip_queue_xmit → dst → dev_queue_xmit

4. 路由与 FIB

组件 作用
fib_*.c 转发信息库、策略路由、FIB rules
route.c ip_route_output_keyfib_lookup
arp.c IPv4 ARP

policy routingip rule)在 FIB 规则层实现。

5. Netfilter(IPv4 侧)

net/ipv4/netfilter/iptables 兼容defragNAT 片段 等;核心 hook 框架在 net/netfilter/(见 04 文档)。

Hook 点:NF_INET_PRE_ROUTINGLOCAL_INFORWARDPOST_ROUTING 等。

6. 隧道与特殊

目录/文件 功能
ip_tunnel.c IPIP/GRE 等
xfrm4_*.c IPsec 与 net/xfrm 协作
bpfilter/ 实验性 iptables BPF 代理

7. RK3588 场景

  • 板载以太网:默认 DHCP/静态 IP 走 ipv4 FIB + ARP;
  • NAT/防火墙netfilter + iptables-nft
  • WiFi STA:同一 ipv4 栈,接口为 wlan0
  • 性能:调整 tcp_congestion_controlnetdev_max_backlogsomaxconn

专文:rk3588-kernel-6.1-net-ipv4分析_zh.md

8. 小结

ipv4/ 是 RK3588 最常见 L3/L4 路径;与 drivers/net 分界在 ip_finish_output2 → 邻居解析 → 驱动发送

03 IPv6 与邻居路由机制与实现详解

03 IPv6 与邻居路由机制与实现详解

1. 目录特点

net/ipv6/~107 文件)。顶层 net/Makefileobj-y += ipv6/ 使 IPv6 底座常编入内核,具体特性仍由 CONFIG_IPV6 及各子选项控制。

2. 地址与接口配置

模块 作用
addrconf.c SLAAC、静态地址、ipv6_add_addr
addrlabel.c 源地址选择标签
anycast.c 任播

RTNETLINKRTM_NEWADDR(AF_INET6)对接 ip -6 addr

3. 邻居发现 ND

ndisc.c 实现 RFC 4861

  • Router Solicitation/Advertisement;
  • Neighbor Solicitation/Advertisement(替代 ARP);
  • Redirect。

挂在 neighbour 子系统 上,协议号 NDISC

4. 路由 fib6

文件 作用
ip6_fib.c FIB6 表
route.c ip6_route_outputfib6_lookup
ip6_flowlabel.c 流标签

策略路由ip -6 rule)与 ipv4 对称。

5. 扩展头与分片

  • exthdrs.c — Hop-by-Hop、Routing、Destination;
  • reassembly.c — 分片重组;
  • seg6.c / rpl.c 等 — 可选 SRv6、RPL(配置依赖)。

6. 传输层

TCPv6UDPv6ICMPv6RAWv6 与 ipv4 共享大量 tcp_ipv4.c/tcp_ipv6.c 划分(实际文件在 ipv6 与 net/ipv4 协同)。

inet6_connection_sock 处理双栈 socket。

7. Netfilter IPv6

net/ipv6/netfilter/ip6tablesnf_defrag_ipv6NAT66 等。

8. RK3588

  • 嵌入式产品 可关闭 IPv6 减体积;
  • 双栈产品需 ND + dhcpv6 或 SLAAC;
  • Thunder Boot 无直接 net/ipv6 补丁(通用栈)。

专文:rk3588-kernel-6.1-net-ipv6分析_zh.md

9. 小结

IPv6 在 RK3588 上与 ipv4 共享 core/dev;差异在 ND 替代 ARP128 位地址路由

04 netfilter 与包过滤机制与实现详解

04 netfilter 与包过滤机制与实现详解

1. 概述

net/netfilter/~253 文件)是 Linux 包过滤、连接跟踪、NAT、负载均衡 的核心实现。它在协议栈 固定 hook 点 介入 sk_buff 路径,不改变网卡驱动;与 NAPI/收包 正交,作用于 L3 已解析之后 的转发/本地交付决策。

项目 说明
源码路径 rk3588/kernel-6.1/net/netfilter/
配置 CONFIG_NETFILTER 及子项(见 Kconfig
用户态 nft(nftables)、iptables(legacy)、conntrack
控制通道 NETLINK_NETFILTERnfnetlink.c
RK3588 无 Rockchip 专属补丁;行为与上游 6.1 一致

1.1 目录结构(按功能)

1
2
3
4
5
6
7
8
9
10
11
net/netfilter/
├── core.c # Hook 框架(注册、nf_hook_slow)
├── nfnetlink.c # NETLINK_NETFILTER 总线
├── nf_conntrack_*.c # 连接跟踪
├── nf_nat_*.c # NAT / 伪装
├── nf_tables_*.c nft_*.c # nftables
├── x_tables.c xt_*.c # iptables 扩展
├── nf_queue.c nf_log.c # 队列到用户态 / 日志
├── nf_flow_table_*.c # 快速转发路径
├── ipset/ # 高效匹配集合
└── ipvs/ # LVS 负载均衡

注意:IPv4/IPv6 的 iptables 表驱动net/ipv4/netfilter/net/ipv6/netfilter/(如 ip_tables.cip6_tables.c),但 hook 框架与 nftables 主体在 net/netfilter/


2. Hook 框架(core.c

2.1 Hook 点(IPv4/IPv6 _inet)

定义于 include/uapi/linux/netfilter.h

Hook 典型位置
NF_INET_PRE_ROUTING 路由决策前(入站)
NF_INET_LOCAL_IN 本机接收
NF_INET_FORWARD 转发
NF_INET_LOCAL_OUT 本机发出
NF_INET_POST_ROUTING 路由后、出接口前
NF_INET_INGRESS 入口(netdev 早期)
本机转发网卡收包L2 解封装NF_INET_PRE_ROUTING路由NF_INET_LOCAL_INNF_INET_FORWARD协议栈 / socketNF_INET_LOCAL_OUTNF_INET_POST_ROUTINGdev_queue_xmit

协议栈调用示例(net/ipv4/ip_forward.c):

1
2
return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, net, NULL, skb,
in, out, ip_forward_finish);

2.2 注册与存储

  • nf_register_net_hook() / nf_register_net_hooks():按 priority 插入 hook 数组
  • (netns, pf, hooknum) 维护 nf_hook_entries(RCU 只读遍历)
  • CONFIG_JUMP_LABELnf_hooks_needed[pf][hook] 无 hook 时跳过 nf_hook_slow 快速路径

nf_hook_ops 关键字段:

1
2
3
4
5
6
7
struct nf_hook_ops {
nf_hookfn *hook; /* 回调 */
u8 pf; /* NFPROTO_IPV4 / IPV6 / INET ... */
unsigned int hooknum;
int priority; /* 数值越小越先执行 */
void *priv;
};

2.3 nf_hook_slow() — 核心裁决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
const struct nf_hook_entries *e, unsigned int s)
{
for (; s < e->num_hook_entries; s++) {
verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);
switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT:
break;
case NF_DROP:
kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP);
return ret;
case NF_QUEUE:
ret = nf_queue(skb, state, s, verdict);
// ...
default:
return 0; /* NF_STOLEN 等 */
}
}
return 1; /* 全部 ACCEPT → 调用 okfn */
}
Verdict 含义
NF_ACCEPT 继续下一个 hook 或 okfn
NF_DROP 丢弃 skb
NF_STOLEN hook 接管 skb,协议栈不再处理
NF_QUEUE 交用户态队列裁决(nf_queue.c
NF_REPEAT 重新从当前 hook 执行

内联入口 nf_hook()include/linux/netfilter.h)在 static_key 显示无 hook 时直接 okfn(skb)


3. 连接跟踪(nf_conntrack)

3.1 核心文件

文件 作用
nf_conntrack_core.c 表项创建/查找/GC、nf_conntrack_in
nf_conntrack_proto_*.c TCP/UDP/ICMP 等 L4 状态机
nf_conntrack_expect.c 期望连接(FTP/SIP 等多通道)
nf_conntrack_helper.c + nf_conntrack_ftp.c ALG 辅助
nf_conntrack_netlink.c 用户态查询/事件

3.2 nf_conntrack_in() 流程

挂于 PREROUTINGLOCAL_OUT 等(由 nf_conntrack_l3proto 注册):

1
2
3
4
5
nf_conntrack_in(skb)
→ get_l4proto() 定位 L4
→ resolve_normal_ct() 查表或新建 nf_conn
→ nf_conntrack_handle_packet() 更新 TCP 状态等
→ skb->_nfct 绑定连接

连接以 五元组 tuple(可加 zone)哈希入 nf_conntrack_hash;状态如 NEW / ESTABLISHED / RELATED

3.3 与 NAT 关系

  • conntrack 独立于 NAT,但 NAT 修改 tuple 必须同步 conntrack(nf_nat_core.c
  • nf_nat_hook 通过 RCU 指针在 core.c 中挂接,避免模块循环依赖

4. NAT(nf_nat)

文件 作用
nf_nat_core.c SNAT/DNAT 查找、tuple 改写
nf_nat_proto.c 协议相关校验和/端口映射
nf_nat_masquerade.c MASQUERADE(出接口地址)
nf_nat_redirect.c REDIRECT(本机端口)
nf_nat_ftp.c NAT helper

NAT 在 POSTROUTING(SNAT)/ PREROUTING(DNAT)hook 修改 skb 地址端口,并 nf_conntrack_alter_reply() 维护反向 tuple。


5. nftables(现代推荐)

5.1 组成

Makefilenf_tables-objs

  • nf_tables_core.c — 规则求值 nft_do_chain()
  • nf_tables_api.c — 表/链/规则/集合的 netlink 配置 API
  • nft_chain_filter.c / nft_chain_route.c / nft_chain_nat.c — 链类型与 hook 绑定
  • nft_*.c — 表达式:payload、cmp、lookup、ct、nat、limit、queue…
  • nft_set_*.c — 集合后端:hash、bitmap、rbtree、pipapo(x86 可有 AVX2)

5.2 规则求值:nft_do_chain()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv)
{
const struct nft_chain *chain = priv;
// 从 RCU blob 遍历规则
for (; rule < last_rule; rule = nft_rule_next(rule)) {
nft_rule_dp_for_each_expr(expr, last, rule) {
// fast path: nft_cmp_fast_eval, nft_payload_fast_eval ...
expr_call_ops_eval(expr, &regs, pkt);
if (regs.verdict.code != NFT_CONTINUE)
break;
}
// NFT_JUMP / NFT_GOTO / NF_ACCEPT / NF_DROP ...
}
}
  • 规则编译为 字节码 blob(表达式序列),求值用 nft_regs 寄存器
  • jump stack 支持 jump/goto 子链
  • gencursor 双缓冲:用户态更新规则时 RCU 切换,数据面无锁读

5.3 Hook 注册

nft_chain_filter.cnft_do_chain_ipv4 注册到各 NF_INET_* hook:

1
[NF_INET_FORWARD] = nft_do_chain_ipv4,

nf_tables_api.cnft_chain_hook 管理 base chain 与 nf_register_net_hook 的绑定。

5.4 用户态配置

1
2
3
nft add table ip filter
nft add chain ip filter forward { type filter hook forward priority 0 \; }
nft add rule ip filter forward tcp dport 22 accept

内核路径:nftNFNL_SUBSYS_NFTABLESnfnetlink)→ nf_tables_api.c


6. iptables / x_tables(legacy)

组件 路径 说明
x_tables x_tables.c match/target 注册框架
xt_*.c net/netfilter/xt_*.c 扩展:conntrack、mark、limit、LOG…
ip_tables net/ipv4/netfilter/ip_tables.c filter/nat/mangle 表
nft_compat nft_compat.c 可选:iptables 规则转 nft 后端

xt_conntrack.c 依赖 nf_conntrackxt_set.c 依赖 ipset


nfnetlink.c 实现 NETLINK_NETFILTER,子系统分发表 table[NFNL_SUBSYS_*]

子系统 用途
NFNL_SUBSYS_NFTABLES nft 表/链/规则
NFNL_SUBSYS_CTNETLINK conntrack 查询/事件
NFNL_SUBSYS_IPSET ipset 管理
NFNL_SUBSYS_QUEUE NFQUEUE
NFNL_SUBSYS_HOOK hook 查询(新)

每 netns:netlink_kernel_create(net, NETLINK_NETFILTER, &cfg)

详见 10-netlink内核用户通信机制与实现详解.md


8. 辅助子系统

8.1 ipset(ipset/

  • ip_set_core.c:集合类型注册、ip_set_test/add/del
  • 类型:hash:iphash:netbitmap:port 等(ip_set_hash_*.c
  • xt_set / nft_lookup 做大规模地址/端口匹配

8.2 nf_flow_table(快速转发)

nf_flow_table_core.c + nft_flow_offload.c

  • 对已 ESTABLISHED 连接缓存 flow_offload 条目
  • 后续包可 绕过部分协议栈 直接转发(可硬件 offload)
  • 依赖 conntrack tuple

8.3 ipvs(ipvs/

Linux Virtual Server:L4 负载均衡,独立 hook 与调度器(rr、wlc、mh 等),与 filter/NAT 可叠加。

8.4 nf_queue / nf_log

  • nf_queue.cNF_QUEUE verdict 将 skb 送用户态(如 iptables -j NFQUEUE
  • nf_log.c / nfnetlink_log.c:LOG/NFLOG 目标

9. 模块依赖关系(简化)

core.c Hook 框架nf_tables / nft_*nf_conntracknf_natx_tables / xt_*ipsetnfnetlink

10. 调试与 sysctl(常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 规则
nft list ruleset
iptables -L -n -v

# 连接跟踪
cat /proc/net/nf_conntrack
sysctl net.netfilter.nf_conntrack_max

# 统计
cat /proc/net/stat/nf_conntrack
nft monitor trace # 需内核 trace 支持

# drop 原因(较新内核)
# SKB_DROP_REASON_NETFILTER_DROP

11. RK3588 场景

场景 关注点
网关/路由器 nf_conntrack_max、FORWARD 链默认 policy、MASQUERADE
Android/嵌入式 iptables-legacy 或 nft;热点 NAT
容器 netns 隔离;每 netns 独立 nft 表与 conntrack
性能 规则数量、nf_flow_table、避免过多 xt_recent/hashlimit
WiFi AP bridge + iptables FORWARD;或 nft forward chain

net/netfilter/ 内 RK 补丁;板级差异来自 defconfigCONFIG_NF_* 开关)与用户态规则。


12. 源码索引

主题 路径
Hook 注册/执行 net/netfilter/core.c
nf_hook 内联 include/linux/netfilter.h
conntrack 入口 net/netfilter/nf_conntrack_core.cnf_conntrack_in
NAT net/netfilter/nf_nat_core.c
nft 求值 net/netfilter/nf_tables_core.cnft_do_chain
nft 配置 API net/netfilter/nf_tables_api.c
nft hook 绑定 net/netfilter/nft_chain_filter.c
nfnetlink net/netfilter/nfnetlink.c
ipset net/netfilter/ipset/ip_set_core.c
flow offload net/netfilter/nf_flow_table_core.c
IPv4 iptables net/ipv4/netfilter/ip_tables.c

13. 相关文档


14. 小结

问题 答案
netfilter 在哪介入? 协议栈 NF_INET_* hook 点,对 sk_buff 裁决
框架核心文件? core.cnf_hook_slow
现代防火墙 API? nftablesnf_tables + nft_*
状态防火墙基础? nf_conntrack + 可选 nf_nat
如何配置? 用户态 nft/iptablesNETLINK_NETFILTER
与驱动关系? 无直接耦合;仅处理已进入网络栈的包

05 调度、tc、BPF 与 XDP 机制与实现详解

05 调度、tc、BPF 与 XDP 机制与实现详解

1. 三个相关子系统

目录 职责 配置
net/sched/ Traffic Control:qdisc、分类、动作 常 y
net/bpf/ 网络相关 BPF 自检/测试运行 CONFIG_BPF
net/xdp/ AF_XDP 用户态零拷贝 CONFIG_XDP_SOCKETS
kernel/bpf/ BPF 解释器/JIT(不在 net/) CONFIG_BPF_SYSCALL

tcXDP 是 RK 上 QoS、高性能收包 的主要内核接口。

2. net/sched — Traffic Control

sch_*.c — 队列规程(pfifo_fast、fq_codel、htb…)
cls_*.c — 分类器(u32、flower、bpf…)
act_*.c — 动作(mirred、pedit、bpf、vlan…)

配置通路:NETLINK_ROUTEtc 子族(tc qdisctc filter)。

数据路径:dev_queue_xmit → qdisc_enqueue → 驱动**;ingress 在 **__dev_xmit_skb` 之前 的 ingress qdisc。

3. core 中的 BPF 挂钩

  • cls_bpf / act_bpf 在 sched;
  • sock_mapsk_msg 在 core(BPF 与 socket 结合);
  • lwt_bpf.c — 轻量隧道 BPF。

4. net/bpf/

主要为 BPF_PROG_TEST_RUN 对网络程序类型的 内核自测(skb、xdp、flow_dissector 等),不是 数据面必经路径。

用户态加载程序走 bpf() 系统调用kernel/bpf/syscall.c)。

5. XDP 两层

位置 说明
原生 XDP 驱动 ndo_bpf / xdp_buff 最早点处理
generic XDP net/core/xdp.c 无驱动支持时的慢路径
AF_XDP net/xdp/ 用户态 mmap 环(XSK)

bpftool 加载 SEC("xdp") 程序;驱动需声明 NETDEV_XDP_ACT_* 能力。

6. ethtool 协同

net/ethtool/ 配置 ring、channel、pause 参数,影响 XDP/tc 性能上限。

7. RK3588

场景 建议
出口限速 htb/fq_codel on eth0
高性能收包 驱动 XDP + AF_XDP(若驱动支持)
过滤 tc flowernft + netfilter

stmmac 等驱动 XDP 支持因版本/补丁而异,需查 ethtool -k 与驱动 Release notes。

专文:schedbpfxdp

8. 小结

sched = 队列与策略;BPF = 可编程挂载点;XDP = 尽早处理包。三者正交,可组合使用。

06 二层、桥接、无线与 socket 族机制与实现详解

06 二层、桥接、无线与 socket 族机制与实现详解

1. 链路层与以太辅助

目录 作用
ethernet/ eth.ceth_type_transalloc_etherdev
802/ LLC/SNAP、STP 辅助
8021q/ VLAN 子接口、vlan_dev
bridge/ 网桥 FDB、转发、STP、与 netfilter 桥挂钩
dsa/ 交换机 CPU 口 + 标签协议
switchdev/ 硬件交换 offload 通知 API
hsr/ 工业冗余协议

RK3588 板载 单口或双口 GMAC 常用 vlan;多口交换芯片可能 DSA

2. 无线协议栈(框架在 net/)

iw / wpa_supplicantnl80211net/wireless cfg80211net/mac80211drivers/net/wireless
目录 职责
wireless/ cfg80211、监管域、扫描、注册 wiphy
mac80211/ 802.11 MAC:加密、聚合、mesh

芯片驱动(BCM/AP6212 等)在 drivers/net/wireless/,实现 ieee80211_ops

net/wireless/KconfigROCKCHIP_THUNDER_BOOT 影响部分默认项(非核心逻辑)。

3. 其它 socket 地址族(节选)

目录 AF RK 相关性
unix/ AF_UNIX 高(本地 IPC)
packet/ AF_PACKET 抓包、dhcp 客户端
can/ AF_CAN 车载/工业 CAN
bluetooth/ AF_BLUETOOTH 板载 BT
tls/ kTLS HTTPS 卸载
vmw_vsock/ AF_VSOCK 虚拟机
qrtr/ QRTR 高通,RK 一般不用

4. 管理与观测

目录 作用
netlink/ AF_NETLINK、genetlink 基础设施
ethtool/ 链路参数、统计、环大小
devlink/ 端口拆分、固件(部分 NIC)
rfkill/ 射频开关(含 RK 驱动
psample/ 采样到用户态

5. RK3588:rfkill

CONFIG_RFKILL_RKrfkill-wlan.c / rfkill-bt.c

  • rockchip_wifi_power() — WiFi 电源;
  • rockchip_wifi_set_carddetect() — SDIO 检测;
  • rockchip_wifi_mac_addr() — vendor storage MAC;
  • GRF/syscon 引脚控制。

导出符号供 bcmdhd、brcmfmac 等模块调用。

详见 08-RK3588rfkill 专文

6. 小结

二层/无线 框架在 net/芯片在 drivers/。RK 产品 WiFi/BT 必涉及 rfkill + cfg80211 + 厂商无线驱动 三角关系。

07 数据面路径与 drivers 分界机制与实现详解

07 数据面路径与 drivers 分界机制与实现详解

1. 接收路径(RX)

ipv4/ipv6eth_type_transnet/coredrivers/netMAC/PHY DMAipv4/ipv6eth_type_transnet/coredrivers/netMAC/PHY DMAIRQ NAPI pollnapi_gro_receive / netif_receive_skb__netif_receive_skb_coreip_rcv / ipv6_rcvtcp_v4_rcv / udp_rcv

要点:

  1. 驱动 只做 DMA 描述符 → skb 封装、硬件 offload 标记;
  2. GRO 在 core 合并;
  3. Netfilter PRE_ROUTING 在 L3 入口;
  4. 协议栈 向上递交到 socket 接收队列

2. 发送路径(TX)

1
2
sock_sendmsg → proto_sendmsg → ip_queue_xmit → neigh_resolve_output
→ dev_queue_xmit → qdisc → ndo_start_xmit → DMA

TSO/GSO:在 core/protocol 分段,驱动发大包或硬件分段。

3. 分界表

职责 net/ drivers/net/
套接字语义
TCP/UDP 状态机
FIB/ARP/ND
net_device 抽象 ✓ 定义 ✓ 注册实例
寄存器/DMA/NAPI
MDIO PHY ✓(常 phy 子目录)
ethtool 能力声明 ✓ 框架 ✓ ops 实现
XDP 程序 attach ✓ 框架 ✓ ndo_bpf

4. RK3588 常见驱动位置

接口 典型路径
板载 GMAC drivers/net/ethernet/stmicro/stmmac/ 或 Rockchip dwmac
PCIe 网卡 r8169igc
WiFi drivers/net/wireless/broadcom/brcmfmacbcmdhd
USB 网卡 asixr8152

Device Tree 描述 MAC/PHY 在 arch/arm64/boot/dts/rockchip/,不在 net/

5. 统计与调试接口

工具 内核侧
ip -s link dev->stats、per-queue stats
ethtool -S get_ethtool_stats(驱动)
drop_monitor net/core/drop_monitor.c
ftrace/tcp 协议 tracepoint

6. 与编解码/多媒体

RK3588 VPU/NPU 不走 net/ 主路径;RTP/RTSP 多在用户态或 MPP,内核仅提供 UDP socket。网络调优关注 带宽、抖动、防火墙

7. 小结

排障时先确定层次:链路 up?(驱动)→ 路由?(fib)→ 过滤?(netfilter)→ 应用?(socket)。线速问题常落 驱动 + 中断亲和 + RPS

08 RK3588 平台关联与使用场景详解

08 RK3588 平台关联与使用场景详解

1. net/ 内 Rockchip 代码范围

net/ grep Rockchip4 个文件

文件 内容
rfkill/rfkill-wlan.c WiFi 电源、SDIO 卡检测、OOB IRQ、MAC、WiFi 内存预分配
rfkill/rfkill-bt.c 蓝牙射频控制
rfkill/Kconfig CONFIG_RFKILL_RK
wireless/Kconfig default y if !ROCKCHIP_THUNDER_BOOT(2 处)

协议栈主体(ipv4、tcp、netfilter…)均为上游通用实现

2. CONFIG_RFKILL_RK

1
2
3
4
config RFKILL_RK
tristate "Rockchip RFKILL driver"
depends on ARCH_ROCKCHIP
depends on MMC

产物:rfkill-wlanrfkill-bt 模块(或 built-in)。

2.1 导出 API(WLAN)

符号 用途
rockchip_wifi_power 上/下电
rockchip_wifi_set_carddetect SDIO 卡检测 GPIO
rockchip_wifi_get_oob_irq 外带中断线
rockchip_wifi_mac_addr rk_vendor_storage 读 MAC
rockchip_mem_prealloc WiFi 固件内存预留

无线 芯片驱动(如 SDIO)在 probe 时调用上述接口,而非在 net/ipv4 内写死。

2.2 BSP 集成

  • defconfig 常开 CONFIG_RFKILL=y + CONFIG_RFKILL_RK=m/y
  • U-Boot/loaderregulator 在 DT 定义,rfkill 脚本按 OF 解析 rockchip,grf 等。

3. 以太网(不在 net/)

RK3588 千兆:

  • DTgmac0stmmacrk_gmac 节点;
  • 驱动drivers/net/ethernet/
  • 调优ethtoolnetdev_budgetrps_sock_flow_table

net/core 仅见 同一套 dev_queue_xmit 路径。

4. 典型产品场景

场景 涉及 net/ 子系统
嵌入式网关 ipv4、netfilter、bridge、sched
Android/盒子 ipv4、netfilter、rfkill、cfg80211
工业网关 can、ipv4、bridge
摄像头/NVR 上云 ipv4 TCP、TLS(可选 kTLS)
容器 veth、netfilter、ipv4 命名空间

5. 推荐 defconfig 关注点

1
2
3
4
5
6
7
8
CONFIG_NET=y
CONFIG_INET=y
CONFIG_IPV6=y # 按需
CONFIG_NETFILTER=y / NFTABLES
CONFIG_CFG80211=y
CONFIG_MAC80211=y
CONFIG_RFKILL=y
CONFIG_RFKILL_RK=y

关闭无用协议(ATM、TIPC、SMC…)可显著减小 vmlinux

6. 调试命令(板端)

1
2
3
4
5
6
7
ip link
ip route
ss -tunap
nft list ruleset # 或 iptables -L
ethtool -S eth0
cat /proc/net/softnet_stat
dmesg | grep -i rfkill

7. 关联文档

8. 小结

RK3588 上 net/ 分析 = 通用 Linux 网络栈 + 少量 rfkill 平台 glue;性能与稳定性关键在 GMAC/无线驱动 + DT 电源时序,而非 ipv4 协议差异。

09 NAPI 收包轮询机制与实现详解

09 NAPI 收包轮询机制与实现详解

1. 概述

NAPI(New API)是 Linux 网卡 收包路径 的核心抽象:用 短硬中断 + 软中断批量轮询 替代“每包一进中断”,在高 PPS 场景下降低 CPU 开销、提高吞吐。

项目 说明
头文件 include/linux/netdevice.h
实现 net/core/dev.c__napi_schedulenet_rx_actionnetif_napi_add_weight
与 socket 关系 NAPI 在 L2/L3 入口net/socket.crecvmsg 在更上层读已入队的 skb
驱动职责 实现 poll(),在 RX 中断里调用 napi_schedule()

2. 要解决的问题

2.1 纯中断收包的问题

1
每包 → 硬中断 → 中断上下文收包、上交协议栈
  • 中断次数 ≈ PPS,千兆/万兆时 CPU 耗在中断与上下文切换;
  • 中断里不宜做重逻辑,却又必须及时处理;
  • 多队列、多 CPU 时难以统一调度。

2.2 NAPI 的思路

1
2
3
硬中断:关中断/清状态 → napi_schedule()
软中断 NET_RX_SOFTIRQ:net_rx_action() → 驱动 poll() 批量收包(有 budget 上限)
收完或达到 budget:napi_complete() → 可再开中断

本质:中断 触发,收包 轮询,并由内核 统一限流


3. 核心数据结构

定义于 include/linux/netdevice.h

1
2
3
4
5
6
7
8
9
10
11
12
struct napi_struct {
struct list_head poll_list; /* 挂在 per-CPU poll 队列 */
unsigned long state; /* NAPI_STATE_* 状态位 */
int weight; /* 单次 poll 包数上限 */
int (*poll)(struct napi_struct *, int);
struct net_device *dev;
struct gro_list gro_hash[GRO_HASH_BUCKETS];
struct list_head rx_list;
struct hlist_node napi_hash_node;
unsigned int napi_id; /* busy poll 查找用 */
/* ... timer, thread, skb 等 */
};

3.1 状态位(节选)

状态 含义
NAPI_STATE_SCHED 已调度,poll 进行中或待执行
NAPI_STATE_MISSED schedule 时已在跑,需再次调度
NAPI_STATE_DISABLE 禁用中,napi_schedule 无效
NAPI_STATE_THREADED poll 在内核线程中执行
NAPI_STATE_IN_BUSY_POLL 用户态 busy poll 占用

3.2 驱动回调 poll

1
int (*poll)(struct napi_struct *napi, int budget);
参数/返回值 约定
budget 本次最多处理包数(通常 = napi->weight
返回值 实际处理包数;必须 ≤ budget
< budget 通常表示本轮收完 → 调用 napi_complete()
== budget 可能还有包 → 框架 repoll

默认权重:NAPI_POLL_WEIGHT = 64


4. 驱动侧 API

4.1 注册与生命周期

API 作用
netif_napi_add(dev, napi, poll) 注册 NAPI,weight=64
netif_napi_add_weight(dev, napi, poll, weight) 指定 weight
netif_napi_add_tx(dev, napi, poll) 仅 TX 队列用 NAPI
napi_enable(napi) 使能,允许 schedule
napi_disable(napi) 禁用并等待 poll 结束
netif_napi_del(napi) 从设备链表移除

netif_napi_add_weight() 实现要点(net/core/dev.c):

  • 设置 napi->pollnapi->weightnapi->dev
  • 加入 dev->napi_listnapi_hash(busy poll);
  • 可选创建 NAPI 内核线程dev->threaded)。

4.2 调度与完成

API 典型调用点
napi_schedule(napi) RX 硬中断下半部
napi_schedule_irqoff(napi) local_irq_disable()
napi_complete(napi) poll 返回 work < budget
napi_complete_done(napi, work) 带 GRO flush 等
napi_reschedule(napi) complete 后仍有包

napi_schedule() 逻辑:

1
2
if (napi_schedule_prep(n))   /* CAS 置 SCHED,保证单实例 */
__napi_schedule(n); /* 加入本 CPU softnet_data.poll_list,触发软中断 */

4.3 收包辅助 API

API 作用
napi_alloc_skb(napi, len) NAPI 上下文分配 skb
napi_gro_receive(napi, skb) 收包并尝试 GRO 聚合
napi_consume_skb(skb, budget) 释放 skb(知悉 NAPI 预算)
napi_get_frags() / napi_frags_* 页片段收包模式

5. 内核调度路径

5.1 流程图

协议栈napi->pollNET_RX_SOFTIRQnapi_schedule驱动 ISR网卡 RX 中断协议栈napi->pollNET_RX_SOFTIRQnapi_schedule驱动 ISR网卡 RX 中断loop[work < budget]IRQnapi_schedule(napi)poll_list + raise softirq__napi_poll(napi, weight)读描述符/DMAnapi_gro_receive(skb)napi_complete (若收完)

5.2 net_rx_action(软中断)

net/core/dev.cNET_RX_SOFTIRQ 处理函数:

  1. 将当前 CPU softnet_data.poll_list 移到本地链表;
  2. 循环对每个 napi_struct 调用 napi_poll()__napi_poll()napi->poll()
  3. 累计消耗 netdev_budget(默认 300)与 netdev_budget_usecs 时间片;
  4. 预算用尽则 time_squeeze++,剩余 NAPI 留待下次软中断;
  5. 若 poll_list 非空,再次 raise_softirq(NET_RX_SOFTIRQ)

5.3 __napi_poll 与 repoll

1
2
3
4
5
work = n->poll(n, weight);
if (work < weight)
return work; /* 驱动应已 napi_complete */
/* work == weight:可能还有包 */
*repoll = true; /* 加入 repoll 链表,本轮或下轮继续 */

6. 驱动模板代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
struct my_netdev_priv {
struct napi_struct napi;
/* ... */
};

static int my_netdev_poll(struct napi_struct *napi, int budget)
{
struct my_netdev_priv *priv = netdev_priv(napi->dev);
int work = 0;

while (work < budget) {
struct sk_buff *skb;

skb = my_hw_fetch_one_packet(priv);
if (!skb)
break;

napi_gro_receive(napi, skb);
work++;
}

if (work < budget)
napi_complete_done(napi, work);

return work;
}

static irqreturn_t my_netdev_isr(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct my_netdev_priv *priv = netdev_priv(dev);

/* 清中断源、关 RX 中断(视硬件而定) */
napi_schedule(&priv->napi);
return IRQ_HANDLED;
}

static int my_netdev_probe(...)
{
struct my_netdev_priv *priv = ...;

netif_napi_add(ndev, &priv->napi, my_netdev_poll);
napi_enable(&priv->napi);
/* 注册 IRQ ... */
}

注意

  • 不要在 poll 里睡眠;
  • work > budget 会触发内核告警;
  • 多 RX 队列:每队列一个 napi_struct + 独立 poll

7. 系统级调优参数

参数 默认(约) 路径/变量 含义
NAPI_POLL_WEIGHT 64 单 NAPI 单次 poll 上限
dev_rx_weight 64 sysctl net.core.dev_weight backlog NAPI 权重
netdev_budget 300 sysctl net.core.netdev_budget 一次软中断最多“消耗”的包预算
netdev_budget_usecs ~2ms@HZ=100 sysctl net.core.netdev_budget_usecs 软中断时间上限
netdev_max_backlog 1000 sysctl net.core.netdev_max_backlog per-CPU 输入队列长度

7.1 观测

1
2
3
4
cat /proc/net/softnet_stat
# 列含义含:总处理包数、time_squeeze(预算不够被迫结束的次数)等

ethtool -S eth0 # 驱动层 RX 统计

time_squeeze 持续偏高 → 可适当增大 netdev_budget 或优化驱动/CPU 亲和。


8. 扩展机制

机制 说明
GRO napi_gro_receive 在 poll 路径聚合小包
RPS 跨 CPU 分发软中断(process_backlog + IPI)
busy poll 用户态通过 napi_id 轮询,低延迟场景
NAPI threaded dev_set_threaded(),poll 在 kthread
XDP 可在驱动更早 drop/redirect,与 NAPI 正交

协议栈默认 per-CPU backlog 也用一个 NAPI:process_backlog()(非网卡驱动),处理未启用 RPS 时的输入队列。


9. RK3588 关联

说明
实现位置 NAPI 框架在 net/corestmmac/dwmac、r8169 等在 drivers/net/ethernet/
板载 GMAC DT 中 gmac + stmmac 驱动,probe 时 netif_napi_add,RX IRQ → napi_schedule
WiFi SDIO/USB 无线驱动同样使用 NAPI;上电由 net/rfkill/rfkill-wlan.c 配合
与 Thunder Boot 不改变 NAPI 接口本身

调试千兆吞吐时:驱动 poll + netdev_budget + 中断亲和(smp_affinity 需一并查看。


10. 源码索引

内容 路径
struct napi_struct、内联 API include/linux/netdevice.h
netif_napi_add_weight__napi_schedulenet_rx_action net/core/dev.c
sysctl net/core/sysctl_net_core.c
napi_alloc_skb net/core/skbuff.c / include/linux/skbuff.h

11. 相关文档


12. 小结

问题 答案
NAPI 是什么? 网卡收包的 调度框架(不是 socket API)
驱动要做什么? 实现 poll,中断里 napi_schedule,收完 napi_complete
内核做什么? 软中断里按 budget 批量调 poll,全局限流
为何重要? 高吞吐下 减中断、提效率、统一调度

10 Netlink 内核-用户通信机制与实现详解

10 Netlink 内核-用户通信机制与实现详解

1. 概述

Netlink 是 Linux 内核与用户态之间的 配置与事件总线,对应协议族 PF_NETLINKsocket(AF_NETLINK, SOCK_DGRAM, protocol))。它不承载 IP 数据面流量,而是承载 路由、链路、防火墙、无线、审计 等控制消息。

项目 说明
实现目录 net/netlink/(7 文件)
头文件 include/linux/netlink.hinclude/uapi/linux/netlink.h
系统调用入口 net/socket.csendmsg/recvmsg 分发给 netlink_ops
与数据面 与 NAPI/收包路径正交;配置网卡/路由后影响数据面行为

1.1 目录与编译单元

1
2
3
4
5
6
7
8
net/netlink/
├── af_netlink.c # 核心:socket、单播/组播、dump、ACK、nl_table
├── af_netlink.h # netlink_sock、netlink_table(内部)
├── genetlink.c # Generic Netlink:family 注册与分发
├── policy.c # nla_policy 序列化导出
├── diag.c # CONFIG_NETLINK_DIAG
├── Makefile
└── Kconfig

Makefileobj-y := af_netlink.o genetlink.o policy.o


2. 架构总览

用户态系统调用层net/netlink协议 handler内核 socket用户 socket 队列ip / iproute2iw / wpa_supplicantnft / iptables-nftudevsocket.c: sendmsg recvmsgnetlink_opsnetlink_sendmsgnetlink_recvmsgnetlink_unicast / broadcastnetlink_rcv_skbnetlink_dumpNETLINK_ROUTE: rtnetlink.cNETLINK_GENERIC: genetlink.cNETLINK_NETFILTERNETLINK_AUDIT
类型 protocol 常量 典型用途 内核注册
固定协议 NETLINK_ROUTE(0)、NETLINK_NETFILTER(12) 等 rtnetlink、nfnetlink netlink_kernel_create() + cfg.input
Generic Netlink NETLINK_GENERIC(16) nl80211、tipc、ovs genl_register_family()

固定协议号有限;新子系统普遍走 genetlink,在 NETLINK_GENERIC 上再分 family id + cmd


3. 核心数据结构

struct sock 之上扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct netlink_sock {
struct sock sk; /* 必须是第一个成员 */
unsigned long flags; /* NETLINK_F_* */
u32 portid; /* 本 socket 端口(类 PID) */
u32 dst_portid; /* connect 后的默认目标 */
u32 dst_group; /* connect 后的默认组播组 */
u32 subscriptions;
u32 ngroups;
unsigned long *groups; /* 订阅的组播位图 */
void (*netlink_rcv)(struct sk_buff *skb); /* 内核 socket 收包回调 */
int (*netlink_bind)(struct net *, int group);
struct netlink_callback cb; /* dump 状态 */
bool cb_running;
/* ... */
};

用户态 socketnetlink_rcv == NULL,消息入 sk_receive_queue,由 recvmsg 读出。
内核 socketnetlink_rcv 指向如 rtnetlink_rcvgenl_rcv,在 netlink_unicast 中同步调用。

全局表,每个 protocol 号一项

字段 作用
hash rhashtable,按 (netns, portid) 查找 socket
mc_list 已 bind 组播的 socket 链表
listeners 内核侧组播监听者位图
registered 该协议是否已由内核模块注册
module / cb_mutex / bind / unbind 模块引用与 per-protocol 锁

查找用 RCU;插入/删除用 nl_table_lock + per-bucket 锁。

3.3 消息格式:nlmsghdr + 载荷

1
2
3
4
5
6
7
struct nlmsghdr {
__u32 nlmsg_len; /* 含头部的总长度 */
__u16 nlmsg_type; /* 消息类型 / genl family id */
__u16 nlmsg_flags; /* NLM_F_REQUEST, NLM_F_MULTI, NLM_F_ACK ... */
__u32 nlmsg_seq;
__u32 nlmsg_pid; /* 发送方 portid */
};

skb 的 NETLINK_CB(skb)struct netlink_skb_parms)携带路由元数据:portiddst_groupcreds 等。

Generic Netlinknlmsghdr 后还有 genlmsghdr(cmd、version),属性区用 NLAstruct nlattr)。


4. 初始化与挂接

af_netlink.c 启动时:

  1. proto_register(&netlink_proto)
  2. nl_table = kcalloc(MAX_LINKS, ...),每表项初始化 rhashtable
  3. netlink_add_usersock_entry() — 预注册 NETLINK_USERSOCK
  4. sock_register(&netlink_family_ops) — 挂到 socket.cnet_families[PF_NETLINK]
  5. register_pernet_subsys — 每 netns 的 /proc/net/netlink
  6. rtnetlink_init() — 在 net/core/rtnetlink.c 注册 NETLINK_ROUTE

4.2 用户态创建 socket

1
2
3
4
socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)
→ socket.c __sock_create()
→ netlink_create() # 检查 nl_table[protocol].registered
→ __netlink_create() # sk_alloc(netlink_sock)、设置 netlink_ops

netlink_create() 若协议未注册,可 request_module("net-pf-16-proto-N") 加载对应模块。

4.3 内核创建监听 socket

1
2
3
4
5
6
7
8
struct netlink_kernel_cfg cfg = {
.groups = RTNLGRP_MAX,
.input = rtnetlink_rcv, /* 收包回调 */
.cb_mutex = &rtnl_mutex,
.flags = NL_CFG_F_NONROOT_RECV,
.bind = rtnetlink_bind,
};
sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg);

__netlink_kernel_create() 会:创建内核 socket、设置 NETLINK_F_KERNEL_SOCKETnetlink_insert(sk, 0)、填充 nl_table[unit]


5. 用户态 → 内核(发送路径)

  1. msg_namestruct sockaddr_nl)或 connect() 缓存取 dst_portiddst_group
  2. 未 bind → netlink_autobind() 分配 portid 并插入 hash
  3. netlink_alloc_large_skb() 分配 skb,用户数据 memcpy_from_msg
  4. security_netlink_send() LSM 检查
  5. dst_groupnetlink_broadcast();否则 netlink_unicast()
1
2
3
4
netlink_getsockbyportid(ssk, portid)
├─ 目标为内核 socket → netlink_unicast_kernel()
│ └─ nlk->netlink_rcv(skb) # 如 rtnetlink_rcv / genl_rcv
└─ 目标为用户 socket → netlink_sendskb() # 入接收队列

内核 handler 普遍通过此函数处理 一个 skb 内多条消息

1
2
3
4
5
6
7
8
9
10
11
while (skb->len >= nlmsg_total_size(0)) {
nlh = nlmsg_hdr(skb);
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
goto ack; /* 非请求跳过处理 */
if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
goto ack; /* 控制消息 */
err = cb(skb, nlh, &extack); /* 子系统回调 */
if (nlh->nlmsg_flags & NLM_F_ACK || err)
netlink_ack(skb, nlh, err, &extack);
skb_pull(skb, NLMSG_ALIGN(nlh->nlmsg_len));
}

仅带 NLM_F_REQUEST 的消息由内核处理;需要确认时发 netlink_ack()(含扩展 ACK TLV)。


6. 内核 → 用户态(接收/通知)

API 用途
netlink_unicast(ssk, skb, portid, nonblock) 单播到指定 portid
netlink_broadcast(ssk, skb, portid, group, gfp) 组播到订阅 group 的 socket
nlmsg_notify(sk, skb, portid, group, report, flags) 组播 + 可选单播回执

netlink_broadcast() 遍历 nl_table[protocol].mc_list,对 nlk->groups 中对应 bit 已置位的 socket 调用 netlink_broadcast_deliver()

用户态 netlink_recvmsg()

  • skb_recv_datagram() 取 skb
  • 拷贝数据到用户缓冲区
  • 填充 sockaddr_nl(来源 portid、组)
  • cb_running 且接收缓冲有空 → 触发 netlink_dump() 继续 dump

7. Dump 机制(大数据量查询)

ip linkRTM_GETLINK 等不会一次返回全部条目:

netlink_dump内核 handler用户态 recvmsgnetlink_dump内核 handler用户态 recvmsgcb_running = truesendmsg(RTM_GETLINK + NLM_F_DUMP)__netlink_dump_start(cb)recvmsg (缓冲有空)cb->dump(skb, cb) 填充多条消息skb (NLM_F_MULTI)recvmsg ...NLMSG_DONE

要点:

  • __netlink_dump_start() 设置 nlk->cbcb->dump 回调
  • 每次 recvmsg 可能触发 netlink_dump(),按用户 max_recvmsg_len 分配 skb
  • 结束发 NLMSG_DONEnetlink_dump_done()
  • dump 期间持有 per-protocol cb_mutex(如 rtnl_mutex

8.1 动机

  • 固定 NETLINK_* 协议号不够用;
  • 需要统一的 family / cmd / attribute 模型与动态注册。

8.2 初始化

1
2
3
4
5
6
// genl_pernet_init
net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg);
// cfg.input = genl_rcv

// genl_init
genl_register_family(&genl_ctrl); /* 控制器 family */

8.3 收包分发

1
2
3
4
5
6
genl_rcv(skb)
→ netlink_rcv_skb(skb, genl_rcv_msg)
→ family = genl_family_find_byid(nlh->nlmsg_type)
→ genl_family_rcv_msg()
├─ op.dumpit → genl_family_rcv_msg_dumpit
└─ op.doit → genl_family_rcv_msg_doit

8.4 子系统注册

1
2
3
4
5
6
7
8
static struct genl_family nl80211_fam = {
.name = NL80211_GENL_NAME,
.ops = nl80211_ops,
.n_ops = ...,
.mcgrps = nl80211_mcgrps,
/* ... */
};
genl_register_family(&nl80211_fam);

genl_register_family():校验 ops → idr_alloc 分配 family id → 分配组播组 → 向 genl_ctrlCTRL_CMD_NEWFAMILY 事件。

控制器查询:用户态 GENL_ID_CTRL + CTRL_CMD_GETFAMILY 可发现已注册 family 与 ops。


实现于 net/core/rtnetlink.c(非 net/netlink/ 目录,但建立在 netlink 框架上):

消息 工具对应 作用
RTM_NEWLINK / RTM_DELLINK ip link 接口增删改
RTM_NEWADDR / RTM_DELADDR ip addr 地址
RTM_NEWROUTE / RTM_DELROUTE ip route 路由
RTM_NEWNEIGH ip neigh 邻居

注册(每 network namespace):

1
2
sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg);
net->rtnl = sk;

rtnetlink_rcvnetlink_rcv_skb → 各 rtnl_* 处理函数;变更通过 RTMGRP_* 组播 通知监听者。


文件 作用
policy.c netlink_policy_dump_*:将内核 nla_policy 导出给用户态查询
diag.c CONFIG_NETLINK_DIAG:通过 sock_diag 导出 netlink socket 状态
af_netlink.c /proc/net/netlink、BPF iter、netlink tap、notifier

10.1 常见 protocol 号(节选)

常量 模块/用途
NETLINK_ROUTE 0 rtnetlink
NETLINK_USERSOCK 2 用户自定义
NETLINK_SOCK_DIAG 4 socket 诊断
NETLINK_NETFILTER 12 nfnetlink
NETLINK_GENERIC 16 genetlink
NETLINK_KOBJECT_UEVENT 15 udev 热插拔

完整列表见 include/uapi/linux/netlink.h


11. 与 socket.c 的分工

层次 文件 职责
系统调用 net/socket.c socketbindsendmsgrecvmsgsock_register 分发表
Netlink 协议 net/netlink/af_netlink.c netlink_ops、portid、组播、内核 socket、dump、ACK
业务语义 rtnetlink.cnl80211.cnfnetlink.c 具体消息类型与属性解析

netlink_ops 注册的操作(节选):

1
2
3
4
.sendmsg = netlink_sendmsg,
.recvmsg = netlink_recvmsg,
.bind = netlink_bind,
.connect = netlink_connect,

12. RK3588 使用场景

Netlink 为上游通用实现,无 Rockchip 专属补丁net/netlink/。RK3588 板上典型用法:

场景 协议 用户态工具
以太网 UP/DOWN、IP NETLINK_ROUTE ip link / ip addr
路由 NETLINK_ROUTE ip route
WiFi 扫描/连接 NETLINK_GENERIC + nl80211 iwwpa_supplicant
防火墙 NETLINK_NETFILTER nft
设备热插拔 NETLINK_KOBJECT_UEVENT udev
接口统计/诊断 NETLINK_SOCK_DIAG ss -x

调试 netlink 可用:strace -e sendmsg,recvmsg ip link shownlmon(抓 netlink 包)、/proc/net/netlink


13. 源码索引

内容 路径
socket 族注册 net/netlink/af_netlink.cnetlink_proto_initnetlink_ops
内核 socket 创建 __netlink_kernel_create
单播/组播 netlink_unicastnetlink_broadcast
消息解析 netlink_rcv_skbnetlink_ack
dump netlink_dump__netlink_dump_start
Generic Netlink net/netlink/genetlink.c
rtnetlink net/core/rtnetlink.c
UAPI include/uapi/linux/netlink.hrtnetlink.hgenetlink.h

14. 相关文档


15. 小结

问题 答案
Netlink 是什么? 内核与用户态的 二进制配置/事件总线PF_NETLINK
核心实现在哪? net/netlink/af_netlink.c + genetlink.c
用户发消息怎么走? sendmsgnetlink_unicast → 内核 netlink_rcv 或用户队列
和 rtnetlink 关系? rtnetlink 是 NETLINK_ROUTE 上的 业务协议
和 genetlink 关系? genetlink 是 NETLINK_GENERIC 上的 可扩展 family 框架
与 NAPI 关系? 无直接关系;netlink 管 控制面,NAPI 管 收包数据面