3. Linux内核协议栈裁剪基础:内核配置系统(Kconfig/Makefile)、裁剪网络子系统、移除不必要的协议族
各位同学,今天咱们聊点实在的。内核协议栈裁剪,说白了就是给网络协议栈“瘦身”。我刚开始做嵌入式系统移植那会儿,总觉得内核越大越全越好,结果产品一跑起来,内存吃紧,延迟还高。后来才明白——你不需要的东西,就是负担。
这一节,我带你从内核的配置系统入手,一步步把网络子系统里那些用不上的东西砍掉。嗯,咱们的目标很明确:让协议栈跑得更快,占得更少。
3.1 内核配置系统:Kconfig与Makefile的默契配合
内核的裁剪,核心就是靠Kconfig和Makefile这两兄弟。Kconfig负责“问你要不要”,Makefile负责“你要就编译”。
Kconfig的语法其实不复杂。我举个例子,你一看就懂:
config NET_VENDOR_INTEL
bool "Intel devices"
default y
help
If you have a network (Ethernet) card belonging to this class, say Y.
这里bool表示开关选项,default y就是默认开启。我个人习惯,在裁剪时会把所有不用的vendor驱动都设成default n,省得编译时还得手动一个个关。
Makefile那边就更直接了:
obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
看到没?CONFIG_NET_VENDOR_INTEL如果被选为y,就编译intel目录下的驱动。如果是m,就编译成模块。如果是空的,那就跳过。
make menuconfig生成一个.config文件,然后备份。这样万一裁坏了,还能快速恢复。
3.2 裁剪网络子系统:从宏观到微观
网络子系统是内核里最庞大的模块之一。你想想看,从网卡驱动到协议栈,再到socket接口,层层叠叠。裁剪它,得有个顺序。
我个人习惯分三步走:
- 关掉不用的网卡驱动 —— 嵌入式设备通常只有一两种网卡,其他全砍掉。
- 关掉不用的网络功能 —— 比如桥接、VLAN、多播路由,用不上就关。
- 关掉不用的协议族 —— 这个咱们下一节细说。
具体操作时,你可以在make menuconfig里进入Networking support -> Networking options。这里面的选项密密麻麻,我挑几个常见的说说:
| 配置项 | 说明 | 裁剪建议 |
|---|---|---|
| CONFIG_PACKET | 原始套接字支持 | 如果不用tcpdump,可以关掉 |
| CONFIG_NETFILTER | 网络过滤框架 | 嵌入式设备通常不需要防火墙,关掉 |
| CONFIG_BRIDGE | 网桥支持 | 只有做交换机才需要 |
| CONFIG_IP_MULTICAST | IP多播 | 大部分场景用不上 |
我曾经在一个项目里,把CONFIG_NETFILTER关掉后,网络吞吐量提升了将近15%。为什么?因为数据包不再经过那些hook点了,路径短了,自然就快了。
CONFIG_PACKET,那libpcap就用不了了。我吃过这个亏,调试时抓不了包,急得满头大汗。
3.3 移除不必要的协议族
协议族,就是AF_INET、AF_INET6、AF_NETLINK这些。内核里支持的协议族很多,但你的设备可能只用其中一两个。
我见过有些嵌入式设备,明明只用IPv4,却把IPv6、DECnet、IPX这些全编译进去了。这不是浪费吗?
裁剪协议族,主要是在Networking support -> Networking options里操作。我列几个常见的:
- IPv6:如果设备只跑IPv4,直接关掉
CONFIG_IPV6。能省下不少内存和CPU开销。 - DECnet:这是老古董了,现在基本没人用。关掉。
- IPX:Novell时代的协议,关掉。
- NETLINK:这个要小心。很多内核工具(比如ip命令)依赖它。如果不用这些工具,可以关掉。
嗯,这里要注意:协议族的裁剪,影响的不只是内核大小,还有运行时的性能。因为每个协议族在初始化时都会注册自己的处理函数,增加协议栈的查找开销。
我举个例子。假设你的设备只跑IPv4,那你可以把CONFIG_INET保留,其他全关。这样内核在收到数据包时,只需要匹配IPv4的协议号,不用去遍历其他协议族的处理函数。路径短了,延迟自然就低了。
3.4 实战:用SVG画一张裁剪流程图
说了这么多,咱们用一张图来总结一下裁剪的流程。我画了个SVG,你一看就明白:
这张图把裁剪流程串起来了。你照着这个顺序做,基本不会出大问题。
3.5 避坑指南
最后,我分享几个实战中踩过的坑:
- 别一次裁太多 —— 我刚开始时,恨不得把所有不认识的选项全关掉。结果编译出来,网络根本起不来。后来学乖了,每次只关几个选项,然后编译测试。
- 注意依赖关系 —— 有些选项之间有依赖。比如你关了
CONFIG_INET,那所有依赖IPv4的功能都会失效。内核在make menuconfig里会提示,但有时候提示不明显,你得仔细看。 - 保留调试接口 —— 我建议至少保留
CONFIG_NET_SCHED和CONFIG_NET_CLS,方便后期做QoS调试。当然,如果产品已经稳定了,可以再关掉。
好了,这一节的内容就到这儿。裁剪协议栈是个细致活,急不得。你按照我上面说的步骤来,一步步裁,一步步测,很快就能上手。
记住:少即是多。你砍掉的每一行代码,都可能让协议栈跑得更快。