初探OpenWrt

2015.11.07/2015.11.13发布于研究暂无评论/目录

小米路由器mini上刷完PandoraBox后,稍微了解了下OpenWrt系统,记录一下以备忘。

OpenWrt是一个专门为嵌入式设备定制的Linux发行版,目前的稳定版是Chaos Calmer 15.05,比中文版的PandoraBox要新两个版本。

以下内容基本上是阅读OpenWrt Wiki和查阅网上资料后总结而来,不见得完全正确,欢迎指正。

包管理器opkg

OpenWrt自带包管理器opkg,可以安装各种扩展为ipk的二进制软件包,类似Debian的apt-get和CentOS的yum。

opkg常用操作:

# 更新本地软件列表
opkg update

# 可以直接安装本地包
opkg install <pkg>
opkg remove <pkg>

# 列出已安装的包
opkg list-installed

# 列出包里的文件
opkg files <pkg>

# 查找包含文件的包,path必须是绝对路径
opkg search <path>

# 查找软件包
opkg find <regex>

opkg的配置文件位于/etc/opkg.conf,例如:

src/gz base http://downloads.openwrt.org/barrier_breaker/14.07/ramips/mt7620a/packages/base/
src/gz luci http://downloads.openwrt.org/barrier_breaker/14.07/ramips/mt7620a/packages/luci/
src/gz packages http://downloads.openwrt.org/barrier_breaker/14.07/ramips/mt7620a/packages/packages/
dest root /
dest ram /tmp
lists_dir ext /var/opkg-lists
option overlay_root /overlay
arch all 100
arch mt7620a 200

其中:

  • src/gz: 指定软件源的地址,可以有多个。OpenWrt的官方源可以在OpenWrt Downloads找到,选择源的时候注意使用合适的Build Target和Subtarget。小米路由器mini应该选用ramips/mt7620(a)。[1] 软件源也可以是file:///path/to/pkgs/dir协议的本地目录。
  • dest: 指定安装位置,默认装在根目录下,可通过opkg的-d选项来选择其他配置里的目录。
  • lists_dir: 指定软件列表的位置。
  • overlay_root: 当使用overlayfs时,指定overlay分区的位置,以检查是否还有可用空间,仅当dest为root时有用。
  • arch: opkg默认只支持架构无关(all)和已安装target架构的软件包,但也可以使用本命令引入其他target的包,最后的数字是安装优先级,越小优先级越高。

flash分区布局

详细内容可参考The OpenWrt Flash Layout。下面以新安装的PandoraBox为例,简要介绍其分区布局。

小米路由器mini自带128M内存和16M flash,OpenWrt将flash设备抽象为MTD。以新安装的PandoraBox为例:

cat /proc/mtd

dev:    size        erasesize   name
mtd0:   00030000    00010000    "u-boot"
mtd1:   00010000    00010000    "u-boot-env"
mtd2:   00010000    00010000    "Factory"
mtd3:   01000000    00010000    "fullflash"
mtd4:   00f80000    00010000    "firmware"
mtd5:   001230fb    00010000    "kernel"
mtd6:   00e3cf05    00010000    "rootfs"
mtd7:   00860000    00010000    "rootfs_data"
mtd8:   00020000    00010000    "panic_oops"
mtd9:   00010000    00010000    "culiang-crash"
mtd10:  00010000    00010000    "culiang-reserved"
mtd11:  00010000    00010000    "culiang-Bdata"

整个flash设备被分成了12个区,通过dmesg | egrep '0x[a-z0-9]{12}'可以查看各个分区的始末地址,

0x000000000000-0x000001000000 : "fullflash"
0x000000000000-0x000000030000 : "u-boot"
0x000000030000-0x000000040000 : "u-boot-env"
0x000000040000-0x000000050000 : "Factory"
0x000000050000-0x000000fd0000 : "firmware"
0x000000050000-0x0000001730fb : "kernel"
0x0000001730fb-0x000000fb0000 : "rootfs"
0x000000750000-0x000000fb0000 : "rootfs_data"
0x000000fb0000-0x000000fd0000 : "panic_oops"
0x000000fd0000-0x000000fe0000 : "culiang-crash"
0x000000fe0000-0x000000ff0000 : "culiang-reserved"
0x000000ff0000-0x000001000000 : "culiang-Bdata"

整个flash的布局大致如下图所示:

|----------------------------------------------------------------------------------------------------------------------------|
|                                              mtd3: fullflash                                                               |
|----------------------------------------------------------------------------------------------------------------------------|
|mtd0: u-boot | mtd1: u-boot-env | mtd2: Factory |                        mtd4: firmware                      | mtd9 ~ mtd11 |
|----------------------------------------------------------------------------------------------------------------------------|
|                                                | mtd5: kernel |         mtd6: rootfs     | mtd8: panic_oops |              |
|                                                |------------------------------------------------------------|              |
|                                                               | /rom | mtd7: rootfs_data |                                 |
|----------------------------------------------------------------------------------------------------------------------------|

其中,各个分区的用处如下:

  • u-boot分区保存启动器代码。
  • u-boot-env分区保存操作系统的一些关键环境变量,以供下次启动使用,可以使用strings /dev/mtd1查看。这应该是刷机之前的那个Config分区。
  • Factory分区,保存了以太网卡的mac地址,另外据说还保存了无线AP的频率校准参数,很有必要备份一下。
  • kernel分区保存系统内核。
  • rootfs分区挂载根文件系统,起始的一部分是只读文件系统SquashFS,启动后挂载于/rom。
  • rootfs_data分区挂载JFFS2文件系统,挂载于/overlay。
  • panic_oops分区应该是mtdoops模块记录内核panic/oops信息的地方。
  • mtd9 ~ mtd11这三个culiang-开头的分区应该就是刷机之前的crash, reserved和Bdata分区,culiang(粗粮)是指小米来着。这里保存的应该是小米自己的配置和数据,culiang-Bdata也可以用strings /dev/mtd11查看,包含model,CountryCode和SN等。

overlayfs文件系统

还是以新安装的PandorasBox为例,介绍下文件系统,具体内容可参考OpenWrt Filesystems

df -h

Filesystem                Size      Used Available Use% Mounted on
rootfs                    8.4M    376.0K      8.0M   4% /
/dev/root                 6.0M      6.0M         0 100% /rom
tmpfs                    61.7M    248.0K     61.5M   0% /tmp
/dev/mtdblock7            8.4M    376.0K      8.0M   4% /overlay
overlayfs:/overlay        8.4M    376.0K      8.0M   4% /
tmpfs                   512.0K         0    512.0K   0% /dev
/dev/sda1               931.5G    780.0G    151.5G  84% /mnt/sda1

这里使用了一个比较特殊的文件系统overlayfs,它可以把一个只读文件系统SquashFS和可写文件系统JFFS2整合在一起,挂载于根目录下。SquashFS挂载于/rom目录,包含压缩过的初始根文件目录,JFFS2挂载于/overlay目录,如果两个目录内有同名的文件,那我们通过根目录实际访问和修改的都是/overlay下的文件,如果是同名的目录,那我们通过根目录访问的是两个目录合并在一起的结果。所有的修改和删除都发生在/overlay目录下,这样的好处比较明显,一是节约了很多flash空间,二是若一旦发生问题,可以很容易的恢复出厂设置(rm -rf /overlay/*)。

启动过程

以新安装的PandoraBox为例,简要介绍OpenWrt的启动过程

  1. 引导器启动
    1. 执行u-boot分区的引导器代码。
    2. 引导器解压缩位于kernel分区的内核并将其载入内存。
  2. 内核启动
    1. 从rootfs分区扫描SquashFS只读分区并挂载到根目录。
    2. 执行/sbin/init (通过/etc/preinit间接调用)
      1. 调用/sbin/kmodloader加载/etc/modules-boot.d目录下的内核模块。
      2. 调用/etc/preinit
        1. 挂载必要的文件系统(procfs, sysfs, tmpfs等)。
        2. 挂载并初始化devfs。
        3. 提供failsafe模式的进入点。
        4. 挂载rootfs_data分区(JFSS2可读写分区)到根目录(overlayfs),老的SquashFS挪到/rom目录。
        5. 调用/sbin/procd。
  3. procd启动
    1. 监控并加载热插拔设备(U盘,打印机等)。
    2. 连接ubus
    3. 读取/etc/inittab,并按字典序依次执行/etc/rc.d/目录下S开头的脚本。

OpenWrt已经用procd替换之前的init作为pid=1的母进程,网上关于procd的文档很少,要了解procd的话只能阅读源码

failsafe模式

当忘记路由器密码或配置有问题无法启动时,failsafe模式会非常有用。

以下内容尚无机会实测,仅供参考。

启动过程中,当可以进入failsafe模式的时候,OpenWrt会有两个动作,一是LED灯开始闪,二是向子网4919端口广播Please press button to enter failsafe消息。然后如果2秒钟内用户按了reset按钮,便可进入failsafe模式。

如果无法通过LED灯闪的情况判断按reset的时机,可以用tcpdump在本地的4919端口捕获Please press button to enter failsafe消息。首先关闭路由器,用网线连接PC和路由器,然后配置PC的以太网接口的ip地址到192.168.1.0网络内。

# 找到插网线的ethernet接口,一般是eth开头
ip link list
# 这里假设接口名称为eth0

# 清空之前的配置
ip addr flush dev eth0

# 配置ip地址和子网掩码
ip link set eth0 up
ip addr add 192.168.1.10/24 broadcast 192.168.1.255 dev eth0

# 检查能否连接路由器
ping 192.168.1.1

然后运行并启动路由器

tcpdump -Ani eth0 port 4919 and udp

当tcpdump输出Please press button to enter failsafe时,迅速捅一下路由器的reset按钮即可进入failsafe模式,此时tcpdump会输出Entering failsafe。

如果之前刷机用的是snapshot版本,用ssh 192.168.1.1登陆路由器,一般来说,用telnet 192.168.1.1即可。

在failsafe模式,系统只挂载了只读的SquashFS分区,我们需要手动mount JFFS2分区。

mount_root

然后便可为所欲为了。

# 重置root密码,完成后退出telnet用ssh重新登陆
passwd

# 恢复出厂设置
rm -r /overlay/*

# 最后重启路由器
reboot -f

记得把PC的ip地址改回去。

参考资料


  1. Xiaomi MiWiFi Mini, 2015-11-07.

#OpenWrt#PandoraBox

评论