
简介kernel-aodv_v2.2.2 是 AODV 按需距离矢量路由协议在 Linux 内核中的实现版本面向研究无线自组织网络、需要动手部署与调试路由协议的开发者与高校师生。资源包共 48 个文件约 53KB以 20 个 c 源文件与 21 个 h 头文件为主体覆盖路由发现、路由维护、邻居探测等核心模块另含 Makefile、启动脚本、gateway 配置及 README、CHANGE_LOG 等说明文档便于编译加载与二次开发。已有 195 人学习。通过该实现可深入理解 RREQ/RREP 交互、路由表管理与 RERR 撤销机制并借助 tcpdump、netstat、dmesg 等工具完成抓包分析与内核日志排错是掌握无基础设施网络路由原理的实用参考。1. kernel-aodv_v2.2.2 到底解决了什么从内核态 AODV 的编译翻车说起如果你在 Linux 内核模块里折腾过 AODV 路由协议大概率见过kernel-aodv_v2.2.2这个包名。它不是一个用户态守护进程而是把 AODV 的报文处理、路由表维护直接塞进内核网络栈的补丁式实现。我第一次拿到它时以为解压、make、insmod 三步就能跑结果在 5.4 内核上直接编译报错struct net_device的成员对不上proc_create的签名也变了。这个版本号 v2.2.2 对应的是一套面向旧内核常见 2.6.x 到 3.x的代码基线直接拿到新内核上编译翻车是常态。它适合谁适合需要做无线自组网、应急通信、传感器网络路由验证的工程师尤其是那些不想在用户态用olsrd或aodv-uu做转发、希望路由决策走内核快速路径的场景。这一章不急着贴代码先把“它是什么、为什么难搞、值不值得搞”说清楚后面再一步步拆编译、加载、调参和排错。2. 内核态 AODV 的编译环境与源码结构先让 v2.2.2 能过编译2.1 为什么 kernel-aodv_v2.2.2 不能直接 makekernel-aodv_v2.2.2的源码树通常包含aodv/、include/、Makefile和若干.patch文件。它的 Makefile 写死了KERNELDIR ? /lib/modules/$(shell uname -r)/build但代码里大量使用了旧内核的 API。比如init_timer在 4.15 之后被移除del_timer_sync的返回值处理也变了proc_create在 3.10 之后要求传入struct proc_dir_entry *parentskb_trim和pskb_trim的语义在 4.x 有调整。直接make的报错往往从第一个.c文件开始几十个 error 滚屏。我的做法是先把内核版本降下来或者用容器/虚拟机跑一个 3.10 或 3.16 的内核这是最省血泪经验的路径。如果必须上 5.x那就得逐文件改 API工作量不小。2.2 源码目录里哪些文件必须改先看目录结构常见布局如下kernel-aodv_v2.2.2/ ├── Makefile ├── aodv/ │ ├── aodv.c │ ├── aodv_dev.c │ ├── aodv_route.c │ ├── aodv_timer.c │ └── aodv_socket.c ├── include/ │ └── aodv.h └── patches/ └── kernel-2.6.32.patchaodv.c是模块入口aodv_dev.c处理网络设备事件aodv_route.c维护路由表aodv_timer.c管定时器aodv_socket.c负责内核 socket 收发。编译前先确认include/aodv.h里的AODV_VERSION是不是2.2.2有些包会混版本。然后检查Makefile里的obj-m是否指向aodv.o以及ccflags-y有没有加-I$(src)/include。如果缺这个 include 路径编译时找不到aodv.h报错会误导你去改代码。2.3 在 3.10 内核上跑通的最小命令序列假设你已经有一台 3.10 内核的机器或者用virtme起了对应内核的轻量环境操作如下# 解压源码包 tar -xvf kernel-aodv_v2.2.2.tar.gz cd kernel-aodv_v2.2.2 # 确认内核头文件路径存在 ls /lib/modules/$(uname -r)/build # 清理旧编译产物 make clean # 编译模块指定内核源码目录 make KERNELDIR/lib/modules/$(uname -r)/build # 查看生成的 .ko ls -l aodv/aodv.ko逻辑说明make clean不是可有可无旧包里的.o文件可能来自不同内核不清理会链接出错。KERNELDIR必须指向当前运行内核的 build 目录不能指向/usr/src/linux-headers-*里不匹配的版本。参数说明如果你的内核是 3.16KERNELDIR同样指向/lib/modules/3.16.0-*/build如果编译报No such file or directory先apt install linux-headers-$(uname -r)或对应发行版的 kernel-devel 包。2.4 加载模块前必须确认的三个参数编译出aodv.ko后不要急着insmod。先看模块参数modinfo aodv/aodv.ko常见参数有debug_level、hello_interval、route_timeout。debug_level默认可能是 0调成 3 能看到详细报文日志hello_interval单位是毫秒默认 1000在节点密集场景要调大避免广播风暴route_timeout默认 3000 毫秒移动快时调小静态拓扑调大。加载命令sudo insmod aodv/aodv.ko debug_level3 hello_interval2000 route_timeout5000加载后用dmesg | tail -20看内核日志如果出现aodv: module loaded且没有Unknown symbol说明模块入口跑通了。如果报Unknown symbol in module通常是内核版本不匹配或依赖模块没加载先modprobe相关依赖再试。3. 把 AODV 挂到无线接口上配置、验证与第一个路由表3.1 接口绑定与 proc 文件系统交互模块加载后AODV 不会自动接管所有网卡。常见做法是通过 proc 接口指定设备名# 查看 AODV 是否创建了 proc 入口 ls /proc/net/aodv # 将 wlan0 加入 AODV 管理 echo add wlan0 /proc/net/aodv/dev # 确认接口状态 cat /proc/net/aodv/dev逻辑说明/proc/net/aodv/dev是 v2.2.2 里常见的控制入口写入add ifname后模块会在该接口上开启 AODV 报文监听。参数说明如果ls /proc/net/aodv不存在说明模块没加载成功或 proc 创建失败回到dmesg看错误。有些包用的是ioctl而不是 proc那就需要写一个小工具调用SIOCAODVADD但 v2.2.2 多数还是 proc 风格。3.2 用 ping 触发路由发现并观察路由表绑定接口后先确认无线接口本身在 ad-hoc 模式且 IP 配好sudo ip link set wlan0 down sudo iwconfig wlan0 mode ad-hoc essid test-mesh sudo ip link set wlan0 up sudo ip addr add 10.0.0.1/24 dev wlan0然后在另一台节点上配10.0.0.2/24从第一台 ping 第二台ping -c 3 10.0.0.2ping 的同时查看 AODV 路由表cat /proc/net/aodv/route如果路由表里出现10.0.0.2且NextHop是wlan0的 MAC 或对应接口说明 RREQ/RREP 交互成功。如果表是空的先看dmesg有没有RREQ received或RREP sent。常见问题是 ad-hoc 模式没生效iwconfig显示Mode:Managed那 AODV 报文根本发不出去。3.3 三个必调参数hello_interval、route_timeout、net_diameterhello_interval控制 HELLO 报文周期。默认 1000ms 在 10 个节点以内没问题超过 20 个节点建议 2000ms 到 3000ms否则信道竞争严重。route_timeout是路由条目过期时间默认 3000ms 对低速移动合适高速移动比如车载要降到 1500ms静态节点可以升到 10000ms 减少重建。net_diameter是网络直径影响 RREQ 的 TTL 初始值默认 30 跳小网络改成 5 到 10 能减少无效广播。修改方式echo 2000 /proc/net/aodv/hello_interval echo 5000 /proc/net/aodv/route_timeout echo 10 /proc/net/aodv/net_diameter参数说明这些值不是越大越好。hello_interval太大链路断裂发现慢太小广播风暴。route_timeout太大失效路由被继续使用丢包太小路由频繁重建开销高。建议先用默认值跑通再根据dmesg里的route expired和RREQ retry计数调整。3.4 验证路由是否真的走了内核快速路径用户态 AODV 的转发要经过 socket 拷贝内核态 AODV 直接在netif_receive_skb附近处理。验证方法在中间节点上抓包看 UDP 数据包的 IP TTL 是否递减以及是否没有经过用户态进程。更直接的是cat /proc/net/aodv/stats看forwarded_packets计数是否增长。如果计数不增长但 ping 通了可能走的是普通 IP 转发而不是 AODV 路由检查ip route有没有冲突的静态路由。4. 避坑与排查kernel-aodv_v2.2.2 最常见的五类翻车4.1 编译报错implicit declaration of function init_timer现象make时大量error: implicit declaration of function init_timer以及struct timer_list没有function成员。原因内核 4.15 之后init_timer被移除改用timer_setup。解决要么降内核到 4.14 以下要么手动改aodv_timer.c把init_timer(t); t.function fn; t.data data;改成timer_setup(t, fn, 0);并把回调签名改成void fn(struct timer_list *t)。改完还要处理t.data的获取方式用from_timer宏。4.2 加载模块报Unknown symbol in module现象insmod失败dmesg显示aodv: Unknown symbol crc_ccitt或类似。原因依赖的 CRC 模块没加载或者内核配置没开CONFIG_CRC_CCITT。解决先modprobe crc_ccitt如果找不到模块说明内核编译时没选这个选项需要重新配置内核或换一个带该选项的内核。另一个常见符号是proc_create如果内核版本太老没有这个函数得改回create_proc_entry。4.3 路由表一直为空ping 不通现象模块加载成功接口也 add 了但/proc/net/aodv/route始终为空ping 目标超时。原因ad-hoc 模式没生效或者两台节点的 ESSID 不一致或者 AODV 的 RREQ 被防火墙丢弃。解决iwconfig确认Mode:Ad-Hoc和ESSID一致iptables -L看有没有 DROP 规则tcpdump -i wlan0 -n udp port 654看 AODV 报文AODV 常用 UDP 654有没有发出和收到。如果只有发出没有收到检查信道是否相同。4.4 路由震荡dmesg频繁打印route expired和new route现象路由表条目反复出现又消失ping 时通时断。原因hello_interval和route_timeout比例失调或者无线链路本身不稳定。解决把hello_interval调到route_timeout的 1/3 到 1/2比如hello_interval2000、route_timeout6000。同时用iwconfig wlan0 rate 5.5M固定速率避免速率自适应导致链路抖动。如果还是震荡检查是否有两个节点同时声称到同一目标的路由AODV 的序列号机制可能被旧条目干扰清空路由表echo clear /proc/net/aodv/route再试。4.5 卸载模块时内核 oops现象rmmod aodv时内核报 oops或者模块引用计数不为零无法卸载。原因定时器没删干净或者 proc 条目没移除或者 skb 队列还有未释放的包。解决卸载前先echo del wlan0 /proc/net/aodv/dev然后rmmod aodv。如果还报错检查aodv_timer.c里的del_timer_sync是否在所有路径都调用了。旧代码有时在模块退出函数里漏掉remove_proc_entry手动补上。生产环境不要频繁rmmod加载后稳定运行即可。5. 进阶把 v2.2.2 改造成可观测、可调优的测试平台5.1 用 tracepoint 替代 printk 做低开销观测v2.2.2 默认用printk打日志debug_level3时每包都打在高速链路上直接拖垮系统。我的习惯是保留printk做粗粒度同时加一个tracepoint。在include/aodv.h里定义TRACE_EVENT(aodv_rreq, ...)在aodv_socket.c的 RREQ 处理分支里调用trace_aodv_rreq(...)。然后用户态用trace-cmd record -e aodv:*抓取开销比printk低一个数量级。这个改动需要内核支持 tracepoint3.10 以上都行。改完后debug_level可以降到 1只保留错误日志。5.2 参数调优的量化方法用 iperf 和路由收敛时间做指标不要凭感觉调hello_interval。搭一个 3 节点线性拓扑A 到 C 经过 B。在 A 上跑iperf -c C -u -b 1M -t 60同时用脚本每 100ms 读一次/proc/net/aodv/route记录路由是否存在。统计路由中断次数和平均恢复时间。然后改hello_interval从 1000 到 3000重复测试。我的经验是节点数少于 5 时1000ms 的收敛最快节点数 10 到 20 时2000ms 的综合吞吐最高超过 20 节点3000ms 加net_diameter5能减少广播碰撞。这些数字随无线环境变化但方法可复现。5.3 一个具体技巧用 netlink 替代 proc 做配置下发proc 接口在并发写入时会丢配置而且没有确认机制。进阶做法是加一个 netlink 家族在aodv.c的初始化里netlink_kernel_create定义AODV_CMD_SET_PARAM和AODV_CMD_GET_ROUTE。用户态用libnl或直接socket(AF_NETLINK, SOCK_RAW, NETLINK_AODV)发送。这样配置有 ACK路由查询可以批量返回适合自动化测试。改造成本大约 200 行代码但后续做参数扫描时省很多事。我一般会先保留 proc 做兼容netlink 作为主通道。5.4 验证改造是否成功的三个检查点第一trace-cmd report里能看到 RREQ、RREP、RERR 事件且时间戳间隔合理。第二iperf在参数调优后路由中断次数下降 50% 以上。第三rmmod时没有 oopsdmesg干净。如果这三点都过说明 v2.2.2 已经从一个“能跑就行”的旧包变成了可观测、可调优的测试平台。我自己的习惯是每次改完内核模块先跑 30 分钟稳定性测试再上真实场景。希望帮到你。本文还有配套的精品资源点击获取