一、简介
适用设备:GL-XE300 路由器 / OpenWrt 系统
OpenWrt 版本:OpenWrt 22.03.4
目标:在 OpenWrt 设备上完成 GRE 隧道配置,实现 4G/5G 多链路主备。
版本限制说明
该固件存在以下限制,需采用特殊方案绕开:
最终方案:Shell 脚本(/etc/init.d/gre-*)管理隧道创建与路由,UCI 管理防火墙,rc.local 实现开机自启。
二、基本配置
2.1 基本参数
2.2 配置静态 IP
登录路由器管理面板,找到【互联网】>【以太网】配置项,填入专线提供的网络参数:
静态 IP:120.236.136.227
掩码:255.255.255.248
网关:120.236.136.225
DNS:211.136.192.6
验证外网连通性(手机/电脑连接路由器 WiFi,访问 https://ip.sb 或搜索"IP"),显示为 120.236.136.227 即配置成功。
2.3 IP 转发
OpenWrt 默认已启用,确认即可:
# 应返回 1
cat /proc/sys/net/ipv4/ip_forward若返回 0,执行:
# 若返回 0, 执行:
echo 1 > /proc/sys/net/ipv4/ip_forward
uci set network.globals.ip_forward=1 && uci commit network2.4 防火墙:放行 GRE 协议
临时放行(重启后失效):
# 放行 GRE 协议(在输入链)
nft add rule inet fw4 input meta l4proto gre accept
# 查看规则
nft list ruleset | grep -A5 -B5 greUCI 持久化:
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-GRE'
uci set firewall.@rule[-1].proto='gre'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].target='ACCEPT'
uci commit firewall
/etc/init.d/firewall restart验证:
uci show firewall | grep -A5 "Allow-GRE"删除规则(扩展):
uci delete firewall.@rule[13] 2>/dev/null # 序号以 uci show 输出为准
uci commit firewall && /etc/init.d/firewall restart2.5 防火墙:放行 ICMP(可选,用于排障)
临时放行(重启后失效):
nft insert rule inet fw4 input_wan meta l4proto icmp accept
# 查看 input_wan 链
nft list chain inet fw4 input_wan | grep icmpUCI 持久化:
uci set firewall.allow_ping=rule
uci set firewall.allow_ping.name='Allow-Ping-WAN'
uci set firewall.allow_ping.proto='icmp'
uci set firewall.allow_ping.src='wan'
uci set firewall.allow_ping.target='ACCEPT'
uci commit firewall && /etc/init.d/firewall restart验证:
uci show firewall.allow_ping
uci show firewall | grep -A5 "allow_ping"
# 从手机 Termux 或外部机器 ping 专线 IP(使用外部网络)
ping -c 3 -W 2 120.236.136.227三、GRE 隧道部署
3.1 加载 GRE 内核模块
# 确认 GRE 模块是否已加载
lsmod | grep gre
# 已加载的输出:gre 2552 1 ip_gre
# 如果没有输出,执行加载
modprobe ip_gre
# 提示没有设备,则安装模块
opkg update
opkg list | grep -i gre # 查看有没有 GRE 的包
opkg install kmod-gre3.2 创建模板脚本
GRE 隧道和路由通过 Shell 脚本 统一管理(非 netifd 方式)
cat > /root/gre-template << 'EOF'
#!/bin/sh
NAME="gre-xxx" # 隧道名称(唯一)
LOCAL_IP="120.236.136.227" # 本端物理 IP(所有隧道共用)
REMOTE_IP="183.235.54.118" # 对端物理 IP
TUNNEL_IP="10.250.0.2/30" # 本端隧道 IP
PEER_IP="10.250.0.1" # 对端隧道 IP
ROUTE_NET="10.60.0.0/19" # 目标网段
METRIC="100" # 路由优先级
case "$1" in
start)
logger -t "$NAME" "Starting GRE tunnel..."
# Wait for local IP to be ready (max 60 seconds)
retry=0
while ! ip addr show | grep -q "$LOCAL_IP" && [ $retry -lt 60 ]; do
sleep 1
retry=$((retry + 1))
done
if ! ip addr show | grep -q "$LOCAL_IP"; then
logger -t "$NAME" "ERROR: Local IP $LOCAL_IP not found, aborting"
exit 1
fi
logger -t "$NAME" "Local IP $LOCAL_IP found, creating tunnel..."
# Load GRE kernel module
modprobe ip_gre 2>/dev/null
# Remove existing tunnel if present
ip tunnel del "$NAME" 2>/dev/null
# Create GRE tunnel
ip tunnel add "$NAME" mode gre remote $REMOTE_IP local $LOCAL_IP ttl 255
# Assign tunnel IP
ip addr add "$TUNNEL_IP" dev "$NAME"
# Bring tunnel up
ip link set "$NAME" up mtu 1400
# Add or replace route (Does not impact other metric routes)
ip route replace "$ROUTE_NET" via $PEER_IP dev "$NAME" metric "$METRIC" table main 2>/dev/null
if ip link show "$NAME" > /dev/null 2>&1; then
logger -t "$NAME" "GRE tunnel started"
else
logger -t "$NAME" "GRE tunnel failed"
exit 1
fi
;;
stop)
ip route del "$ROUTE_NET" 2>/dev/null
ip link set "$NAME" down 2>/dev/null
ip tunnel del "$NAME" 2>/dev/null
logger -t "$NAME" "GRE tunnel removed"
;;
status)
if ip link show "$NAME" > /dev/null 2>&1; then
echo "✅ $NAME is UP"
echo ""
ip link show "$NAME" | grep -E "mtu|state"
echo ""
ip addr show "$NAME" | grep inet
echo ""
if ip route show | grep -q "$ROUTE_NET"; then
ip route show | grep "$ROUTE_NET"
else
echo "⚠️ Route $ROUTE_NET not found"
fi
else
echo "❌ $NAME is DOWN or does not exist"
fi
;;
*)
echo "Usage: $0 {start|stop|status}"
exit 1
;;
esac
EOF⚠️ 脚本编写注意事项:不要使用 Tab 缩进,用空格。Tab 会被 Shell 解析为指令补全,导致命令异常中断。变量值建议使用双引号包裹,防止含空格/特殊字符时被意外拆分。
3.3 基于模板生成各隧道脚本
# 4G 主隧道
cp /root/gre-template /etc/init.d/gre-4g-main
sed -i 's/NAME="gre-xxx"/NAME="gre-4g-main"/' /etc/init.d/gre-4g-main
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.116"/' /etc/init.d/gre-4g-main
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.250.0.10\/30"/' /etc/init.d/gre-4g-main
sed -i 's/PEER_IP=".*"/PEER_IP="10.250.0.9"/' /etc/init.d/gre-4g-main
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="10.60.32.0\/19"/' /etc/init.d/gre-4g-main
sed -i 's/METRIC=".*"/METRIC="100"/' /etc/init.d/gre-4g-main
# 4G 备用隧道
cp /root/gre-template /etc/init.d/gre-4g-backup
sed -i 's/NAME="gre-xxx"/NAME="gre-4g-backup"/' /etc/init.d/gre-4g-backup
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.118"/' /etc/init.d/gre-4g-backup
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.250.0.2\/30"/' /etc/init.d/gre-4g-backup
sed -i 's/PEER_IP=".*"/PEER_IP="10.250.0.1"/' /etc/init.d/gre-4g-backup
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="10.60.0.0\/19"/' /etc/init.d/gre-4g-backup
sed -i 's/METRIC=".*"/METRIC="200"/' /etc/init.d/gre-4g-backup
# 5G 主隧道
cp /root/gre-template /etc/init.d/gre-5g-main
sed -i 's/NAME="gre-xxx"/NAME="gre-5g-main"/' /etc/init.d/gre-5g-main
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.68"/' /etc/init.d/gre-5g-main
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.2.1.10\/30"/' /etc/init.d/gre-5g-main
sed -i 's/PEER_IP=".*"/PEER_IP="10.2.1.9"/' /etc/init.d/gre-5g-main
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="172.16.2.0\/24"/' /etc/init.d/gre-5g-main
sed -i 's/METRIC=".*"/METRIC="100"/' /etc/init.d/gre-5g-main
# 5G 备用隧道
cp /root/gre-template /etc/init.d/gre-5g-backup
sed -i 's/NAME="gre-xxx"/NAME="gre-5g-backup"/' /etc/init.d/gre-5g-backup
sed -i 's/REMOTE_IP=".*"/REMOTE_IP="183.235.54.72"/' /etc/init.d/gre-5g-backup
sed -i 's/TUNNEL_IP=".*"/TUNNEL_IP="10.4.1.10\/30"/' /etc/init.d/gre-5g-backup
sed -i 's/PEER_IP=".*"/PEER_IP="10.4.1.9"/' /etc/init.d/gre-5g-backup
sed -i 's/ROUTE_NET=".*"/ROUTE_NET="172.16.2.0\/24"/' /etc/init.d/gre-5g-backup
sed -i 's/METRIC=".*"/METRIC="200"/' /etc/init.d/gre-5g-backup
# 设置执行权限
chmod +x /etc/init.d/gre-*3.4 开机自启
编辑 /etc/rc.local,在 exit 0 前添加:
# Start all GRE tunnels in background (parallel execution)
/etc/init.d/gre-4g-main start &
/etc/init.d/gre-4g-backup start &
/etc/init.d/gre-5g-main start &
/etc/init.d/gre-5g-backup start &批量启停和状态查看:
# 启动所有
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 start'
# 停止所有
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 stop'
# 查看所有状态
ls /etc/init.d/gre-* | xargs -n1 -r sh -c '$0 status'四、验证
4.1 命令验证
# 1. 查看隧道接口状态
ip link show gre-4g-main
ip addr show gre-4g-main
# 2. 查看路由是否添加成功
ip route show | grep -E "10.60|172.16.2"
# 3. 测试隧道对端 IP
ping -c 3 10.250.0.1
# 4. 测试目标网段(终端需开机)
ping -c 3 10.60.0.1
# 5. 查看脚本日志(logger 打印的内存轮转日志)
logread | grep gre-4g-main | tail -20
# 6. 持久化验证:重启后重复上述命令
reboot4.2 自动检测脚本
保存以下内容为 /root/check_gre.sh 并赋予执行权限(chmod +x):
#!/bin/sh
LOCAL_IP="120.236.136.227"
echo "===== GRE Tunnel Health Check ====="
echo ""
# 1. 检查本地IP是否存在
echo "[1] Local IP Check"
if ip addr show | grep -q "$LOCAL_IP"; then
echo " ✅ $LOCAL_IP found"
else
echo " ❌ $LOCAL_IP not found, aborting"
exit 1
fi
echo ""
# 2. 路由检测函数
check_route() {
local net=$1
printf " %-20s " "$net"
if ip route show | grep -q "$net"; then
echo "✅ FOUND"
ip route show | grep "$net" | head -1
else
echo "❌ NOT FOUND"
fi
}
echo "[2] Static Routes Check"
check_route "10.60.0.0/19"
check_route "10.60.32.0/19"
check_route "172.16.2.0/24"
echo ""
# 3. GRE隧道连通性检测
echo "[3] GRE Tunnel Connectivity"
echo " (ping -c 3 -W 2)"
check_ping() {
local ip=$1
printf " %-16s " "$ip"
if ping -c 3 -W 2 "$ip" > /dev/null 2>&1; then
echo "✅ OK"
else
echo "❌ FAILED"
fi
}
# GRE远端IP(公网)
echo ""
echo " --- Remote Public IPs ---"
for ip in 183.235.54.118 183.235.54.116 183.235.54.68 183.235.54.72; do
check_ping "$ip"
done
# GRE隧道内网IP
echo ""
echo " --- Tunnel Internal IPs ---"
for ip in 10.250.0.1 10.250.0.9 10.2.1.9 10.4.1.9; do
check_ping "$ip"
done
echo ""
echo "===== Check Completed ====="五、内网互访验证
详见:《GRE 隧道转发与抓包分析》
六、附录
6.1 Win11 放行 ICMP(测试专线静态 IP 连通性)
本机(Win11)直连光猫时,需放行 ICMP 入站规则,才能从外部(如手机 Termux)ping 通专线静态 IP 120.236.136.227,用于验证物理链路是否正常。
操作步骤:
按下 Win + R 键,输入 wf.msc,然后按回车,打开 高级安全 Windows Defender 防火墙
左侧导航栏单击 入站规则
右侧操作面板单击 按组筛选 -> 选择 【核心网络诊断】
找到 ICMPv4 入站规则,右键单击远程地址为 任何 的那条规则,选择 启用规则
右键单击远程地址为 【任何】 的那条规则,然后选择 【启用规则】。
右键 属性 → 高级 → 勾选 专用、公用 → 确定


6.2 备选方案:标准 init 脚本
除正文提到的 Shell + rc.local 方案外,也可使用 OpenWrt 标准 init 脚本(USE_PROCD=0 + start_service())实现开机自启。
💡 两种方案选其一即可。init 脚本方案管理更规范(支持 enable/disable),Shell + rc.local 方案更直观。本手册以 Shell + rc.local 方案为主,init 脚本方案供参考。
OpenWrt init 脚本机制简介:
START=99:启动顺序,数字越大越晚执行
USE_PROCD=0:非守护进程模式,需使用 start_service()/stop_service() 函数
/etc/init.d/<脚本> enable:在 /etc/rc.d/ 下创建 S99<脚本> 符号链接,开机自动执行
cat > /etc/init.d/gre-4g-main << 'EOF'
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=0
NAME="gre-4g-main"
LOCAL_IP="120.236.136.227"
REMOTE_IP="183.235.54.116"
TUNNEL_IP="10.250.0.10/30"
PEER_IP="10.250.0.9"
ROUTE_NET="10.60.32.0/19"
METRIC="100"
start_service() {
logger -t "$NAME" "Starting GRE tunnel..."
# 等待本地 IP 就绪
retry=0
while ! ip addr show | grep -q "$LOCAL_IP" && [ $retry -lt 30 ]; do
sleep 1
retry=$((retry + 1))
done
modprobe ip_gre 2>/dev/null
ip tunnel del "$NAME" 2>/dev/null
ip tunnel add "$NAME" mode gre remote $REMOTE_IP local $LOCAL_IP ttl 255
ip addr add "$TUNNEL_IP" dev "$NAME"
ip link set "$NAME" up mtu 1400
ip route replace "$ROUTE_NET" via $PEER_IP dev "$NAME" metric "$METRIC" 2>/dev/null
if ip link show "$NAME" > /dev/null 2>&1; then
logger -t "$NAME" "GRE tunnel started"
else
logger -t "$NAME" "GRE tunnel failed"
fi
}
stop_service() {
ip route del "$ROUTE_NET" 2>/dev/null
ip link set "$NAME" down 2>/dev/null
ip tunnel del "$NAME" 2>/dev/null
logger -t "$NAME" "GRE tunnel removed"
}
status_service() {
if ip link show "$NAME" > /dev/null 2>&1; then
echo "✅ $NAME is UP"
ip link show "$NAME" | grep -E "mtu|state"
ip addr show "$NAME" | grep inet
ip route show | grep "$ROUTE_NET" || echo "⚠️ Route not found"
else
echo "❌ $NAME is DOWN"
fi
}
EOF
chmod +x /etc/init.d/gre-4g-main
# 启用开机自启
/etc/init.d/gre-4g-main enable
# 手动管理
/etc/init.d/gre-4g-main start
/etc/init.d/gre-4g-main stop
/etc/init.d/gre-4g-main status6.3 废弃:/etc/config/network 方式
因精简版固件缺少 /lib/netifd/proto/gre.sh 协议脚本,netifd 无法处理 proto 'gre' 配置,以下配置无效,仅作记录。
vi /etc/config/network
# 在文件末尾添加:
config interface 'gre_pgw1'
option proto 'tunnel'
option tunnel 'gre'
option remote '183.235.54.118'
option local '120.236.136.227'
option mtu '1400'
option ipaddr '10.250.0.2'
option peeraddr '10.250.0.1'
option metric '100'
# 保存后,重启网络测试:
/etc/init.d/network restart