本文是系列最后一篇。SD-WAN终端通常部署在企业分支机构的现场,数量可能达到数百甚至数千台。当需要更新固件或业务软件时,逐台手动升级是不可行的。本文介绍基于MQTT协议的远程OTA(Over-The-Air)升级方案。

一、OTA升级的基本需求

SD-WAN终端的OTA升级需要满足以下要求:

  • 远程触发:通过云端平台下发升级指令,无需现场操作
  • 安全可靠:固件传输过程加密,升级失败可回退
  • 断点续传:网络不稳定时能从断点继续下载
  • 版本管理:能区分设备当前版本和目标版本
  • 选择性升级:可以指定升级固件类型(系统固件或业务软件)
  • 升级保留:升级后保留关键配置和数据

二、方案选型:为什么选择MQTT

远程升级需要一个可靠的通信通道,将升级指令和固件文件从云端传输到终端设备。常见的方案有:

方案 优点 缺点
HTTPS轮询 实现简单 延迟高,服务器压力大
WebSocket 双向通信 需要自建服务端
MQTT 低带宽、高可靠、支持遗嘱消息 需要MQTT Broker
自定义TCP协议 完全可控 开发成本高

选择MQTT的原因:

  1. 轻量级:MQTT协议头部最小仅2字节,适合带宽受限的嵌入式设备
  2. 可靠性:支持QoS消息质量等级,确保消息不丢失
  3. 连接状态感知:遗嘱消息(Will Message)可以在设备异常离线时通知服务器
  4. 成熟的云服务:阿里云、AWS等云平台都提供MQTT IoT服务,免去自建Broker的工作

本方案使用阿里云IoT平台作为MQTT Broker。

三、系统架构

┌──────────────┐     MQTT      ┌──────────────────┐
│  阿里云IoT    │◄────────────►│  OTA升级服务      │
│  平台         │               │  (管理后台)       │
│  (MQTT Broker)│               └──────────────────┘
└──────┬───────┘
       │ MQTT (TLS加密)
       ▼
┌──────────────┐
│  SD-WAN终端   │
│              │
│  remote-ota  │ ← OTA客户端程序
│  (C程序)     │
│              │
│  watchdog_daemon │ ← 进程守护
│  (监控)      │
└──────────────┘

升级服务:运行在云端,通过MQTT协议向终端下发升级指令。管理员在管理后台选择固件版本、目标设备范围,触发升级任务。

remote-ota:运行在终端设备上的OTA客户端程序,用C语言编写(通过阿里云C Link SDK)。负责与阿里云IoT平台通信、下载固件、校验和刷写。

watchdog_daemon:进程守护程序,监控remote-ota的运行状态,异常退出时自动重启。

四、OTA客户端的运行逻辑

4.1 完整流程

1. 设备启动 → watchdog_daemon启动 → remote-ota启动
    ↓
2. 动态注册(免预注册模式)
    设备向阿里云IoT平台发送注册请求
    平台返回设备证书(用于后续MQTT连接认证)
    ↓
3. 建立MQTT连接
    使用获取的证书发起TLS加密的MQTT连接
    ↓
4. 上报版本信息
    向平台上报当前固件版本号(如sdwan_1.0.0)
    ↓
5. 等待升级指令
    平台通过MQTT下发升级指令(包含固件下载URL和版本信息)
    ↓
6. 下载固件
    检查本地是否已有固件文件,有则删除
    从URL下载固件到临时目录(如/tmp/firmware.bin)
    ↓
7. 校验固件
    校验固件的完整性(MD5/CRC)
    校验失败 → 上报升级失败 → 删除文件 → 等待重试
    ↓
8. 执行升级
    调用sysupgrade命令刷写固件
    sysupgrade支持在升级时保留指定的文件和目录
    ↓
9. 设备重启
    新固件启动 → 上报新版本号 → 升级完成

4.2 版本号格式

采用语义化版本号,前缀标识产品:

sdwan_1.0.0    # sdwan = 固件标识, 1.0.0 = 版本号
sdwan_1.1.0    # 小版本更新
sdwan_2.0.0    # 大版本更新

4.3 动态注册

阿里云IoT支持两种设备认证方式:

  • 预注册:在阿里云控制台预先创建设备,获取设备证书(ProductKey、DeviceName、DeviceSecret)
  • 动态注册:设备在运行时向平台请求证书,无需预先创建

动态注册的优势是:可以批量部署设备,无需在平台上逐个创建。设备首次上线时自动完成注册。

remote-ota客户端基于阿里云C Link SDK开发,需要将其交叉编译为MIPS平台可执行文件。

5.1 环境变量配置

export PATH=$PATH:/home/dev/openwrt-build/staging_dir/toolchain-mipsel_24kc_gcc-7.5.0_musl/bin
export CROSS_COMPILE=mipsel-openwrt-linux-musl-
export CC="${CROSS_COMPILE}gcc -pthread"
export LDSHARED="${CC} -shared"
export STAGING_DIR=/home/dev/openwrt-build/package/ota_package/remote_ota/src/core:\
/home/dev/openwrt-build/staging_dir/toolchain-mipsel_24kc_gcc-7.5.0_musl/bin:$STAGING_DIR

注意:STAGING_DIR需要包含SDK的C Link SDK头文件路径和编译输出的临时文件路径。

5.2 编译

cd /path/to/clink-sdk
make    # 生成 fota-posix 可执行文件

六、将OTA客户端打包为OpenWrt软件包

6.1 包结构

package/
  ota_package/
    remote_ota/
      Makefile              # OpenWrt包定义
      src/
        hello.c             # 示例源码(实际是C Link SDK的封装)
        Makefile            # C代码的Makefile

6.2 OpenWrt Makefile编写

include $(TOPDIR)/rules.mk

PKG_NAME:=remote-ota
PKG_VERSION:=1
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

define Package/$(PKG_NAME)
    CATEGORY:=Utilities
    PKGARCH:=all
    TITLE:=Remote OTA module for SD-WAN terminal
endef

# 准备:将源码复制到build_dir
define Build/Prepare
    mkdir -p $(PKG_BUILD_DIR)
    $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

# 编译:调用源码目录的Makefile
define Build/Compile
    $(MAKE) -C $(PKG_BUILD_DIR) \
        ARCH="$(LINUX_KARCH)" \
        CC="$(TARGET_CC)" \
        CFLAGS="$(TARGET_CFLAGS) -Wall" \
        LDFLAGS="$(TARGET_LDFLAGS)"
endef

# 安装:将编译产物部署到目标系统
define Package/$(PKG_NAME)/install
    $(INSTALL_DIR) $(1)/usr/lib/ota/components
    $(INSTALL_DIR) $(1)/usr/lib/ota/core
    $(INSTALL_DIR) $(1)/usr/lib/ota/external
    $(INSTALL_DIR) $(1)/usr/lib/ota/portfiles
    $(INSTALL_DIR) $(1)/usr/sbin
    $(CP) $(PKG_BUILD_DIR)/output/components/* $(1)/usr/lib/ota/components/
    $(CP) $(PKG_BUILD_DIR)/output/core/* $(1)/usr/lib/ota/core/
    $(CP) $(PKG_BUILD_DIR)/output/external/* $(1)/usr/lib/ota/external/
    $(CP) $(PKG_BUILD_DIR)/output/portfiles/* $(1)/usr/lib/ota/portfiles/
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/output/fota-posix-demo $(1)/usr/sbin/remote_ota
endef

$(eval $(call BuildPackage,$(PKG_NAME)))

这个Makefile的要点:

  • Build/Prepare:将C Link SDK的源码复制到build_dir
  • Build/Compile:传入OpenWrt的交叉编译参数,调用SDK的Makefile进行编译
  • install:将编译产物(可执行文件、库文件、配置文件)部署到目标系统的对应目录
  • PKGARCH:=all:虽然C Link SDK是编译产物,但由于它会被预编译后放入files目录再打包,所以标记为all

6.3 自启动服务配置

OTA客户端需要作为系统服务自动启动,并配置看门狗监控:

#!/bin/sh /etc/rc.common

START=99
USE_PROCD=1

start_service() {
    procd_open_instance "remote_ota"
    procd_set_param command "/sbin/remote_ota"
    procd_set_param respawn 3600 5 0
    procd_set_param stdout 1    # 输出到系统日志
    procd_set_param stderr 1
    procd_close_instance
}

七、升级保留策略

OpenWrt的sysupgrade工具在升级固件时,默认会清除所有用户数据。但SD-WAN终端的升级场景下,有些文件需要在升级后保留:

  • OTA客户端的配置和证书文件
  • 业务软件的配置和数据
  • 网络配置(可能需要保留)
  • 4G拨号相关配置

7.1 配置保留机制

OpenWrt通过/lib/upgrade/keep.d/目录下的文件来定义升级保留规则。每个文件包含一系列路径模式,匹配的文件/目录在升级时不会被清除。

默认保留规则位于源码:

package/base-files/files/lib/upgrade/keep.d/

7.2 添加自定义保留规则

在源码的keep.d目录下添加一个文件,列出OTA相关文件的保留规则:

# /lib/upgrade/keep.d/remote-ota
/usr/lib/ota/
/etc/config/ota/
/var/lib/remote_ota/

这样,sysupgrade在执行升级时会保留这些目录中的文件。

7.3 sysupgrade命令

# 基本升级(保留配置)
sysupgrade /tmp/firmware.bin

# 不保留配置(相当于恢复出厂设置)
sysupgrade -n /tmp/firmware.bin

# 仅升级特定分区
sysupgrade -k /tmp/firmware.bin    # 只升级内核

八、异常处理与可靠性

8.1 进程守护

watchdog_daemon程序监控remote-ota进程的运行状态。如果remote_ota异常退出,watchdog_daemon会自动重启它。这通过OpenWrt的procd机制实现。

8.2 升级失败回退

固件下载后、刷写前的校验环节可以防止损坏的固件被刷入设备。如果校验失败:

  1. 删除已下载的不完整固件文件
  2. 通过MQTT上报升级失败事件
  3. 等待平台重新下发升级指令

8.3 看门狗兜底

作为最后的防线,硬件看门狗可以确保设备在严重故障时自动重启。如果OTA升级过程中设备完全死机(连看门狗喂狗程序都停止了),看门狗会强制重启设备。由于升级尚未完成(sysupgrade还没执行),设备会以旧固件重新启动,保持可用状态。

九、调试与运维

9.1 查看OTA日志

logread | grep remote_ota    # 查看OTA程序日志
logread | grep ota           # 查看所有OTA相关日志

9.2 手动触发升级

在调试阶段,可以手动执行OTA流程来验证功能:

# 手动下载固件
wget -O /tmp/firmware.bin "http://ota-server/firmware/v1.1.bin"

# 手动校验
md5sum /tmp/firmware.bin

# 手动升级
sysupgrade /tmp/firmware.bin

9.3 远程调试建议

在实际部署中,建议:

  1. 先在少量设备上灰度升级,验证通过后再全量推送
  2. 升级前确认设备在线且网络稳定
  3. 避免在业务高峰期执行升级
  4. 保留回退方案(如旧版本固件的下载链接)

十、总结

OTA远程升级是SD-WAN终端运维体系的关键能力。本文介绍的方案的核心设计思路是:

  1. 通信层:使用MQTT协议(阿里云IoT平台),确保低带宽下的可靠通信
  2. 安全层:TLS加密传输 + 固件校验,防止固件被篡改
  3. 执行层:sysupgrade完成实际的固件刷写,支持文件保留
  4. 保障层:procd进程守护 + 硬件看门狗,多层兜底确保设备可用

这套方案在实际部署中经受住了数百台设备的规模化升级考验。从工程实践看,OTA升级最常遇到的问题不是技术方案本身,而是网络环境的复杂性——不同现场的带宽、延迟、防火墙策略差异很大,需要在通信协议层面做好重试和超时处理。


本系列文章到此结束。 从业务需求理解,到系统原理剖析,再到编译、定制、集成、分流、嵌入式Agent开发和OTA升级,完整覆盖了在OpenWrt嵌入式路由器上开发SD-WAN终端的核心技术环节。希望这个系列对从事相关领域开发的工程师有所帮助。