5. 莱因特T68M软路由
今天的主角是一台搭载 RK3568 芯片的工业路由器:莱因特 T68M。
最近从闲鱼 450 RMB 购入,卖家当时应该是下单了顶配套装,包含路由器本体、全套配件(电源、串口线、转接线)、子卡、WiFi 模块、天线~不过实际有用的只有机器本体与电源,其余配件由于系统兼容性问题无法驱动。
到手后折腾了一番,拆除掉多余硬件(子卡、WiFi 与天线)后,才刷上 iStoreOS 22.03.7,外接一个机械盘与一个固态盘时待机功耗 6w 左右,只有 PVE 主机待机功耗的十分之一。
使用一段时间后,感觉对 ARM 盒子有了一些新的认知,这里做一做记录,以防后续对它们有不切实际的幻想。

- 机器后侧带有两个 2.5G 网口和两个千兆网口,使用 DC 12V 1A 的充电器供电,后侧还预留了天线接口
- 正面带一个 type-c 接口(无法驱动)、状态灯、TF 卡槽、HDMI 2.0 接口(无法驱动)、USB 3.0 和 USB 2.0 各一个,以及一个 Console 接口
- 机器整体使用金属材料,顶部是一块巨大的被动散热顶盖,通过硅脂直触芯片
- 支持子卡拓展 WiFi/mSATA 和 4G/5G 模块,但 WiFi 和 mSATA 二选一的配置对我无用,而且只有厂家秘制系统固件支持子卡,iStoreOS 的官方固件并不兼容型号复杂的子卡
这台机子最大的亮点是双千兆与双 2.5G 网口,且 450 元的价格相比目前官方淘宝店的 582 元更具性价比,剩下的都是槽点。
从系统兼容性方面来说,RK3568 是极具灾难性,市面上的机器基本同时带 eMMC 和 SD/TF 卡,而且可能因为处于转型时期,各个厂家争相添加非标硬件,比如 H66K/H68K/H69K/R5C 含有 WiFi 模块、R5S 支持 NVME、T68M 支持子卡等,不规范的外设导致了机器适配不完善:
- 关于RK35xx系列机型混刷不同作者固件可能出现的问题 #1012
- T68M USB 无法识别 #1255
- T68M安装固件22.03.4后网卡eth1不能识别,请修复。 #889
- target/rockchip: t68m add minipcie support #887
T68M 是我上网以来少有通过搜索引擎都查询不到有效信息的机器……冷门机型缺少关注度,适配时的优化力度也就跟不上了,像 T68M 真正可用的固件只有 iStoreOS:莱因特T68M 安装教程 #,最简单的刷机办法是先从TF卡启动,然后使用 dd 命令刷入固件到 eMMC。

配置好 iStoreOS 后,我安装了 PassWall 插件,并通过 Docker 部署了一些常用软件,将 PVE 主机上的一些服务迁移了过来,大部分时间下它只是负责流量的路由转发,负载并不高:

可一旦探索路由器以外的玩法时,马上就会遇到性能瓶颈:
- 内置的 32G eMMC 写入速度约 108MB/s,目前只做系统盘使用
- 附带的 TF 卡写入速度约 11MB/s,只适合数据备份或者刷机
- USB 2.0 外接机械盘写入速度越 29MB/s,只有 x86 机器上测试结果的一半
- USB 3.0 外接固态盘写入速度约 214MB/s,低于 x86 机器上的测试结果,更远低于 USB 3.0 标称的 5Gbps 速率
- 通过 NFS 测试固态盘写入速度最高 181MB/s,CPU 占用率超过 80%
- librespeed 的 speedtest 无线测速可以跑满千兆,需要使用宿主机网络,直接访问 IP+端口 测试
- Docker 应用的流量一单经过容器网络(docker-proxy 转发)或者反向代理转发,性能就会大打折扣,且 CPU 经常满载,比如 filebrowser 使用 caddy 反向代理后速度降低一半
- 板载的 G52 集显支持 h264/h265 的 4K 解码和 1080P 编码,可以为 jellyfin 启用 RKMPP 硬件加速,但转码时的播放卡顿和延迟比较明显
总得来说:CPU 算力不足容易满载,磁盘 I/O 性能羸弱无法充当 NAS,只有网络性能够用。
最后附上加拿大白嫖王 Linus 对 RK3588 NAS 套件的测试:

这块板子通过 SMB 跑满 2.5G 网口时,CPU 负载已经来到了 60%,理论上应该支撑不了 5G 和 10G 网口满载的使用场景。
八核心的 RK3588 尚且如此,其他低端型号更不用说了,我认为目前使用 ARM 芯片的 NAS 机器都不太靠谱,还是得上 x86。
iStoreOS 对 NAT6 的支持还存在问题,能设置 IPv6 子网但无法转发流量,只有中继模式可以正常工作,而中继模式下 IPv6 透明代理无法生效。
由于之前在 OpenWrt 23.05.4 成功配置过 NAT6,就想着在 iStoreOS 上使用虚拟机运行 OpenWrt 做主路由,可惜测试下来发现当前内核不支持虚拟化:
➜ ~ uname -a
Linux hermes 5.10.221 #0 SMP Fri Jul 26 06:23:27 2024 aarch64 GNU/Linux
➜ ~ modinfo kvm
cannot find module - kvm
看起来是未启用 KVM 模块,就折腾了一下 LXC 运行 OpenWrt。
首先是修改 iStoreOS 接口设备,创建一个 br-wan 网桥,将 eth0 附加到该网桥的有线端口,再给网桥配置静态地址,这样插入网桥的其他设备也能从上级路由器获取到动态地址访问公网:

➜ ~ brctl show
bridge name bridge id STP enabled interfaces
br-lan 7fff.7a6210698133 no eth3
eth1
eth2
br-wan 7fff.7a6210698132 no eth0
docker0 8000.02426c5765f4 no veth48c0d8f
vethc2225c5
vethb51d5bc
vethf67f72e
vetha763745
然后安装 luci-app-lxc,这样就可以在网页上操作 LXC 容器,images.linuxcontainers.org 上提供了 21.02、22.03、23.05 三个版本的 OpenWrt 模板,由于当前 iStoreOS 内核未启用 nf_tables,只有 21.02 能正常运行,其余两个模板强依赖 nf_tables,NAT 模块无法正常工作。

创建 LXC 容器后,可以编辑容器的 config 文件进行配置,这里我就为容器设置了双网卡,eth0 接入 br-wan 作为 WAN 口,eth1 接入 br-lan 作为 LAN 口,如下:
➜ ~ cat /srv/lxc/ow/config
# Template used to create this container: /usr/share/lxc/templates/lxc-download
# Parameters passed to the template: --dist openwrt --release 23.05 --arch arm64 --server images.linuxcontainers.org
# Template script checksum (SHA-1): b3bb2a43ecae163bbffcd371e9166118ab6182aa
# For additional config options, please look at lxc.container.conf(5)
# Uncomment the following line to support nesting containers:
#lxc.include = /usr/share/lxc/config/nesting.conf
# (Be aware this has security implications)
# Distribution configuration
lxc.include = /usr/share/lxc/config/common.conf
lxc.arch = aarch64
# Container specific configuration
lxc.rootfs.path = dir:/srv/lxc/ow/rootfs
lxc.uts.name = ow
# Network configuration
lxc.net.0.name = eth0
lxc.net.0.type = veth
lxc.net.0.link = br-wan
lxc.net.0.flags = up
lxc.net.1.name = eth1
lxc.net.1.type = veth
lxc.net.1.link = br-lan
lxc.net.1.flags = up
启动 LXC 容器后就可以进入容器内修改防火墙设置,允许从 WAN 口访问网页控制台:
➜ ~ lxc-start -n ow
➜ ~ lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
ow RUNNING 0 - 192.168.1.128 2408:xxxx:xxxx:xxxx:xxxx:xxxx, 2408:xxxx:xxxx:xxxx:xxxx:xxxx fal
➜ ~ lxc-attach -n ow
BusyBox v1.36.1 (2024-07-15 22:14:18 UTC) built-in shell (ash)
~ # uname -a
Linux ow 5.10.221 #0 SMP Fri Jul 26 06:23:27 2024 aarch64 GNU/Linux
~ # cat /etc/os-release
NAME="OpenWrt"
VERSION="23.05.4"
ID="openwrt"
ID_LIKE="lede openwrt"
PRETTY_NAME="OpenWrt 23.05.4"
VERSION_ID="23.05.4"
HOME_URL="https://openwrt.org/"
BUG_URL="https://bugs.openwrt.org/"
SUPPORT_URL="https://forum.openwrt.org/"
BUILD_ID="r24012-d8dd03c46f"
OPENWRT_BOARD="armsr/armv8"
OPENWRT_ARCH="aarch64_generic"
OPENWRT_TAINTS=""
OPENWRT_DEVICE_MANUFACTURER="OpenWrt"
OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/"
OPENWRT_DEVICE_PRODUCT="Generic"
OPENWRT_DEVICE_REVISION="v0"
OPENWRT_RELEASE="OpenWrt 23.05.4 r24012-d8dd03c46f"
~ # uci set firewall.@zone[1].input="ACCEPT"
~ # uci commit firewall
~ # service firewall restart
netlink: Error: cache initialization failed: Invalid argument
Unable to parse nftables JSON output: Failed to parse JSON string: unexpected end of data
netlink: Error: cache initialization failed: Invalid argument
The rendered ruleset contains errors, not doing firewall restart.
访问 http://192.168.1.128 即可查看 OpenWrt 后台:

上面刚刚提到 iStoreOS 对 NAT6 的支持还存在问题,具体来说是 IPv6 的 POSTROUTING 存在异常,缺失 IP 动态伪装相关的规则,如下:

➜ ~ iptables-save|grep zone_lan_postrouting
:zone_lan_postrouting - [0:0]
-A POSTROUTING -o br-lan -m comment --comment "!fw3" -j zone_lan_postrouting
-A zone_lan_postrouting -m comment --comment "!fw3: Custom lan postrouting rule chain" -j postrouting_lan_rule
-A zone_lan_postrouting -i docker0 -m comment --comment "!fw3: DockerNAT" -j MASQUERADE
-A zone_lan_postrouting -m comment --comment "!fw3" -j MASQUERADE --mode fullcone
➜ ~ ip6tables-save|grep zone_lan_postrouting
IPv6 的防火墙规则里缺失自定义链 zone_lan_postrouting,即使客户端分配到内网 IPv6 地址,也无法访问外网 IPv6 站点。
前天刚好又犯了常见错误:卸载系统自带软件连带删除关键组件,导致 iStoreOS 的网卡异常,只能重置系统,于是参考之前在 OpenWrt 开启 NAT6 的方法再尝试了一下:
官方文档地址:NAT66 and IPv6 masquerading
# 1.配置防火墙
uci set firewall.@zone[1].masq6="1"
uci commit firewall
service firewall restart
# 2.配置 WAN6
uci set network.wan6.sourcefilter="0"
uci commit network
service network restart
# 3.设置 IPv6 默认路由
uci set dhcp.lan.ra_default="1"
uci commit dhcp
service odhcpd restart
第一步操作中设置的 masq6 依旧无法识别,重启 firewall 会报错,但第二步和第三步的操作正常,然后我尝试在防火墙自定义规则中添加了一条 自动重写源IP 的规则,如下:
ip6tables -t nat -A POSTROUTING -o br-wan -s fd98:5686:64cf::/60 -j MASQUERADE
br-wan 是我的公网网桥,fd98:5686:64cf::/60 是我的内网 IPv6 地址段。

结果保存配置后,就可以正常访问 IPv6 站点了……下面是在 Debian 12 环境测试的,使用 SLAAC 获取 IPv6 地址,可以看到 inet6 设置为 auto,IPv6 内网地址是从 MAC 地址生成的:

另外注意配置下 PassWall 和 dnsmasq:
- 在 服务 -> PassWall 的 基本设置 -> DNS 中需要取消勾选 过滤代理域名 IPv6,然后在 高级设置 -> 转发配置 中勾选 IPv6 透明代理(TProxy),就可以透明代理访问外网的 IPv6 流量。
- 在 网络 -> DHCP/DNS 的 过滤器 中,取消勾选 过滤 IPv6 AAAA 记录
配置完成后访问谷歌的 IPv6 DNS 服务器,在 PassWall 日志中可以看到请求通过代理服务器转发:
➜ ~ nslookup google.com 2001:4860:4860:0:0:0:0:8888
Server: 2001:4860:4860:0:0:0:0:8888
Address: 2001:4860:4860::8888#53
Non-authoritative answer:
Name: google.com
Address: 142.250.206.206

为了避免安装和卸载 iStoreOS 自带软件导致系统异常,我只在系统上直接安装 PassWall 软件,其余软件都通过 Docker 运行,包括 tailscale,下面是使用 Docker 运行 tailscale 的脚本:
#!/bin/sh
# 容器镜像
image="tailscale/tailscale:stable"
# 容器名称
container="tailscale"
# 检查容器是否存在
if [ "$(docker ps -a -q -f name=$container)" ]; then
# 如果容器未处于停止状态,则停止容器
if [ "$(docker ps -q -f name=$container)" ]; then
docker stop $container
fi
# 删除容器
docker rm $container
fi
# 启动容器: 容器名称-> 是否后台运行 -> 重启策略 -> 网络类型 -> 环境变量 -> 挂载项 -> 镜像名
docker run --name $container -d \
--restart unless-stopped \
--network host \
-e TS_AUTHKEY=xxxxxxx \
-e TS_USERSPACE=false \
-e TS_ROUTES=内网IPv4网段 \
-e TS_EXTRA_ARGS=--advertise-exit-node \
-e TS_STATE_DIR=/var/lib/tailscale \
-e TS_SOCKET=/var/run/tailscale/tailscaled.sock \
-v $PWD/state:/var/lib/tailscale \
-v /var/run/tailscale:/var/run/tailscale \
--privileged=true \
$image
TS_AUTHKEY 需要在 tailscale 控制台上创建,用于认证账号,可选一次性有效或者长期有效,认证成功后配置文件就会保存到 /var/lib/tailscale 目录下,下次启动不需要使用 TS_AUTHKEY。