09/7
19:12
| Port | Media / Speed | Connected Device | Role / Service | Description |
|---|---|---|---|---|
| SFP+ 1 | Optical (PON Stick) | Shanghai Unicom ODN | Uplink (WAN) | Carries Internet & IPTV traffic from ISP |
| SFP+ 2 | DAC (SFP+) | UCG-Fiber (WAN 1) | Downlink (WAN 1) | Primary WAN link (PPPoE / DHCP) |
| SFP+ 3 | DAC (SFP+) | UCG-Fiber (WAN 2) | Downlink (WAN 2) | Secondary WAN link (Dual WAN / Load Balance) |
| SFP+ 4 | DAC / Optical | Core Switch / LAN | Management (MGMT) | Out-of-band management access to CRS305 |
| Ether1 | RJ45 (1G) | IPTV STB / Local LAN | IPTV Access | Dedicated untagged IPTV access port |
# ============================================================
# CRS305-1G-4S+ 自动化部署脚本 (setup.rsc)
# 适用: RouterOS v7.x
# 执行重置指令:
# /system reset-configuration no-defaults=yes run-after-reset=setup.rsc
#
# 口型:
# sfp-sfpplus1 PONStick tagged 1268/44/40 + untagged 99 (Stick 管理 192.168.0.1)
# sfp-sfpplus2 UCG-WAN1 untagged 1268 PPPoE
# sfp-sfpplus3 UCG-WAN2 untagged 1268 PPPoE + tagged 99 (访问 192.168.0.1/.2)
# sfp-sfpplus4 Local-MGMT untagged 99
# ether1 IPTV untagged 44 + tagged 40
# ============================================================
:delay 15s;
/ipv6 settings
set disable-ipv6=yes
/interface list
add name=MGMT
/interface bridge
add name=br-pon \
protocol-mode=none \
vlan-filtering=no \
igmp-snooping=yes
/interface bridge port
add bridge=br-pon \
interface=sfp-sfpplus1 \
pvid=99 \
ingress-filtering=yes \
frame-types=admit-all \
hw=yes \
multicast-router=permanent \
comment="PONStick"
add bridge=br-pon \
interface=sfp-sfpplus2 \
pvid=1268 \
ingress-filtering=yes \
frame-types=admit-only-untagged-and-priority-tagged \
hw=yes \
unknown-multicast-flood=no \
multicast-router=disabled \
comment="UCG-WAN1"
add bridge=br-pon \
interface=sfp-sfpplus3 \
pvid=1268 \
ingress-filtering=yes \
frame-types=admit-all \
hw=yes \
unknown-multicast-flood=no \
multicast-router=disabled \
comment="UCG-WAN2"
add bridge=br-pon \
interface=sfp-sfpplus4 \
pvid=99 \
ingress-filtering=yes \
frame-types=admit-only-untagged-and-priority-tagged \
hw=yes \
unknown-multicast-flood=no \
multicast-router=disabled \
comment="Local-MGMT"
add bridge=br-pon \
interface=ether1 \
pvid=44 \
ingress-filtering=yes \
frame-types=admit-all \
hw=yes \
fast-leave=yes \
multicast-router=disabled \
comment="IPTV"
/interface bridge vlan
add bridge=br-pon \
vlan-ids=99 \
tagged=br-pon,sfp-sfpplus3 \
untagged=sfp-sfpplus1,sfp-sfpplus4
add bridge=br-pon \
vlan-ids=1268 \
tagged=sfp-sfpplus1 \
untagged=sfp-sfpplus2,sfp-sfpplus3
add bridge=br-pon \
vlan-ids=44 \
tagged=sfp-sfpplus1 \
untagged=ether1
add bridge=br-pon \
vlan-ids=40 \
tagged=sfp-sfpplus1,ether1
/interface vlan
add name=vlan99-mgmt \
interface=br-pon \
vlan-id=99
/ip address
add address=192.168.0.2/24 \
interface=vlan99-mgmt
/ip route
add dst-address=0.0.0.0/0 \
gateway=192.168.0.3 \
comment="Default Gateway via UCG"
/ip dns
set servers=192.168.0.3,223.5.5.5
/interface list member
add interface=vlan99-mgmt \
list=MGMT \
comment="VLAN99 IP Management"
add interface=sfp-sfpplus4 \
list=MGMT \
comment="Emergency MAC Winbox"
/ip neighbor discovery-settings
set discover-interface-list=MGMT
/tool mac-server
set allowed-interface-list=MGMT
/tool mac-server mac-winbox
set allowed-interface-list=MGMT
/ip service
set telnet disabled=yes
set ftp disabled=yes
set api disabled=yes
set api-ssl disabled=yes
/interface bridge
set [find name=br-pon] frame-types=admit-only-vlan-tagged ingress-filtering=yes vlan-filtering=yes
ucg 7号sfp+口 接入wan
ip link add link eth6 name eth6.99 type vlan id 99
ip link set eth6.99 up
ip addr add 192.168.0.3/24 dev eth6.99
UCG-Fiber VLAN99 一键脚本
直接 SSH 到 UCG-Fiber,以 root 身份整段复制执行:
bash <<'UCG_VLAN99_INSTALL'
set -Eeuo pipefail
# ============================================================
# UCG-Fiber VLAN99 完整一键部署
#
# 已验证环境:
# UniFi Cloud Gateway Fiber
# UniFi OS / Firmware v6.0.9
# Linux 5.4.213-ui-ipq9574
#
# 配置:
# Parent : eth6
# VLAN : 99
# IP : 192.168.0.3/24
# MTU : 1500
#
# 功能:
# 1. 自动检测/安装 unifi-common / udm-boot
# 2. 自动备份旧 VLAN99 配置
# 3. 部署 VLAN99 maintainer
# 4. 创建 systemd service
# 5. 创建 /data/on_boot.d 固件升级恢复脚本
# 6. 自动启用并启动
# 7. 自动健康检查
# ============================================================
PARENT="eth6"
VLAN_IF="eth6.99"
VLAN_ID="99"
IP_ADDR="192.168.0.3/24"
SRC_IP="192.168.0.3"
SUBNET="192.168.0.0/24"
BASE="/data/ucg-vlan99"
SCRIPT="$BASE/vlan99-maintain.sh"
BOOT="/data/on_boot.d/50-ucg-vlan99.sh"
UNIT="/etc/systemd/system/ucg-vlan99.service"
UDM_UNIT="/etc/systemd/system/udm-boot.service"
UDM_INSTALL_URL="https://raw.githubusercontent.com/unifi-utilities/unifi-common/HEAD/remote_install.sh"
STAMP="$(date +%Y%m%d-%H%M%S)"
BACKUP="$BASE/backup/$STAMP"
# ============================================================
# 辅助函数
# ============================================================
section() {
echo
echo "============================================================"
echo "$1"
echo "============================================================"
}
die() {
echo
echo "ERROR: $*" >&2
exit 1
}
# ============================================================
# 0. 基础检查
# ============================================================
section "[0/8] 环境检查"
[ "$(id -u)" -eq 0 ] || die "请使用 root 执行"
command -v systemctl >/dev/null || die "systemctl 不存在"
command -v ip >/dev/null || die "ip 命令不存在"
command -v curl >/dev/null || die "curl 不存在"
if command -v ubnt-device-info >/dev/null 2>&1; then
MODEL="$(ubnt-device-info model 2>/dev/null || true)"
FW="$(ubnt-device-info firmware 2>/dev/null || true)"
echo "Model : ${MODEL:-unknown}"
echo "Firmware : ${FW:-unknown}"
if [ "${MODEL:-}" != "UniFi Cloud Gateway Fiber" ]; then
echo "WARNING: 当前型号不是 UniFi Cloud Gateway Fiber"
echo " 脚本仍继续,但 eth6 映射需要你自行确认。"
fi
else
echo "ubnt-device-info 不存在,跳过型号检查"
fi
echo "Kernel : $(uname -r)"
echo "Arch : $(uname -m)"
# ============================================================
# 1. 检测 / 安装 on_boot 框架
# ============================================================
section "[1/8] 检查 udm-boot / on_boot"
NEED_UDM_INSTALL=0
if [ ! -f "$UDM_UNIT" ]; then
echo "未发现 $UDM_UNIT"
NEED_UDM_INSTALL=1
else
# 必须确认这是使用 /data/on_boot.d 的当前结构
if ! grep -q '/data/on_boot.d' "$UDM_UNIT" 2>/dev/null; then
echo "发现 udm-boot,但不是当前 /data/on_boot.d 结构"
NEED_UDM_INSTALL=1
else
echo "已发现兼容的 udm-boot.service"
fi
fi
if [ "$NEED_UDM_INSTALL" -eq 1 ]; then
echo "安装当前 unifi-common / udm-boot..."
TMP_INSTALL="/tmp/unifi-common-remote-install.sh"
curl -fL \
"$UDM_INSTALL_URL" \
-o "$TMP_INSTALL"
chmod 700 "$TMP_INSTALL"
/bin/bash "$TMP_INSTALL"
rm -f "$TMP_INSTALL"
fi
mkdir -p /data/on_boot.d
systemctl daemon-reload
systemctl enable udm-boot.service >/dev/null 2>&1 || \
die "无法 enable udm-boot.service"
# 已经 active 就不重复启动
if ! systemctl is-active --quiet udm-boot.service; then
systemctl start udm-boot.service || \
die "无法启动 udm-boot.service"
fi
echo
echo "udm-boot enabled : $(systemctl is-enabled udm-boot.service 2>/dev/null || true)"
echo "udm-boot active : $(systemctl is-active udm-boot.service 2>/dev/null || true)"
echo "on_boot path : /data/on_boot.d"
# ============================================================
# 2. 备份已有配置
# ============================================================
section "[2/8] 备份现有 VLAN99 配置"
mkdir -p "$BASE"
mkdir -p "$BACKUP"
[ -f "$SCRIPT" ] && \
cp -a "$SCRIPT" "$BACKUP/vlan99-maintain.sh"
[ -f "$BOOT" ] && \
cp -a "$BOOT" "$BACKUP/50-ucg-vlan99.sh"
[ -f "$UNIT" ] && \
cp -a "$UNIT" "$BACKUP/ucg-vlan99.service"
echo "Backup directory:"
echo "$BACKUP"
# ============================================================
# 3. 清理错误/旧 watchdog 名称
# ============================================================
section "[3/8] 清理旧服务"
systemctl disable --now ucg-vlan99-watchdog.service \
>/dev/null 2>&1 || true
rm -f \
/etc/systemd/system/ucg-vlan99-watchdog.service \
/etc/systemd/system/multi-user.target.wants/ucg-vlan99-watchdog.service
# 替换正式服务前先停止
systemctl stop ucg-vlan99.service \
>/dev/null 2>&1 || true
echo "旧 watchdog 名称已清理"
# ============================================================
# 4. 写入最终 VLAN99 Maintainer
# ============================================================
section "[4/8] 写入 VLAN99 Maintainer"
cat >"$SCRIPT" <<'MAINTAIN_EOF'
#!/bin/bash
# ============================================================
# UCG-Fiber VLAN99 Maintainer
#
# Parent : eth6
# VLAN : 99
# IP : 192.168.0.3/24
# MTU : 1500
#
# 特性:
# - 等待父接口存在
# - 等待父接口 carrier=1
# - VLAN 不存在才创建
# - MTU 错误才修改
# - 接口 DOWN 才 set up
# - IP 丢失才恢复
# - 不 flush 其他地址
# - UniFi 删除 VLAN 后最多约一个检查周期恢复
# - 正常运行时只检查,不反复修改 netlink
# ============================================================
PARENT="eth6"
VLAN_IF="eth6.99"
VLAN_ID="99"
IP_ADDR="192.168.0.3/24"
SRC_IP="192.168.0.3"
SUBNET="192.168.0.0/24"
INTERVAL=5
log() {
logger -t ucg-vlan99 -- "$*"
}
ensure_vlan() {
# --------------------------------------------------------
# 1. 等待父接口出现
# --------------------------------------------------------
if ! ip link show dev "$PARENT" >/dev/null 2>&1; then
return 0
fi
# --------------------------------------------------------
# 2. 等待物理链路真正建立
#
# 避免启动阶段:
# RTNETLINK answers: Network is down
# --------------------------------------------------------
CARRIER="$(cat /sys/class/net/"$PARENT"/carrier 2>/dev/null || echo 0)"
if [ "$CARRIER" != "1" ]; then
return 0
fi
# --------------------------------------------------------
# 3. VLAN99 不存在才创建
# --------------------------------------------------------
if ! ip link show dev "$VLAN_IF" >/dev/null 2>&1; then
if ip link add \
link "$PARENT" \
name "$VLAN_IF" \
type vlan id "$VLAN_ID"
then
log "Created $VLAN_IF VLAN $VLAN_ID on $PARENT"
else
log "ERROR: failed to create $VLAN_IF"
return 0
fi
fi
# UniFi 可能恰好在此时重构父接口
if ! ip link show dev "$VLAN_IF" >/dev/null 2>&1; then
return 0
fi
# --------------------------------------------------------
# 4. MTU 不正确时才修改
# --------------------------------------------------------
CURRENT_MTU="$(cat /sys/class/net/"$VLAN_IF"/mtu 2>/dev/null || true)"
if [ "$CURRENT_MTU" != "1500" ]; then
if ip link set dev "$VLAN_IF" mtu 1500; then
log "Set $VLAN_IF MTU to 1500"
else
return 0
fi
fi
# --------------------------------------------------------
# 5. Admin state DOWN 时才执行 set up
#
# /sys/.../flags bit 0 = IFF_UP
# --------------------------------------------------------
FLAGS="$(cat /sys/class/net/"$VLAN_IF"/flags 2>/dev/null || true)"
if [ -n "$FLAGS" ]; then
FLAGS_DEC=$((FLAGS))
if (( (FLAGS_DEC & 1) == 0 )); then
if ip link set dev "$VLAN_IF" up; then
log "Brought $VLAN_IF up"
else
return 0
fi
fi
fi
# --------------------------------------------------------
# 6. IPv4 地址不存在才添加
#
# 不执行 addr flush,避免删除其他地址。
# --------------------------------------------------------
if ! ip -4 -o addr show dev "$VLAN_IF" 2>/dev/null |
awk '{print $4}' |
grep -Fxq "$IP_ADDR"
then
if ip addr add "$IP_ADDR" dev "$VLAN_IF"; then
log "Assigned $IP_ADDR to $VLAN_IF"
else
return 0
fi
fi
# --------------------------------------------------------
# 7. Connected route 检查
#
# 正常情况下 IP 添加后 Linux 自动建立:
#
# 192.168.0.0/24 dev eth6.99 proto kernel ...
#
# 只有 route 异常消失时才恢复。
# --------------------------------------------------------
if ! ip -4 route show "$SUBNET" dev "$VLAN_IF" 2>/dev/null |
grep -q "src $SRC_IP"
then
if ip route replace "$SUBNET" \
dev "$VLAN_IF" \
src "$SRC_IP" 2>/dev/null
then
log "Restored route $SUBNET via $VLAN_IF"
fi
fi
}
trap 'exit 0' TERM INT
log "VLAN99 maintainer started"
while true; do
ensure_vlan
sleep "$INTERVAL" &
wait $!
done
MAINTAIN_EOF
chmod 755 "$SCRIPT"
bash -n "$SCRIPT" || \
die "vlan99-maintain.sh 语法检查失败"
echo "$SCRIPT : syntax OK"
# ============================================================
# 5. 创建正式 systemd service
# ============================================================
section "[5/8] 创建 ucg-vlan99.service"
cat >"$UNIT" <<'UNIT_EOF'
[Unit]
Description=UCG-Fiber VLAN99 Maintainer
After=network-pre.target
Wants=network-pre.target
[Service]
Type=simple
ExecStart=/data/ucg-vlan99/vlan99-maintain.sh
Restart=always
RestartSec=2
TimeoutStopSec=2
Nice=10
[Install]
WantedBy=multi-user.target
UNIT_EOF
chmod 644 "$UNIT"
echo "$UNIT created"
# ============================================================
# 6. 创建固件升级恢复脚本
# ============================================================
section "[6/8] 创建 on_boot 固件升级恢复脚本"
cat >"$BOOT" <<'BOOT_EOF'
#!/bin/bash
SCRIPT="/data/ucg-vlan99/vlan99-maintain.sh"
UNIT="/etc/systemd/system/ucg-vlan99.service"
# ------------------------------------------------------------
# 核心维护脚本不存在则不继续
# ------------------------------------------------------------
[ -x "$SCRIPT" ] || exit 0
# ------------------------------------------------------------
# 如果 UniFi OS 升级清除了 /etc 下的 unit,则重新创建
# ------------------------------------------------------------
if [ ! -f "$UNIT" ]; then
cat >"$UNIT" <<'UNIT_EOF'
[Unit]
Description=UCG-Fiber VLAN99 Maintainer
After=network-pre.target
Wants=network-pre.target
[Service]
Type=simple
ExecStart=/data/ucg-vlan99/vlan99-maintain.sh
Restart=always
RestartSec=2
TimeoutStopSec=2
Nice=10
[Install]
WantedBy=multi-user.target
UNIT_EOF
systemctl daemon-reload
fi
# ------------------------------------------------------------
# 如果 enable 状态丢失,自动恢复
# ------------------------------------------------------------
if ! systemctl is-enabled --quiet ucg-vlan99.service 2>/dev/null; then
systemctl enable ucg-vlan99.service >/dev/null 2>&1 || true
fi
# ------------------------------------------------------------
# 如果 service 没运行,自动启动
# ------------------------------------------------------------
if ! systemctl is-active --quiet ucg-vlan99.service 2>/dev/null; then
systemctl start --no-block ucg-vlan99.service || true
fi
exit 0
BOOT_EOF
chmod 755 "$BOOT"
bash -n "$BOOT" || \
die "50-ucg-vlan99.sh 语法检查失败"
echo "$BOOT : syntax OK"
# ============================================================
# 7. 启用并启动正式服务
# ============================================================
section "[7/8] 启动 VLAN99"
systemctl daemon-reload
systemctl enable ucg-vlan99.service \
>/dev/null 2>&1
systemctl restart ucg-vlan99.service
# 给 maintainer 若干检查周期
for i in 1 2 3 4 5 6; do
if ip -4 -o addr show dev "$VLAN_IF" 2>/dev/null |
awk '{print $4}' |
grep -Fxq "$IP_ADDR"
then
break
fi
sleep 5
done
# ============================================================
# 8. 健康检查
# ============================================================
section "[8/8] 最终健康检查"
echo
echo "----- udm-boot -----"
echo "enabled : $(systemctl is-enabled udm-boot.service 2>/dev/null || true)"
echo "active : $(systemctl is-active udm-boot.service 2>/dev/null || true)"
systemctl status udm-boot.service \
--no-pager -l || true
echo
echo "----- on_boot directory -----"
ls -la /data/on_boot.d || true
echo
echo "----- VLAN99 service -----"
systemctl status ucg-vlan99.service \
--no-pager -l || true
echo
echo "----- eth6 -----"
ip -d link show "$PARENT" || true
printf "carrier : "
cat /sys/class/net/"$PARENT"/carrier \
2>/dev/null || echo "unknown"
echo
echo "----- eth6.99 -----"
ip -d link show "$VLAN_IF" || true
echo
echo "----- IPv4 -----"
ip -4 addr show dev "$VLAN_IF" || true
echo
echo "----- Route -----"
ip -4 route show "$SUBNET" || true
echo
echo "----- VLAN99 Journal -----"
journalctl \
-b \
-u ucg-vlan99.service \
--since "-5 min" \
--no-pager || true
echo
echo "----- Relevant dmesg -----"
dmesg |
grep -E 'eth6\.99|link change request' |
tail -30 || true
echo
echo "----- Error check -----"
WARNINGS="$(
dmesg |
grep -Ec \
'link change request failed|Interface eth6\.99 may have been left' \
|| true
)"
NETWORK_DOWN="$(
journalctl -b -u ucg-vlan99.service --no-pager 2>/dev/null |
grep -c 'RTNETLINK answers: Network is down' \
|| true
)"
echo "link-change warnings : $WARNINGS"
echo "Network-is-down : $NETWORK_DOWN"
echo
echo "============================================================"
echo " UCG-Fiber VLAN99 部署完成"
echo "============================================================"
echo
echo "Parent : $PARENT"
echo "VLAN : $VLAN_ID"
echo "Interface : $VLAN_IF"
echo "IP : $IP_ADDR"
echo
echo "Maintainer : $SCRIPT"
echo "Service : $UNIT"
echo "on_boot : $BOOT"
echo "Backup : $BACKUP"
echo
echo "udm-boot : $(systemctl is-enabled udm-boot.service 2>/dev/null || true)"
echo "VLAN service: $(systemctl is-active ucg-vlan99.service 2>/dev/null || true)"
echo
echo "============================================================"
UCG_VLAN99_INSTALL