Skip to content

OpenWrt 架构与原理

整体架构

OpenWrt 在标准 Linux 内核之上构建了一套专为嵌入式网络设备设计的用户空间框架。

┌─────────────────────────────────────────────────────┐
│                   用户应用层                          │
│  LuCI  │  mosquitto  │  node-red  │  自定义脚本      │
├─────────────────────────────────────────────────────┤
│                   服务管理层                          │
│         procd(进程守护)│ ubus(IPC 总线)           │
├──────────────┬──────────────────────────────────────┤
│   配置层      │              网络层                   │
│   UCI        │  netifd │ hostapd │ dnsmasq │ nftables│
├──────────────┴──────────────────────────────────────┤
│                   Linux 内核                          │
│  netfilter │ mac80211 │ kmod-* │ SquashFS/JFFS2      │
├─────────────────────────────────────────────────────┤
│                   硬件抽象层                          │
│         SoC BSP │ 网卡驱动 │ USB │ UART │ SPI/I2C   │
└─────────────────────────────────────────────────────┘

UCI 配置系统

UCI(Unified Configuration Interface)是 OpenWrt 的核心配置框架,所有系统配置统一存储在 /etc/config/ 目录下的文本文件中。

配置文件格式

# /etc/config/network

config interface 'loopback'
    option ifname 'lo'
    option proto 'static'
    option ipaddr '127.0.0.1'
    option netmask '255.0.0.0'

config interface 'lan'
    option type 'bridge'
    option ifname 'eth0'
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'

config interface 'wan'
    option ifname 'eth1'
    option proto 'dhcp'

UCI 命令行操作

bash
# 读取配置
uci get network.lan.ipaddr          # 192.168.1.1
uci show network.lan                # 显示 lan 接口所有配置

# 修改配置
uci set network.lan.ipaddr='10.0.0.1'
uci set network.lan.netmask='255.255.0.0'

# 添加列表项
uci add_list network.lan.dns='8.8.8.8'
uci add_list network.lan.dns='8.8.4.4'

# 提交并生效
uci commit network
/etc/init.d/network restart

# 批量操作(推荐用于脚本)
uci batch <<EOF
set network.wan.proto=pppoe
set network.wan.username=user@isp.com
set network.wan.password=secret
commit network
EOF

UCI 配置文件对应关系

文件管理的服务
/etc/config/network网络接口、路由、VLAN
/etc/config/wirelessWiFi 配置
/etc/config/firewall防火墙规则
/etc/config/dhcpDHCP/DNS(dnsmasq)
/etc/config/system主机名、时区、日志
/etc/config/rpcdRPC 访问控制

procd 进程管理

procd 是 OpenWrt 的 init 系统和进程守护程序,替代了传统的 sysvinit。

服务脚本结构

bash
#!/bin/sh /etc/rc.common
# /etc/init.d/myservice

USE_PROCD=1
START=95
STOP=05

start_service() {
    procd_open_instance
    procd_set_param command /usr/bin/myapp --config /etc/myapp.conf
    procd_set_param respawn 3600 5 0   # 崩溃后重启:间隔/超时/最大次数(0=无限)
    procd_set_param stdout 1           # 重定向 stdout 到 syslog
    procd_set_param stderr 1
    procd_set_param pidfile /var/run/myapp.pid
    procd_set_param env MY_VAR=value   # 环境变量
    procd_close_instance
}

reload_service() {
    stop
    start
}

service_triggers() {
    procd_add_reload_trigger "network"  # 网络变化时自动 reload
}
bash
# 服务管理命令
/etc/init.d/myservice start
/etc/init.d/myservice stop
/etc/init.d/myservice restart
/etc/init.d/myservice reload
/etc/init.d/myservice enable    # 开机自启
/etc/init.d/myservice disable

ubus IPC 总线

ubus 是 OpenWrt 的进程间通信机制,类似于 D-Bus,用于服务发现和方法调用。

bash
# 列出所有注册的对象
ubus list

# 查看对象方法
ubus -v list network.interface

# 调用方法
ubus call network.interface.lan status
ubus call system board
ubus call network reload

# 监听事件
ubus monitor
ubus listen network.interface

ubus 编程示例(C)

c
#include <libubus.h>

static int hello_handler(struct ubus_context *ctx,
                          struct ubus_object *obj,
                          struct ubus_request_data *req,
                          const char *method,
                          struct blob_attr *msg)
{
    struct blob_buf b = {};
    blob_buf_init(&b, 0);
    blobmsg_add_string(&b, "message", "Hello from ubus!");
    ubus_send_reply(ctx, req, b.head);
    blob_buf_free(&b);
    return 0;
}

netifd 网络管理

netifd 是 OpenWrt 的网络接口守护进程,负责管理所有网络接口的生命周期。

netifd 架构
├── 接口(interface):逻辑网络,如 lan/wan
├── 设备(device):物理设备,如 eth0/br-lan
├── 协议处理器(proto handler):dhcp/static/pppoe/...
└── 热插拔脚本:/etc/hotplug.d/iface/

自定义协议处理器

bash
# /lib/netifd/proto/myproto.sh
#!/bin/sh
. /lib/functions.sh
. /lib/netifd/netifd-proto.sh

init_proto() {
    proto_config_add_string "server"
    proto_config_add_string "username"
    proto_config_add_string "password"
}

proto_myproto_setup() {
    local config="$1"
    local iface="$2"
    
    local server username password
    json_get_vars server username password
    
    # 建立连接逻辑...
    proto_init_update "$iface" 1
    proto_add_ipv4_address "10.0.0.2" "255.255.255.0"
    proto_add_ipv4_route "0.0.0.0" 0 "10.0.0.1"
    proto_send_update "$config"
}

文件系统结构

OpenWrt 使用 OverlayFS 实现可写文件系统:

Flash 存储
├── kernel 分区(只读)
│   └── Linux 内核镜像
└── rootfs 分区
    ├── SquashFS(只读基础系统)
    └── JFFS2/F2FS(可写 overlay)
        └── /overlay/upper/  ← 用户修改存储在此
bash
# 查看文件系统使用情况
df -h
# overlay 是可写层,空间有限!

# 查看 overlay 内容
ls /overlay/upper/

# 恢复出厂设置(清空 overlay)
firstboot && reboot
# 或
jffs2reset -y && reboot

构建系统

OpenWrt 构建系统基于 GNU Make,支持交叉编译。

bash
# 克隆源码
git clone https://git.openwrt.org/openwrt/openwrt.git
cd openwrt
git checkout v23.05.3

# 更新 feeds(软件包源)
./scripts/feeds update -a
./scripts/feeds install -a

# 配置目标平台和软件包
make menuconfig
# Target System → x86
# Target Profile → Generic x86/64
# 选择需要的软件包...

# 编译(-j 并行)
make -j$(nproc) V=s 2>&1 | tee build.log

# 输出目录
ls bin/targets/x86/64/

自定义软件包 Makefile

makefile
# package/myapp/Makefile
include $(TOPDIR)/rules.mk

PKG_NAME:=myapp
PKG_VERSION:=1.0.0
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://example.com/releases/
PKG_HASH:=abc123...

include $(INCLUDE_DIR)/package.mk

define Package/myapp
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=My IoT Application
  DEPENDS:=+libmosquitto +libmodbus
endef

define Package/myapp/description
  Industrial IoT data collection application.
endef

define Build/Configure
  $(call Build/Configure/Default,--enable-mqtt --enable-modbus)
endef

define Package/myapp/install
  $(INSTALL_DIR) $(1)/usr/bin
  $(INSTALL_BIN) $(PKG_BUILD_DIR)/myapp $(1)/usr/bin/
  $(INSTALL_DIR) $(1)/etc/init.d
  $(INSTALL_BIN) ./files/myapp.init $(1)/etc/init.d/myapp
  $(INSTALL_DIR) $(1)/etc/config
  $(INSTALL_CONF) ./files/myapp.config $(1)/etc/config/myapp
endef

$(eval $(call BuildPackage,myapp))

内存与存储优化

嵌入式设备资源有限,需要特别注意:

bash
# 查看内存使用
free -m
cat /proc/meminfo

# 查看进程内存
top
ps aux --sort=-%mem | head -20

# 减少日志占用(tmpfs)
uci set system.@system[0].log_size='64'  # 64KB 循环日志
uci commit system

# 使用 USB/SD 扩展存储(extroot)
# 1. 格式化 USB
mkfs.ext4 /dev/sda1

# 2. 挂载并复制 overlay
mount /dev/sda1 /mnt
tar -C /overlay -cvf - . | tar -C /mnt -xf -

# 3. 配置 fstab
uci set fstab.@mount[0].target='/overlay'
uci set fstab.@mount[0].device='/dev/sda1'
uci set fstab.@mount[0].fstype='ext4'
uci set fstab.@mount[0].enabled='1'
uci commit fstab
reboot

褚成志的IoT笔记