最近在玩LVS,碰到一些问题,顺便记录一下
测试环境
在本地Mac用Parallel起了一个虚拟机
+------------------+ +-----------+
|Parallel VM | ping |Mac |
|Ubuntu 12.04 LTS <-------------+ |
| | |en0: 192.168.2.222
| | | |
| | | |
|eth0: 192.168.2.101/24 | |
|eth1: 10.211.55.6/24 | |
| | | |
+------------------+ +-----------+
ARP协议
当网络通信时,Client 的包首先查找本地路由器,确定下一跳的IP地址。但是 IP 地址只是一个逻辑地址,网络要在硬件设备间通信,必须知道下一站网络设备的地址,设备地址在以太网是用 MAC 地址来标识,所以需要 IP 地址和 MAC 地址建立对应关系。这个关系的建立,就是通过 ARP 协议来完成的。
ARP本地缓存
当 Client 与 Server 通信,如果 Client 不知道 Server 的 MAC 地址,Client 就会发送 ARP 广播请求,Server 响应 ARP 广播请求,发送自己的 MAC 地址给 Client。具体流程为
- Client 发送 ARP 广播请求,请求包含 Client IP 和 MAC
- Server 收到 ARP 请求后,发送 ARP 响应,包含 Server 的 IP 和 MAC
- Server 保存 Client 的 IP 和 MAC,Client 保存 Server 的 IP 和 MAC
ARP 请求响应之后,在 Client 和 Server 上都会建立对方 IP 和 MAC 地址的本地缓存。当然,如果双方在一段时间内没有通信,本地缓存将失效
下面是 222 机器发 ping 包给 101 机器
# 101 机器
$ sudo tcpdump -v arp -n host 192.168.2.101
11:47:04.641424 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.2.101 tell 192.168.2.222, length 46
11:47:04.641478 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.2.101 is-at 00:1c:42:d1:ae:d5, length 28
$ arp -n |grep 192.168.2.222
192.168.2.222 ether 60:f8:1d:cd:1d:fe C eth0
# 222 机器
$ ping 192.168.2.101
PING 192.168.2.101 (192.168.2.101): 56 data bytes
64 bytes from 192.168.2.101: icmp_seq=0 ttl=64 time=0.574 ms
$ arp -n -a |grep 192.168.2.101
? (192.168.2.101) at 0:1c:42:d1:ae:d5 on en0 ifscope [ethernet]
Issue
本地环境测试发现一个问题,没搞明白。假设 A,B,C 三台机器在同一局域网
- A ping B 之后,A 和 B 都会有对方 IP 和 MAC 的 ARP 缓存, C 不会有 A 的 ARP 缓存
- 如果在 A ping B 之前,在 C 上抓 arp 的包,则 ping 之后,C 就会有 A 的 ARP 缓存
禁止 ARP 通信
在 LVS-DR/TUN 模式中,Director 和 RS(Real Server) 都绑定了 VIP,当 Client 请求 VIP:PORT 的服务时,只能是 Director 去接收 Client 请求。如果 Client 的请求跑到 RS 上,LVS 的负载均衡就失去了意义,所以要想办法禁止 RS 的 VIP 直接去接收 Client 的请求。
RS 有一个 IP(VIP),Client 请求这个 IP 时,RS 不能接收这个请求。有了 ARP 知识,应该知道这个问题的实质是,VIP 要和 Director 的 MAC 绑定,不要和 RS 的 MAC 绑定。如果 RS 关于这个 VIP 的 ARP 通信都被禁止了,RS 的 MAC 不就没有机会和 VIP 绑定了吗
如果 RS 上面的所有网卡的 IP 和 VIP 不在同一个网络里面,那么 VIP 的 ARP 广播请求都到不了 RS 上,所以这种情况下什么都不需要做1。
如果 RS 上有网卡的 IP 和 VIP 在同一个网络里面,那么 VIP 的 ARP 广播请求就有可能得到响应,所以要禁止相关 ARP 的通信,具体方法有很多2。
假设我们在 192.168.2.101
的 lo
加了一个VIP 192.168.2.200
,下面只说说 arp_ignore/arp_announce
的情况 (Linux kernel 2.6.4 and 2.4.26之后才有)
$ sudo ifconfig lo:0 192.168.2.200 netmask 255.255.255.255
吐槽一下Manual3,好晦涩,也不知道弄懂了没有
arp_ignore 参数
arp_ignore - INTEGER
Define different modes for sending replies in response to
received ARP requests that resolve local target IP addresses:
0 - (default): reply for any local target IP address, configured
on any interface
1 - reply only if the target IP address is local address
configured on the incoming interface
2 - reply only if the target IP address is local address
configured on the incoming interface and both with the
sender's IP address are part from same subnet on this interface
3 - do not reply for local addresses configured with scope host,
only resolutions for global and link addresses are replied
4-7 - reserved
8 - do not reply for all local addresses
The max value from conf/{all,interface}/arp_ignore is used
when ARP request is received on the {interface}
这个参数定义了本机要不要响应 ARP 请求
0
表示目标 IP 是本机的,则响应 ARP 请求1
如果接收 ARP 请求的网卡 IP 和目标 IP 相同,则响应 ARP 请求
对于默认值0
,当192.168.2.101
的 eth0 收到 192.168.2.200
的 ARP 请求,发现192.168.2.200
在本机上,所以回应了这个 ARP 请求。
# 101 机器
$ sudo arp -d 192.168.2.222
$ sudo tcpdump -v arp host 192.168.2.200 -n
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:31:24.415877 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.2.200 tell 192.168.2.222, length 46
14:31:24.415907 ARP, Ethernet (len 6), IPv4 (len 4), Reply 192.168.2.200 is-at 00:1c:42:d1:ae:d5, length 28
# 222 机器 ping 192.168.2.200
$ sudo arp -d 192.168.2.200
192.168.2.200 (192.168.2.200) deleted
$ ping -c 1 192.168.2.200
PING 192.168.2.200 (192.168.2.200): 56 data bytes
64 bytes from 192.168.2.200: icmp_seq=0 ttl=64 time=0.729 ms
对于默认值1
,当192.168.2.101
的 eth0 收到 192.168.2.200
的 ARP 请求,发现这个 IP 虽然是本机的,但不是 eth0 的IP地址(eth0 是接收这个 ARP 请求的网卡), 所以不会响应这个 ARP 请求
# 101 机器
$ sudo arp -d 192.168.2.222
$ sudo sysctl -p
net.ipv4.conf.eth0.arp_ignore = 1
$ sudo tcpdump -v arp host 192.168.2.200 -n
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
14:39:07.829946 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.2.200 tell 192.168.2.222, length 46
# 222 机器
$ sudo arp -d 192.168.2.200
192.168.2.200 (192.168.2.200) deleted
$ ping -c 1 192.168.2.200
PING 192.168.2.200 (192.168.2.200): 56 data bytes
--- 192.168.2.200 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss
arp_announce
刚开始讲到,只要有 ARP 通信, Client 和 Server 都会建立对方的 ARP 缓存。如果 RS 发送了一个 ARP 请求, IP 地址是 VIP,MAC 对应网卡的 IP 和 VIP 在同一个网络里面,这时候 RS 的下一站就有一个不应该出现的 ARP 缓存。
至于 RS 会什么会发送 ARP 请求,我理解是因为LVS-DR模式,RS 处理完请求,是直接回给 Client,不会回给 Director
arp_announce
定义了发送arp
请求时,源 IP 应该填什么
arp_announce - INTEGER
Define different restriction levels for announcing the local
source IP address from IP packets in ARP requests sent on
interface:
0 - (default) Use any local address, configured on any interface
1 - Try to avoid local addresses that are not in the target's
subnet for this interface. This mode is useful when target
hosts reachable via this interface require the source IP
address in ARP requests to be part of their logical network
configured on the receiving interface. When we generate the
request we will check all our subnets that include the
target IP and will preserve the source address if it is from
such subnet. If there is no such subnet we select source
address according to the rules for level 2.
2 - Always use the best local address for this target.
In this mode we ignore the source address in the IP packet
and try to select local address that we prefer for talks with
the target host. Such local address is selected by looking
for primary IP addresses on all our subnets on the outgoing
interface that include the target IP address. If no suitable
local address is found we select the first local address
we have on the outgoing interface or on all other interfaces,
with the hope we will receive reply for our request and
even sometimes no matter the source IP address we announce.
The max value from conf/{all,interface}/arp_announce is used.
Increasing the restriction level gives more chance for
receiving answer from the resolved target while decreasing
the level announces more valid sender's information.
对于 192.168.2.101
机器,如果 VIP 192.168.2.200
发送了一个 ARP 请求,通过 eth0 广播出去,MAC 地址是 eth0 的 MAC 地址
0
的意思是,ARP 请求的源 IP 是192.168.2.200
2
的意思是,ARP 请求的源 IP 是192.168.2.101
,而不是192.168.2.200
讨论
-
不需要配置
如果 RS 没有 IP 和 VIP 在同一网络,是不需要做配置的。不过 RS 需要有路由能把处理的包发出去
-
对
lo
的arp配置如果 eth0 的IP 和 VIP(绑定到lo上) 是同一个网络的,网上很多配置如下
net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.lo.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 1 net.ipv4.conf.lo.arp_announce = 1
-
没有配置
如果
arp_ignore/arp_announce
没有配置,就可能出现请求直接到达 RS 上 6