1 問題表現
SNAT 下,使用 keepalived 做雙機熱備,會出現了 ip 衝突的 問題。
2 網絡拓撲
2.1 主機 FW1 的配置:
2.1.1 主機的 iptables 配置
將所有 192.168.8.0/24,地址轉換爲出口 ip 10.10.10.254。
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j SNAT --to-source 10.10.10.254
2.1.2 主機的 keepalived.conf 配置
vrrp_group | mcast_src_ip |
虛擬 ip |
---|---|---|
VI_1 | 10.101.101.1/24 | 10.10.10.254/24 |
VI_2 | 192.168.8.1/24 | 192.168.8.254/24 |
! Configuration File for keepalived
global_defs {
vrrp_sync_group G1{
group{
VI_1
VI_2
}
}
router_id localhost.localdomain
}
vrrp_instance VI_1 {
state BACKUP
interface vEth0
track_interface {
vEth0
vEth1
}
mcast_src_ip 10.101.101.1
virtual_router_id 10
priority 200
advert_int 3
virtual_ipaddress {
10.10.10.254/24
}
}
vrrp_instance VI_2 {
state BACKUP
interface vEth1
track_interface {
vEth0
vEth1
}
mcast_src_ip 192.168.8.1
virtual_router_id 20
priority 200
advert_int 3
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.8.254/24
}
}
2.2 備機 FW2 的配置:
2.2.1 備機 的 iptables 配置
將所有 192.168.8.0/24,地址轉換爲出口 ip 10.10.10.254。
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j SNAT --to-source 10.10.10.254
2.2.2 備機的 keepalived.conf 配置
vrrp_group | mcast_src_ip |
虛擬 ip |
---|---|---|
VI_1 | 10.101.101.2/24 | 10.10.10.254/24 |
VI_2 | 192.168.8.2/24 | 192.168.8.254/24 |
! Configuration File for keepalived
global_defs {
vrrp_sync_group G1{
group{
VI_1
VI_2
}
}
router_id localhost.localdomain
}
vrrp_instance VI_1 {
state BACKUP
interface vEth0
track_interface {
vEth0
vEth1
}
mcast_src_ip 10.101.101.2
virtual_router_id 10
priority 100
advert_int 3
virtual_ipaddress {
10.10.10.254/24
}
}
vrrp_instance VI_2 {
state BACKUP
interface vEth1
track_interface {
vEth0
vEth1
}
mcast_src_ip 192.168.8.2
virtual_router_id 20
priority 100
advert_int 3
virtual_ipaddress {
192.168.8.254/24
}
}
3 故障重現
- 拔出主機的 vEth0 口的網線。等待主機上的 虛擬ip地址,遷移到備機。
- 插上主機的 vEth0 口的網線。等待備機上的 虛擬ip地址,遷移回主機。
- 查看 備機上的 ip。發現 vEth1 口的 虛擬ip地址 (192.168.8.254/24)沒有完全刪除。造成 ip 衝突。
3.1 主機 ip 查看結果
ip address show
> 8: vEth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
> link/ether 00:10:f3:51:40:2e brd ff:ff:ff:ff:ff:ff
> inet 10.101.101.1/24 scope global vEth0
> valid_lft forever preferred_lft forever
> inet 10.10.10.254/24 scope global vEth0
> valid_lft forever preferred_lft forever
> inet6 fe80::210:f3ff:fe51:402e/64 scope link
> valid_lft forever preferred_lft forever
> 9: vEth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
> link/ether 00:10:f3:51:40:2f brd ff:ff:ff:ff:ff:ff
> inet 192.168.8.1/24 scope global vEth1
> valid_lft forever preferred_lft forever
> inet 192.168.8.254/24 scope global secondary vEth1 # <-- 主機機的 虛擬ip
> ^^^^^^^^^^^^^^^^
> valid_lft forever preferred_lft forever
> inet6 fe80::210:f3ff:fe51:402f/64 scope link
> valid_lft forever preferred_lft forever
3.2 備機 ip 查看結果
ip address show
16: vEth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:10:f3:66:20:0b brd ff:ff:ff:ff:ff:ff
inet 10.101.101.2/24 scope global vEth0
valid_lft forever preferred_lft forever
inet6 fe80::210:f3ff:fe66:200b/64 scope link
valid_lft forever preferred_lft forever
17: vEth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:10:f3:66:20:0c brd ff:ff:ff:ff:ff:ff
inet 192.168.8.2/24 scope global vEth1
valid_lft forever preferred_lft forever
inet 192.168.8.254/24 scope global secondary vEth1 # <-- 備機的 虛擬ip 沒有完全刪除,造成 ip 衝突。
^^^^^^^^^^^^^^^^
valid_lft forever preferred_lft forever
inet6 fe80::210:f3ff:fe66:200c/64 scope link
valid_lft forever preferred_lft forever
4 問題分析
爲了分析故障的原因。使用 tcpdump 查看 vrrp 報文。
tcpdump -nn -i any vrrp
> tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
> listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
> 19:54:11.106503 IP 10.10.10.254 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^^ abnormal, should be 192.168.8.1
> 19:54:12.105473 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
> 19:54:14.107528 IP 10.10.10.254 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^^ abnormal, should be 192.168.8.1
> 19:54:15.106532 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
> 19:54:17.108558 IP 10.10.10.254 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^^ abnormal, should be 192.168.8.1
> 19:54:18.107585 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
> 19:54:20.109579 IP 10.10.10.254 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^^ abnormal, should be 192.168.8.1
> 19:54:21.108639 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
上述報文有問題如下:
- 從 192.168.8.1 發送出來的 vrrp 報文。其中的源地址,因爲 SNAT 的原因 (
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j SNAT --to-source 10.10.10.254
),都變換爲了 10.10.10.254。 - 由於主機的 keepalived 在配置中,是使用 192.168.8.1 作爲
mcast_src_ip
的。所以經過 SNAT 後,備機無法得知主機 正確的mcast_src_ip
地址。 - 同樣道理,備機上 使用 192.168.8.2 作爲
mcast_src_ip
的。經過 SNAT 後,主機也是無法得知備機機 正確的mcast_src_ip
地址。
5 處理目標
在主備機器中,源地址爲 mcast_src_ip
所 發送出的 vrrp 報文,都需要避免進行 SNAT。
6 處理方法
6.1 主機 的 iptables 配置
# 避免 10.101.101.1/32 進行 SNAT
iptables -t nat -A POSTROUTING -s 10.101.101.1/32 -d 224.0.0.0/8 -j ACCEPT
# 避免 192.168.8.1/32 進行 SNAT
iptables -t nat -A POSTROUTING -s 192.168.8.1/32 -d 224.0.0.0/8 -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j SNAT --to-source 10.10.10.254
6.2 備機 的 iptables 配置
# 避免 10.101.101.2/32 進行 SNAT
iptables -t nat -A POSTROUTING -s 10.101.101.2/32 -d 224.0.0.0/8 -j ACCEPT
# 避免 192.168.8.2/32 進行 SNAT
iptables -t nat -A POSTROUTING -s 192.168.8.2/32 -d 224.0.0.0/8 -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.8.0/24 -j SNAT --to-source 10.10.10.254
7 修復後的驗證
修復後,再次觀察主備機器上的 vrrp 報文:
- vrrp 報文恢復正常。
- 拔插網線後,也沒有虛擬ip 沒有完全刪除的情況出現。
主機上的 vrrp 報文:
tcpdump -nn -i any vrrp
> tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
> listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
> 19:56:59.760086 IP 192.168.8.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^ normal
> 19:57:00.761498 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
> 19:57:02.760174 IP 192.168.8.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^ normal
> 19:57:03.761584 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40
> 19:57:05.760225 IP 192.168.8.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 20, prio 200, authtype simple, intvl 3s, length 20
> ^^^^^^^^^^^ normal
> 19:57:06.761670 IP 10.101.101.1 > 224.0.0.18: VRRPv2, Advertisement, vrid 10, prio 200, authtype simple, intvl 3s, length 40