之前帖子提到可以借用插件调起流程, 实现用户级别启动脚本的持久化.
帖子本身和后面的回复提到两种替换方式, 一个是借用 gamespeederv3 插件, 另一个是借用 opmaintainv3 插件的 ommonitord 检测工具. 但是当我们需要优化插件, 甚至停用前面提到的电信插件时, 也希望保持启动功能不被影响.
于是重头梳理了一下目前测试光猫(中兴, 电信系统)的用户阶段启动流程.
根据这个流程我们可以仅利用电信自带的 saf lxc 管理模块和固件自带的 openwrt 实现灵活的启动方式, 同时按需启动所需自带插件.
用户空间启动流程梳理
主要分析测试光猫, 还是中兴设备, 电信的系统, 只要使用 saf 管理模块的应该大同小异. 需要提前 telnet 拿到 shell.
- 物理设备固件/kernel启动
- 启动 init (busybox), pid=1 进程
- init 运行 /etc/inittab 里面的初始化行, 按照电信的传统, 指向 /etc/init.d/rcS
- /etc/init.d/rcS 会调用 /etc/rc.d/S* 脚本, 主要是启动设备, 安装驱动, kernel mod 等, (比较老的电信天翼设备是都写在 rcS 中的)
- rcS 最后调用了 /sbin/pc 程序 (网上有一些分析是启动了 lxc 脚本, 但是我这里的系统, 已经不再使用脚本, 而是一个独立程序)
- pc 程序应该 listen 了 socket, 帮忙启动后台程序, 同时本身也启动了大量 daemon, 如 telnet, http, cspd, dbus 等
- cspd 一方面负责解析 user.xml, 响应sendcmd 命令等, 同时 cspd 也负责启动 saf 系统, 即电信改造的 lxc 管理模块
- cspd 向 pc 请求执行 saf A B C, 即指定主从两个 rootfs分区和一个插件分区, rootfs 内是电信改造过的 openwrt, 可以适配 saf 模块
- openwrt 启动容器内 1 号进程 procd, 后面是标准的 opewrt 启动流程
- procd 调用 rcS, 按顺序启动/etc/rc.d/ 下注册的服务启动脚本, 其中包括 appmgr, cloudclient, virtual**client 等电信组件, 其中 appmgr 管理了光猫页面上显示的插件
- appmgr 按照配置配置 /etc/config/appmgr 启动插件, 每个插件是一个 rootless lxc in lxc, 如前文提到的gamespeederv3, 此时可以通过 telnet 访问物理系统
- opmaintainv3 插件用来检测 wifi 状态和其他物理资源状态, 通过 saf 框架直接在 host 系统直接启动了ommonitord 常驻程序, 通过ommonitord 实现对物理系统的检测
关闭插件后的启动脚本
本帖隐藏的内容
如果启动执行的功能可以直接在第一层 openwrt 容器实现, 可以参考 openwrt 的 procd 文档写一个服务配置放在 /etc/init.d 下在 enable 注册启动项. 简单的命令也可以写入 /etc/rc.local 在 boot 阶段执行一次.
然而很多情况, 还是直接在 host os 操作网络设备更方便. 正常情况下, 我们只能对 openwrt 环境的启动脚本可以写入, 然后容器内无法直接回到 host 环境执行程序.
考虑到 telnet 这种兜底方式脚本难以维护, 我们需要尝试模拟 ommonitord 启动流程. 在仔细研究 saf 框架和 opmaintainv3 插件后, 基本确认了调起流程如下
- saf 实现了一组专用的 gdbus 接口, 启动 openwrt 是传入 dbus 的 socket 这样就可以接受请求
- 其中 saf 的一个请求会接受一个服务名字 XXX, 用这个名字在 hardcode 路径找执行文件, 依次找 /opt/upt/apps/apps/opt/apps/opmaintain/diagapps/XXX 和 /opt/upt/framework/saf/rootfs/opt/apps/opmaintain/diagapps/XXX
- saf 会启动第一个找到的可执行路径.
- saf 启动 wrt 时, mountain /opt/upt/apps/apps/opt -> /opt, opmaintainv3 等插件会把需要 host 环境执行的程序放到 /opt/apps/opmaintain/diagapps/ 下, 目前这个下面有很多插件放进去的工具
- opmaintainv3 在启动 resource_and_wifi_process_monitor 函数时, 通过 saf 的 gdbus 服务调用diagapps/ommonitord, 设置启动模式为后台服务.
- 容器内 opmaintainv3 与 host ommonitord 通过 dbus 或者 mount dir 交互信息
利用这个过程, 先把需要 host 环境启动脚本放在 /opt/upt/apps/apps/opt/apps/opmaintain/diagapps/boot-hook 里面
- #!/bin/sh
- exec >”${0}.log” 2>&1
- ip r a …
- # any codes you like
复制代码
注意 diagapps 服务无法传参, 同时一定要增加可执行状态 chmod +x boot-hook. 启动过程有问题可以看日志文件 /opt/upt/apps/apps/opt/apps/opmaintain/diagapps/boot-hook.log
接下来在 openwrt 启动过程触发上面代码, 最简单的方式时放在 rc.local 里面, 修改 host 环境路径 /opt/upt/apps/apps/etc/rc.local 在 exit 0 之前添加代码
- gdbus call -y -d com.ctc.saf1 -o /com/ctc/saf1 -m com.ctc.saf1.framework.DiagService boot-hook 1
复制代码
-y, -o, -m 都是接口固定参数, 倒数第二个与前面启动脚本的 boot-hook 名字相同, 最后一个 1 表示同步执行.
至此, 可以重启测试效果了.插件管理
第一种 openwrt 原生插件, 如 appmgr, cloudclient 等, 利用 openwrt 原生的 uci 可以打开关闭插件.
appmgr 管理的插件, 这种虽然可以用 opkg 看到有单独的包对应, 但是每次启动 appmgr 会自动安装被删除的包.
appmgr 和电信每个插件都会实现一组 dbus 接口, 这样我们可以用appmgr dbus 接口运行和停止插件, 页面上会显示 RUNNING/STOPPED 状态, 同时大部分情况下重启后依然生效.
- 列出插件: gdbus call -y -d com.ctc.appframework1 -o /com/ctc/appframework1 -m com.ctc.appframework1.AppAgent.List
- 查询一个插件状态 gdbus call -y -d com.ctc.appframework1 -o /com/ctc/appframework1 -m com.ctc.appframework1.AppAgent.GetStatus [插件名字]
- 停止插件: gdbus call -y -d com.ctc.appframework1 -o /com/ctc/appframework1 -m com.ctc.appframework1.AppAgent.Stop [插件名字]
- 启动插件: gdbus call -y -d com.ctc.appframework1 -o /com/ctc/appframework1 -m com.ctc.appframework1.AppAgent.Run [插件名字]
常见插件作用
测试了一部分插件停用效果, 结合论坛其他人的说明做了一些整理, 有一些还需要关闭后长时间看看效果.
- inter_conndv3: 可能时信息交换用, appmgr 本身依赖这个插件获取信息, 无法关闭, stop 后, 下次重启会被 appmgr 拉起
- gamespeederv3: 游戏加速, 可能和 virtual**client 有一些交互
- b01odmv3: 电信天翼app 可以从里面获取信息, 非电信用户应该可以关掉
- extccv3: 应该与 app 中远程配置路由器有关
- opmaintainv3: 获取设备资源和网络设备状态
- xrobotv3: 好像是数据收集的
- redictv3: 重定向功能, 会创建两张 iptables chain: ct_redict_dnat, ct_redict_reject, 还不太清楚具体添加什么规则
- u01v3: xrobotv3 依赖这个插件, 不清楚具体作用
- appmgr: openwrt 原生服务, 前面插件的管理器
- cloudclient: openwrt 原生服务, 可能是电信 app 主要功能入口, 与 web 状态页面里面一些远程管理信息有关
- virtual**client: openwrt 原生服务, 可能和gamespeederv3 有关, 不清楚其他作用