GRE 隧道深度解析:从协议原理到生产实践

0 阅读5分钟

摘要:GRE(Generic Routing Encapsulation)是一种通用的三层隧道封装协议,广泛应用于多协议承载、组播传输和动态路由场景。本文将从 GRE 协议架构、报文格式、Keepalive 机制等维度进行深度解析,并提供完整的 Linux 生产环境配置实践。

关键词:GRE、隧道封装、路由协议、多协议承载


一、GRE 概述

1.1 什么是 GRE?

GRE(Generic Routing Encapsulation,通用路由封装)是由 Cisco 开发、IETF 标准化的隧道协议。RFC 2784(2000 年 3 月)是当前的标准文档,取代了早期的 RFC 1701(1994 年 10 月,已废弃)。RFC 2890(2000 年 9 月)增加了 Key 和序列号字段扩展。GRE 的核心思想是在一种网络层协议(如 IPv4)中封装另一种网络层协议(如 IPv6、IPX、AppleTalk 等)。

核心特性:

  • 📦 多协议承载:支持 IPv4、IPv6、IPX、AppleTalk、MPLS 等多种乘客协议
  • 🔄 组播支持:原生支持组播流量传输(IPSec 不支持)
  • 🛣️ 动态路由:可在隧道上运行 OSPF、EIGRP、BGP 等动态路由协议
  • 🔐 无加密:GRE 本身不提供加密,常与 IPSec 结合使用(GRE over IPSec)

1.2 GRE vs IPSec vs L2TP

特性GREIPSecL2TP/IPSec
OSI 层级第 3 层第 3 层第 2 层
加密能力❌ 无✅ 有✅ 有
组播支持✅ 支持❌ 不支持❌ 不支持
动态路由✅ 支持⚠️ 有限支持❌ 不支持
多协议承载✅ 支持❌ 仅 IP✅ 支持(PPP)
典型应用站点互联、组播传输安全 VPN远程接入

1.3 应用场景

场景类型典型应用GRE 优势
多协议网络IPv6 over IPv4 隧道原生支持多种乘客协议
组播传输视频会议、IPTV 跨网传输唯一支持组播的隧道协议
动态路由OSPF/BGP over Tunnel隧道接口支持路由协议邻居建立
数据中心互联DCI(Data Center Interconnect)低开销、高性能
混合云组网私有云 - 公有云互联简单配置、广泛支持

⚠️ 注意:GRE 不提供加密和认证,敏感数据传输需配合 IPSec 使用(GRE over IPSec)。


二、GRE 协议架构

2.1 协议栈位置

GRE 协议栈架构

2.2 GRE 报文格式(RFC 2784)

GRE 报文封装结构

2.3 头部字段详解

字段长度含义
C (Checksum Present)1 比特1=包含校验和字段
R (Routing Present)1 比特1=包含路由字段(必须为 0)
K (Key Present)1 比特1=包含 Key 字段
S (Sequence Number Present)1 比特1=包含序列号字段(RFC 2890)
s (Strict Source Route)1 比特严格源路由(必须为 0)
Recur3 比特递归控制(防止嵌套隧道环路)
Flags5 比特保留字段(必须为 0)
Ver3 比特版本号(必须为 0)
Protocol Type16 比特乘客协议类型(如 0x0800=IPv4, 0x86DD=IPv6)

2.4 可选字段说明

字段长度启用条件用途
Checksum4 字节C=1头部和数据校验
Offset4 字节C=1数据偏移(极少使用)
Key4 字节K=1标识隧道会话,防止 spoofing
Sequence Number4 字节S=1防止重放攻击,检测丢包
Routing可变R=1源路由(RFC 2784 规定必须为 0)

三、GRE 隧道建立机制

3.1 无状态隧道

GRE 是无状态协议,不需要显式的隧道建立过程:

GRE 无状态隧道建立流程

特点:

  • ✅ 配置简单,无需协商
  • ✅ 快速收敛,无握手延迟
  • ❌ 无连接状态检测,需依赖 Keepalive

3.2 Keepalive 机制

GRE 本身无 Keepalive,需依赖以下机制检测隧道状态:

方式 1:使用监控脚本(Linux 无原生 Keepalive)

# Linux iproute2 不支持 keepalive 参数(Cisco 语法)
# 使用监控脚本检测隧道状态

cat > /usr/local/bin/gre-monitor.sh <<'EOF'
#!/bin/bash
REMOTE_IP="10.0.0.2"
INTERFACE="gre0"

if ! ping -c 1 -W 2 "$REMOTE_IP" >/dev/null 2>&1; then
    echo "$(date): Tunnel $INTERFACE is down, restarting..." >> /var/log/gre-monitor.log
    ip link set "$INTERFACE" down
    sleep 5
    ip link set "$INTERFACE" up
fi
EOF

chmod +x /usr/local/bin/gre-monitor.sh

# 添加到 crontab(每分钟检测一次)
# 注意:crontab 最小单位是分钟,如需更频繁检测使用 systemd timer
* * * * * /usr/local/bin/gre-monitor.sh

# 或使用 systemd timer(推荐)
cat > /etc/systemd/system/gre-monitor.service <<EOF
[Unit]
Description=GRE Tunnel Monitor
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/gre-monitor.sh

[Install]
WantedBy=multi-user.target
EOF

cat > /etc/systemd/system/gre-monitor.timer <<EOF
[Unit]
Description=Run GRE Monitor every 30 seconds

[Timer]
OnBootSec=1min
OnUnitActiveSec=30s
Unit=gre-monitor.service

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable gre-monitor.timer
sudo systemctl start gre-monitor.timer

方式 2:使用 BFD(Bidirectional Forwarding Detection,推荐)

# 安装 FRR(BFD 功能已包含在主包中)
sudo apt-get install -y frr

# 配置 BFD 会话(毫秒级检测)
vtysh -c "configure terminal" \
      -c "bfd" \
      -c " peer 10.0.0.2" \
      -c "  no shutdown"

方式 3:依赖路由协议 Hello

# OSPF over GRE
# OSPF Hello 包可检测邻居状态
router ospf 1
 network 10.0.0.0 0.0.0.3 area 0
 ip ospf hello-interval 10
 ip ospf dead-interval 40

3.3 递归路由问题

问题描述:当隧道目的地址通过隧道本身可达时,会导致路由递归,隧道反复 up/down。

GRE 递归路由问题


四、GRE over IPSec 安全增强

4.1 为什么需要 GRE over IPSec?

需求GREIPSecGRE over IPSec
组播传输
动态路由⚠️
数据加密
完整性保护
身份认证

4.2 封装顺序

GRE over IPSec 有两种封装模式:

Tunnel Mode(隧道模式) Transport Mode(传输模式)

GRE over IPSec 封装模式对比

4.3 配置要点

# 关键配置原则
# 1. IPSec 保护 GRE 流量(协议 47)
# 2. GRE 隧道端点 = IPSec 隧道端点
# 3. 感兴趣流匹配 GRE 协议,而非乘客协议

# 错误配置示例(❌)
# 感兴趣流:10.0.0.0/24 → 192.168.0.0/24(乘客协议网段)

# 正确配置示例(✅)
# 感兴趣流:协议 47,源 1.1.1.1 → 目的 2.2.2.2(GRE 隧道端点)


五、生产环境配置实践

5.1 典型拓扑

GRE 隧道网络拓扑


5.2 【Linux】GRE 隧道配置

环境信息

角色公网 IP内网网段隧道 IP主机名
站点 A1.1.1.1192.168.1.0/2410.0.0.1/30site-a
站点 B2.2.2.2192.168.2.0/2410.0.0.2/30site-b

【站点 A】配置步骤

步骤 1:创建 GRE 隧道接口

# 创建 GRE 隧道接口
sudo ip tunnel add gre0 mode gre remote 2.2.2.2 local 1.1.1.1 ttl 255

# 启用接口
sudo ip link set gre0 up

# 配置隧道 IP 地址
sudo ip addr add 10.0.0.1/30 dev gre0

# 设置 MTU(建议值:1500 - 24 = 1476)
sudo ip link set gre0 mtu 1476

# 启用 Keepalive(可选,使用监控脚本)
# 参考 3.2 节 Keepalive 配置

步骤 2:配置路由

# 添加静态路由(通过隧道访问对端内网)
sudo ip route add 192.168.2.0/24 dev gre0

# 或者添加默认路由(所有流量走隧道)
# sudo ip route add 0.0.0.0/0 dev gre0

# 确保隧道目的地址通过物理接口可达(防止递归路由)
sudo ip route add 2.2.2.2/32 dev eth0

步骤 3:配置防火墙

# 放行 GRE 协议(IP 协议 47)
sudo iptables -A INPUT -p gre -s 2.2.2.2 -j ACCEPT
sudo iptables -A OUTPUT -p gre -d 2.2.2.2 -j ACCEPT

# 如果使用 GRE over IPSec
sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT
sudo iptables -A INPUT -p esp -j ACCEPT

# 启用 IP 转发
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

步骤 4:验证隧道状态

# 查看隧道接口
ip -d link show gre0

# 查看接口状态
ip addr show gre0

# 查看路由表
ip route show

# 测试连通性
ping -I gre0 10.0.0.2
ping -I gre0 192.168.2.1

# 抓包验证(在 eth0 上抓 GRE 包)
sudo tcpdump -i eth0 -n proto 47


【站点 B】配置步骤

# 创建 GRE 隧道接口
sudo ip tunnel add gre0 mode gre remote 1.1.1.1 local 2.2.2.2 ttl 255
sudo ip link set gre0 up
sudo ip addr add 10.0.0.2/30 dev gre0
sudo ip link set gre0 mtu 1476
# Keepalive 使用监控脚本,参考 3.2 节

# 配置路由
sudo ip route add 192.168.1.0/24 dev gre0
sudo ip route add 1.1.1.1/32 dev eth0

# 配置防火墙
sudo iptables -A INPUT -p 47 -s 1.1.1.1 -j ACCEPT
sudo iptables -A OUTPUT -p 47 -d 1.1.1.1 -j ACCEPT

# 启用 IP 转发
sudo sysctl -w net.ipv4.ip_forward=1


5.3 【持久化配置】(Ubuntu/Debian)

创建网络配置文件:

# /etc/network/interfaces.d/gre0
auto gre0
iface gre0 inet tunnel
    mode gre
    endpoint 2.2.2.2
    local 1.1.1.1
    ttl 255
    address 10.0.0.1
    netmask 255.255.255.252
    mtu 1476
    pointopoint 10.0.0.2

或使用 systemd-networkd:

# /etc/systemd/network/10-gre0.netdev
[NetDev]
Name=gre0
Kind=gre
MTUBytes=1476

[Tunnel]
Local=1.1.1.1
Remote=2.2.2.2
TTL=255

# /etc/systemd/network/10-gre0.network
[Match]
Name=gre0

[Network]
Address=10.0.0.1/30
Peer=10.0.0.2


5.4 【GRE over IPSec】完整配置

步骤 1:配置 GRE 隧道(同上)

# 站点 A
sudo ip tunnel add gre0 mode gre remote 2.2.2.2 local 1.1.1.1 ttl 255
sudo ip link set gre0 up
sudo ip addr add 10.0.0.1/30 dev gre0

步骤 2:配置 IPSec(strongSwan)

# /etc/ipsec.conf - 站点 A
config setup
    charondebug="ike 2, knl 2, cfg 2"
    uniqueids=never

conn gre-ipsec
    type=transport
    keyexchange=ikev2
    authby=secret
    
    # 隧道端点(与 GRE 端点一致)
    left=1.1.1.1
    right=2.2.2.2
    
    # 保护 GRE 流量(协议 47)
    leftprotoport=47
    rightprotoport=47
    
    # 加密算法
    ike=aes256gcm16-prfsha256-ecp256!
    esp=aes256gcm16-ecp256!
    
    # 生命周期
    ikelifetime=8h
    lifetime=1h
    
    # 自动启动
    auto=start

# /etc/ipsec.secrets
1.1.1.1 2.2.2.2 : PSK "GREoverIPSec@StrongKey2025!"

步骤 3:启动 IPSec

# 重启 strongSwan
sudo ipsec restart

# 查看状态
sudo ipsec status
sudo ipsec statusall

# 验证 GRE 流量是否被加密
sudo tcpdump -i eth0 -n host 2.2.2.2
# 应该看到 ESP 包,而非明文 GRE 包


六、性能优化建议

6.1 MTU 优化

GRE 封装会增加额外开销:

  • 外层 IP 头:20 字节
  • GRE 头部:4 字节(基础),启用 Key/Sequence 后可达 12-16 字节
# 推荐 MTU 设置
# 物理接口 MTU 1500 - GRE 开销 24 = 1476

sudo ip link set gre0 mtu 1476

# 如果使用 GRE over IPSec
# 物理接口 MTU 1500 - IPSec(50-73) - GRE(24) ≈ 1400
sudo ip link set gre0 mtu 1400

MTU 问题诊断
# 测试 MTU(通过隧道接口发送,需扣除 IP+ICMP 头 28 字节)
# 纯 GRE 场景:MTU 1476 → ICMP payload = 1476 - 28 = 1448
ping -M do -s 1448 10.0.0.2
# GRE over IPSec 场景:MTU 1400 → ICMP payload = 1400 - 28 = 1372
ping -M do -s 1372 10.0.0.2

# 查看分片统计
netstat -s | grep -i fragment

6.2 多队列优化(多核 CPU)

# 启用多队列(需要内核支持)
sudo ip link set gre0 numtxqueues 4
sudo ip link set gre0 txqueuelen 1000

# 查看队列统计
ethtool -S gre0

6.3 路由优化

# 使用策略路由(多隧道场景)
ip rule add from 192.168.1.0/24 table 100
ip route add default via 10.0.0.2 dev gre0 table 100

# 启用 ECMP(等价多路径)
ip route add 192.168.2.0/24 \
    nexthop via 10.0.0.2 dev gre0 weight 1 \
    nexthop via 10.0.0.6 dev gre1 weight 1

6.4 Keepalive 调优

# 快速故障检测(毫秒级)
# Linux iproute2 不支持 keepalive 参数(Cisco 语法)
# 请使用 3.2 节的监控脚本或 BFD 方案

# 保守配置(低带宽链路)
# Linux iproute2 不支持 keepalive 参数(Cisco 语法)
# 请使用 3.2 节的监控脚本或 BFD 方案


七、故障排查

7.1 常见故障及解决方案

故障 1:隧道接口 up 但无法 ping 通

可能原因
  • 路由未配置
  • 防火墙阻止 GRE 协议
  • 对端未配置
排查步骤
# 1. 检查接口状态
ip -d link show gre0
# 应显示:gre0: <POINTOPOINT,UP,LOWER_UP>

# 2. 检查路由
ip route show | grep gre0

# 3. 检查防火墙
sudo iptables -L -n -v | grep 47

# 4. 抓包验证
sudo tcpdump -i eth0 -n proto 47

故障 2:隧道反复 up/down

可能原因
  • Keepalive 超时
  • 路由递归
  • 网络不稳定
解决方案
# 调整 Keepalive
# Linux iproute2 不支持 keepalive 参数(Cisco 语法)
# 请使用 3.2 节的监控脚本或 BFD 方案

# 检查路由递归
ip route get 2.2.2.2
# 应显示通过物理接口,而非 gre0

# 添加主机路由
sudo ip route add 2.2.2.2/32 dev eth0

故障 3:GRE over IPSec 不通

可能原因
  • IPSec SA 未建立
  • 感兴趣流配置错误
  • NAT 设备阻止
排查步骤
# 1. 检查 IPSec 状态
sudo ipsec status

# 2. 检查感兴趣流
# 应匹配协议 47,而非乘客协议
grep -A 10 "conn gre-ipsec" /etc/ipsec.conf

# 3. 检查 NAT 穿越
sudo ipsec statusall | grep NAT

7.2 诊断命令汇总

# ==================== 接口状态 ====================
ip -d link show gre0          # 查看隧道详情
ip addr show gre0             # 查看 IP 地址
ethtool -S gre0               # 查看统计信息

# ==================== 路由检查 ====================
ip route show                 # 查看路由表
ip route get 192.168.2.1      # 检查特定路由
ip route show table all       # 查看所有路由表

# ==================== 抓包分析 ====================
# 物理接口抓包(查看 GRE 包)
sudo tcpdump -i eth0 -n proto 47

# 隧道接口抓包(查看乘客协议包)
sudo tcpdump -i gre0 -n

# 详细抓包(解码 GRE)
sudo tcpdump -i eth0 -n -vv proto 47

# ==================== IPSec 检查 ====================
sudo ipsec status             # 查看 SA 状态
sudo ipsec trafficstatus      # 查看流量统计
sudo cat /var/log/charon.log  # 查看日志

# ==================== 性能测试 ====================
# 带宽测试
iperf3 -c 10.0.0.2 -t 60

# 延迟测试
ping -c 100 10.0.0.2

# MTU 测试
ping -M do -s 1448 10.0.0.2  # 1448+28=1476(纯 GRE 场景)


八、高级应用场景

8.1 动态路由 over GRE(OSPF 示例)

# 站点 A - OSPF 配置(使用 FRR)
sudo apt-get install -y frr frr-pythontools

# /etc/frr/ospfd.conf
router ospf
 router-id 1.1.1.1
 network 10.0.0.0/30 area 0.0.0.0
 network 192.168.1.0/24 area 0.0.0.0
 passive-interface eth0
!

# 站点 B - OSPF 配置
# /etc/frr/ospfd.conf
router ospf
 router-id 2.2.2.2
 network 10.0.0.0/30 area 0.0.0.0
 network 192.168.2.0/24 area 0.0.0.0
 passive-interface eth0
!

# 重启 FRR 服务
sudo systemctl restart frr

# 验证 OSPF 邻居
vtysh -c "show ip ospf neighbor"

# 查看 OSPF 路由
vtysh -c "show ip route ospf"

8.2 组播传输 over GRE

# GRE 原生支持组播,无需特殊配置

# 1. 启用组播路由
sudo sysctl -w net.ipv4.conf.all.mc_forwarding=1

# 2. 配置 PIM-SM(协议无关组播)
# /etc/frr/pimd.conf
ip pim rp-address 192.168.1.1
interface gre0
 ip pim sm
!
interface eth0
 ip pim sm
!

# 3. 验证组播
show ip mroute
show ip pim neighbor

8.3 多隧道负载均衡

# 创建多个 GRE 隧道
sudo ip tunnel add gre0 mode gre remote 2.2.2.2 local 1.1.1.1
sudo ip tunnel add gre1 mode gre remote 2.2.2.3 local 1.1.1.2

# 配置 ECMP 路由
sudo ip route add 192.168.2.0/24 \
    nexthop via 10.0.0.2 dev gre0 weight 1 \
    nexthop via 10.0.0.6 dev gre1 weight 1

# 验证负载均衡
watch -n1 'ip -s link show gre0; ip -s link show gre1'


九、安全加固建议

9.1 基础安全措施

# 限制 GRE 源地址
sudo iptables -A INPUT -p gre -s 2.2.2.2 -j ACCEPT
sudo iptables -A INPUT -p gre -j DROP

# 启用反向路径过滤
sudo sysctl -w net.ipv4.conf.all.rp_filter=1
sudo sysctl -w net.ipv4.conf.default.rp_filter=1

# 限制 ICMP 重定向
sudo sysctl -w net.ipv4.conf.all.accept_redirects=0

9.2 GRE over IPSec 最佳实践

# /etc/ipsec.conf
conn gre-ipsec
    # 使用 IKEv2
    keyexchange=ikev2
    
    # 强加密算法
    ike=aes256gcm16-prfsha256-ecp256!
    esp=aes256gcm16-ecp256!
    
    # 启用 PFS
    dpdaction=clear
    rekey=yes
    
    # 严格模式
    leftfirewall=yes
    installpolicy=yes

9.3 监控与告警

# 监控隧道状态
#!/bin/bash
# /usr/local/bin/gre-monitor.sh

INTERFACE="gre0"
# 注意:GRE 隧道接口的 ip link state 通常为 UNKNOWN,
# 应检查 flags 中的 UP 标志以及连通性
if ! ip link show "$INTERFACE" | grep -q '<.*UP.*>'; then
    echo "ALERT: GRE tunnel $INTERFACE is DOWN" | \
        mail -s "GRE Tunnel Alert" admin@example.com
elif ! ping -c 1 -W 2 10.0.0.2 >/dev/null 2>&1; then
    echo "ALERT: GRE tunnel $INTERFACE has no connectivity" | \
        mail -s "GRE Tunnel Alert" admin@example.com
fi

# 添加到 crontab
# */5 * * * * /usr/local/bin/gre-monitor.sh


十、常见问题 FAQ

Q1: GRE 和 IPIP 有什么区别?

特性GREIPIP
协议号474
多协议支持❌(仅 IPv4)
组播支持
头部开销24 字节20 字节
推荐场景多协议、组播简单 IPv4 over IPv4

Q2: 为什么 GRE 支持组播而 IPSec 不支持?

原因:IPSec 的 SA 是点对点的,组播地址无法建立 SA。GRE 无状态,直接封装组播包即可传输。

解决方案:GRE over IPSec,由 GRE 承载组播,IPSec 提供加密。

Q3: GRE 隧道 MTU 如何计算?

GRE MTU 计算

Q4: 如何排查 GRE 隧道性能问题?

# 1. 检查丢包
ip -s link show gre0

# 2. 检查 CPU 使用率
top -p $(pgrep -f 'gre0')

# 3. 带宽测试
iperf3 -c 10.0.0.2 -t 60 -P 4

# 4. 检查中断分布
cat /proc/interrupts | grep gre0

Q5: GRE 还是 VXLAN/Geneve?

特性GREVXLANGeneve
标准RFC 2784RFC 7348RFC 8926
开销24 字节50 字节可变
VNI 支持✅ (24 位)✅ (24 位)
扩展性
推荐场景传统 VPN数据中心 Overlay新一代 Overlay

十一、总结

GRE 作为一种简单、高效的三层隧道协议,在多协议承载、组播传输和动态路由场景下仍具有不可替代的优势。

核心要点回顾:

  1. 无状态协议:配置简单,无需协商,快速收敛
  2. 多协议支持:IPv4、IPv6、IPX、MPLS 等
  3. 组播传输:唯一支持组播的隧道协议
  4. 动态路由:支持 OSPF、BGP 等路由协议
  5. 安全增强:配合 IPSec 实现加密(GRE over IPSec)

适用场景:

  • ✅ 多协议网络互联
  • ✅ 组播流量跨网传输
  • ✅ 需要动态路由的站点互联
  • ✅ 数据中心 Overlay 网络
  • ⚠️ 敏感数据传输需配合 IPSec

随着 VXLAN、Geneve 等新一代 Overlay 协议的兴起,GRE 在数据中心场景的应用有所减少,但在传统企业网络和组播传输领域仍是首选方案。


参考文献

  1. RFC 2784 - Generic Routing Encapsulation (GRE)
  2. RFC 2890 - Key and Sequence Number Extensions to GRE
  3. RFC 1701 - Generic Routing Encapsulation
  4. Linux IP Tunneling HOWTO
  5. strongSwan Documentation