应用负载均衡之LVS(二):VS_TUN和VS_DR的arp问题

LVS系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.htmlhtml


1. ARP协议简介

ARP(Address Resolution Protocol)协议称为地址解析协议,用于将主机IP地址解析为主机的MAC地址,即IP<-->MAC之间一一映射。RARP协议相反,是将MAC地址解析为IP地址。缓存

ARP解析时分两种状况:bash

  1. 解析目标和本身在同一网段。
    A解析同网段的B,A根据本身的IP和子网掩码判断B和本身同网段,这时A就直接在这个网段上发一个ARP广播包寻求B的MAC地址,全部人都收到广播信息,可是B会将MAC地址回应给A,A缓存B的MAC地址。
  2. 解析目标和本身不在同一网段。
    A根据本身的IP和子网掩码判断出B和本身不在同一个网段,这时A就向本身的网段发送一个ARP广播包用来解析网关的MAC地址,也就是路由器的接口MAC地址,而后路由器回应,A缓存回应的MAC结果。

当发送ARP请求广播后,目标设备会进行应答,其中请求数据包和应答数据包的格式很是接近。如下是请求包和应答包数据格式的部分,完整格式请百度或者翻阅TCP/IP协议卷(一)。服务器

其中: 网络

  • op字段是一个1-4的值,1表示该数据帧是ARP请求包,2表示该数据帧是ARP应答包,3和4则表示RARP的请求和应答包。
  • src_MAC和src_IP是数据帧中的源MAC和源IP地址。这两个字段的值不必定是对应的,意思是src_IP不必定配置在src_MAC地址的接口上。
  • dest_MAC和dest_IP则是目标MAC地址和目标IP地址。对于ARP请求包,dest_MAC值为"ff:ff:ff:ff:ff:ff",表示这是广播包。一样,这两个字段的值也并不是是对应的。

当发送ARP请求广播包时,op的值设置为1,目标MAC设置为广播地址"ff:ff:ff:ff:ff:ff",而后在局域网内广播,这是在询问"who has DEST_IP"。每台主机都能收到该广播包,但只有设置了目标IP的主机才会应答:"Reply DEST_IP is-at DEST_MAC"。应答时使用单播包进行回应,会将op值改成2,表示这是应答包,同时将应答的MAC地址替换原来的"ff:ff:ff:ff:ff:ff",并将src和dest的字段位置进行调换。以下图:tcp

当响应者接收到请求者的ARP请求时,它会将请求包中的源MAC和源IP缓存到ARP缓存表中。当请求者接收到响应者的应答包时,它会将应答包中的源MAC地址和源IP地址缓存到ARP缓存表中。也就是说,一次arp请求,会让两端主机都缓存对方的IP和MAC地址。学习

使用ping命令或其余TCP链接时,两端都会缓存对方的ARP条目。但为了测试,能够手动使用arping命令发送一个自定义源MAC和源IP的arp请求让对方缓存本身的IP和MAC。测试

假如主机A上有eth0(192.168.100.54)和eth1两网卡,主机B有eth0(192.168.100.70)。下面的命令表示,在主机A上向主机B发送一个arp广播包(若是"-c N"的N大于1,则只有第一个请求包是广播,其余是单播),其中源MAC为eth1网卡的MAC,但源IP为eth0上的IP地址192.168.100.54。这会使得主机B缓存的arp条目为192.168.100.54<-->eth1_MAC,但实际上这并不是正确的映射关系。ui

arping -c 1 -I eth1 -s 192.168.100.54 192.168.100.70

有些程序能够检测到IP地址冲突的现象。典型的如DHCP服务器准备提供IP地址给客户端以前,会发送一个arp广播,以便确认该IP地址是否已被其余主机使用(例如其余主机使用静态IP时手动输入了该IP)。若是没有收到回应,则表示该IP地址没有被使用,能够提供给客户端使用,若是收到了回应,则表示该IP地址已经被使用了,DHCP会从IP池中换一个IP提供给客户端。this

arp -a命令能够显示arp缓存表的内容,arp -d ADDR能够删除ARP缓存表中某条ARP记录,这两命令对于Windows和Linux系统均可用。此外,对于Windows,arp -d *表示删除arp缓存表中的全部记录,对于Linux,则使用ip neigh flush all命令来删除arp缓存中全部记录。

注意,不管是arp请求仍是arp应答,都带有完整的源MAC、源IP、目标MAC和目标IP。这看似一句废话,但不熟知arp请求的人很容易所以而陷入困惑。

2. arp_ignore和arp_announce变量的做用分析

在设置VS/TUN和VS/DR时,须要设置到这两个arp相关的内核变量,因此这里先解释解释。

前文已经说明了arp请求包或应答包中,MAC地址能够和IP地址不对应。这样一来就出现问题了,ARP请求包中,使用哪一个源IP地址以及哪一个源MAC地址?ARP应答包中,使用哪一个源MAC和源IP地址(注意,应答包中源IP地址并不必定是请求包中的目标IP,可能会更换为本机的其余IP地址)?

arp_ignore和arp_announce这两个变量的做用正是设置使用哪一个源IP和哪一个源MAC。其中arp_ignore设置的是收到请求包后,在应答包中将本机的哪一个IP地址和MAC地址回应给请求者以供缓存;arp_announce设置的是发出请求包时,选择哪一个IP和MAC地址供响应者缓存,这也符合announce的字面意思:向外通告本机的哪一个IP地址和MAC地址供其余主机缓存。

它们的做用以下图所示:

再来细看arp_ignore和arp_announce的介绍。

2.1 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请求时的不一样应答模式:回应哪一个IP和MAC地址给请求者。

  • 0 - (default):将本机全部非lo接口的IP地址都回应出去。
  • 1 - 只有当ARP请求中的目标IP地址配置在流入接口上时才响应。
  • 2 - 只有当ARP请求中的目标IP地址配置在流入接口上时,且该IP地址(即发送者源地址)是接口地址上的子网地址时才响应(例如192.168.100.10/24和192.168.100.10/16的关系)。
  • 3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied。
  • 4-7 - 保留
  • 8 - 不回应任意地址。
  • 当某接口接收到ARP请求时,将取conf/{all,interface}/arp_ignore中值最大的生效。

注意:这里的是否响应,指的不是是否构建响应,而是路由决策后是否让构建好的响应包出去。换句话说,arp响应包是必定会构建的,可是构建好的响应包根据arp_ignore设置的值不一样,不必定能出的去。可见稍后arp_ignore=1的示例分析。

举个例子来解释值为0和1的状况。

(1)arp_ignore=0时,当主机收到arp请求时,会将本机任意可能的IP地址都应答给arp请求者。

例如,主机A有3个网卡,eth0(192.168.100.17/24),eth1(192.168.100.36/24)和eth2(172.16.10.10/16),主机B有网卡eth0(192.168.100.39)。当主机B发起对192.168.100.36或17的ping时,因为主机A回应icmp响应给主机B时,默认状况下有如下路由:

[root@xuexi ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.100.2 0.0.0.0 UG 100 0 0 eth0
0.0.0.0 192.168.100.2 0.0.0.0 UG 101 0 0 eth1
0.0.0.0 192.168.100.2 0.0.0.0 UG 102 0 0 eth2
172.16.0.0 0.0.0.0 255.255.0.0 U 100 0 0 eth2
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.100.0 0.0.0.0 255.255.255.0 U 101 0 0 eth1
192.168.100.2 0.0.0.0 255.255.255.255 UH 100 0 0 eth2

这时主机A会将eth0和eth1上的IP地址都应答给主机B,且这两个IP地址对应的MAC地址都是eth0(由于该接口是该网段的第一条路由出口)的MAC地址,由于不管请求的是哪一个目标IP,构建的arp响应都能从eth0出去,而eth0的arp_ignore=0,容许任意目标的响应包出去。如下是主机B上ping 192.168.100.36后的arp缓存表,若是结果不一样,请 ip neigh flush all 清空缓存表或者多等待一段时间再测试。

[root@xuexi ~]# ip n s 
192.168.100.36 dev eth0 lladdr 00:0c:29:fb:dd:04 REACHABLE
192.168.100.1 dev eth0 lladdr 00:50:56:c0:00:08 REACHABLE
192.168.100.17 dev eth0 lladdr 00:0c:29:fb:dd:04 STALE

若是将主机A上192.168.100.0 eth0的路由条目删除,则主机B ping 192.168.100.36时,主机A将再也不把eth0(192.168.100.17)响应给主机B,尽管它可使用eth1对应的路由出去。但若是主机B ping 192.168.100.17,那么也会将该地址响应出去,使用的源MAC地址也是eth1(由于路由出口为eth1)。所以,主机B只会缓存主机A的192.168.100.36 eth1_MAC。

由此可知,所谓响应任意可能的IP地址并非响应全部地址,lo接口、非同一网段地址以及无第一路由的接口地址就不会主动响应出去。一样,那些定义在接口上的别名地址也默认不会响应出去,由于它们的数据的流入流出都是经过它所依附的接口。

(2)arp_ignore=1时,当主机收到arp请求时,只有arp请求包中目标IP和流入接口上的IP相同时,才会响应该IP以及该接口的MAC。

例如,设置eth0网卡的该变量值为1。不过,为了完善测试,先将上面示例中删除的路由条目添加回来。

route add -net 192.168.100.0/24 dev eth0

echo 1 >/proc/sys/net/ipv4/conf/eth0/arp_ignore

这时主机B上ping 192.168.100.17时,主机A将只会响应eth0_MAC给主机B,且ping 192.168.100.36时将ping不通(这一点须要注意,在后面配置LVS的arp参数时,外界主机每每只能ping通同网段的其中一个地址)。如下是在主机B上ping 192.168.100.36时在主机A上抓取的数据包。

[root@xuexi ~]# tcpdump -nn host 192.168.100.39
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
12:21:51.739967 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:52.739741 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:53.739868 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:55.742680 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:56.743560 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
12:21:57.743086 ARP, Request who-has 192.168.100.36 tell 192.168.100.39, length 46
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

从结果中能够看出,主机A收到目标IP为192.168.100.36的ARP请求后,并无响应给主机B。由于主机B发出的ARP请求包到达主机A时的流入接口为eth1,构建arp响应包后,通过路由决策从eth0出去,而eth0上的arp_ignore=1,这个arp响应包将响应出不去,主机B也就不知道192.168.100.36的MAC地址,从而没法与A主机通讯。

这里的关键流入接口是eth1,但arp响应包的流出接口是eth0,eth0的arp_ignore=1意味着只有从eth0流入的arp请求,构建的arp响应包才容许出去。尽管ping的目标是eth0同网段的eth1:192.168.100.36。也就是说,只要eth0的arp_ignore=1,那么该主机上该网段的全部地址(除了配置在eth0上的IP)都没法与外界通讯。

此时,若是将eth0的路由条目删除,或者将eth0的路由优先级设置的比eth1的路由优先级更低(例如将eth0路由的metric的值设置的比eth1的metric更大),那么arp响应包的流出接口将是eth1,这时主机B ping主机A的eth0_IP或eth1_IP都能通,且arp缓存表中,这两个地址对应的MAC地址都是eth1_MAC。

再继续,若是没有eth0的路由,或者eth0的路由优先级比eth1低,且还设置了eth1的arp_ignore=1,此时主机B将只能ping通eth1_IP,由于ping eth0_IP的arp请求从eth0而不是eth1流入,但它的响应包通过路由决策后却要从eth1出去,eth1的arp_ignore=1不会容许这样的arp响应包出去。

所以在arp请求过程当中,目标主机路由表中路由的前后顺序很是重要,它不只决定了数据从哪流出,更深层面上还决定了流出时使用哪一个MAC地址,而这直接决定是否能成功ARP请求、ARP响应以及arp缓存的 IP<-->MAC 映射结果。若是你在学习arp_ignore和arp_announce时作了不少测试,必然能体会到这一点。

2.2 arp_announce

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.

大体翻译一下:该变量接受一个整数值。它定义的是当发送ARP请求时,在请求数据包中填入的源IP地址和源MAC地址,它们是被响应者缓存的内容

  • 0 - (default)可使用本机上任意接口的任意地址。
  • 1 - 尽可能不使用不在目标IP所在子网的地址。当目标主机能够经过该接口达到,但要求ARP数据包中的源IP地址是逻辑网络接口网段中的地址时,设置为该级别颇有用。当生成ARP请求数据包时,将检测全部包含目标IP的子网(自身网段或子网均可以),若是源IP地址处于该子网内,则使用该地址。若是没有包含该源IP地址的子网,则使用级别2(arp_announce=2)来处理。

  • 2 - 老是为目标地址寻找最佳本地地址做为ARP请求的源IP地址。这种模式下,将忽略源IP地址,而是尝试选择出能和目标IP最佳通讯质量的IP地址。这个IP是经过寻找各流出接口上的主IP地址(primary IP,不能是secondary IP)获得的,它须要和目标IP地址在同网段或属于其子网内。若是没有选出合适的地址,将选择第一个流出接口上的IP地址,这样不只能够接收到应答包,还能无视已经手动通告的源地址。

稍微解释下。

  • arp_announce=0时,向外发送ARP请求时,极可能会使用流出接口的IP地址和MAC地址,这没有硬性限制。
  • arp_announce=1时,尽可能使用与目标IP地址在同一子网的地址,例如目标IP地址为192.168.100.40/16,而本机有IP地址192.168.100.22/24,这个IP地址是目标IP地址子网内的一个地址,所以会尽可能使用该地址做为ARP请求中的源IP地址,可是源MAC地址仍是数据流出接口上的MAC。
  • arp_announce=2时,无论ARP请求包中指定的源IP地址是什么(由于ARP请求包中的源IP和源MAC能够手动指定),总会在本地搜索出和目标IP最匹配的IP地址来做为源地址。它会优先选和目标IP同子网的本地IP,若是没有则选路由表中的第一个流出接口上的IP。

例如,若是Linux主机有3个网卡:eth0(IP0)、eth1(IP1)和eth2(IP2)。若是想经过eth2接口流出源地址为IP0的ARP请求广播包,默认状况下是行不通的。由于默认状况下,使用eth2流出ARP请求的源IP地址必须使用IP2。所以必须设置arp_announce=1或2,其实设置为1时也只是有机会流出,由于它要判断IP0和目标IP地址是否存在子网所属关系。只有设置arp_announce=2才必然能流出,但这时该Linux主机向外通告的IP地址将不是IP0,而是IP2。

3.设置arp_ignore和arp_announce

Linux内核2.0.xx版本中,回环接口、回环别名接口(如lo:0,lo:1)以及回环隧道接口都不会作arp回应,对于LVS集群来讲,这很方便。但从Linux 2.2.xx开始,除了回环地址(127.0.0.0/8)和广播地址外,其余全部地址(包括回环接口上的别名接口)都会作arp回应。所以,在这样的内核版本下配置LVS可能会出现一些问题。从Linux内核2.2.14开始,提供了一个接口标记"hidden"用于从ARP广播中隐藏指定接口

这意味着对于如今的CentOS六、CentOS7来讲,虽然每一个接口(包括lo接口)均可以设置这两个变量,但这两个变量只对能arp回应的接口才生效(如eth0,eth1等对外通讯的普通接口)。也就是说,在lo接口上设置arp_ignore、arp_announce等arp参数是没有意义的

尽管对lo接口设置arp参数没有意义,但为了保证lo和普通网卡、隧道设置方法的统一性,以及将来的内核可能对此作出改变,本文以及网上的文章仍是对它进行了一样的设置。

例如,设置lo接口的arp_ignore=一、arp_announce=2。

echo 1 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/lo/arp_announce

若是在接口上设置了别名IP,例如eth0:0,因为它们仍然使用所依附的接口流入流出数据,所以在接口上设置arp_ignore和arp_announce对别名IP一样生效。

其实,在/proc/sys/net/ipv4/conf下,除了各网卡接口的配置目录,还有default和all两个目录,这两个目录内关于arp参数的值只影响普通网卡,不影响lo接口,也没有意义去影响lo接口。

[root@xuexi ~]# ls -l /proc/sys/net/ipv4/conf/
total 0
dr-xr-xr-x 1 root root 0 Feb 15  2018 all
dr-xr-xr-x 1 root root 0 Feb 15  2018 default
dr-xr-xr-x 1 root root 0 Feb 14 22:56 eth0
dr-xr-xr-x 1 root root 0 Feb 14 22:56 eth1
dr-xr-xr-x 1 root root 0 Feb 14 22:56 lo

其中:

  • default目录中的变量值为普通网络接口提供初始化值(不影响lo接口)。这个目录其实没什么用,由于每次重启操做系统,/proc/sys下的设置都会失效,而直接设置该目录下的值又起不到提供初始化值的做用。之因此放在conf目录内是为了提示咱们能够设置default属性的值。例如,向sysctl.conf中追加永久设置net.ipv4.conf.default.arp_ignore=1,这样每次重启系统后各网卡接口的arp_ignore级别都是1(注意:普通网卡才生效,lo接口不受影响)。
  • all目录中的变量做用范围是全部网卡(不包括lo接口)。

对于每一个网卡来讲,将比较all目录中的变量值和网卡自身的变量值,取较大值。例如:

conf/eth0/arp_ignore值为1,conf/all/arp_ignore值为0,则对于eth0接口来讲,arp_ignore=1。
conf/lo/arp_announce值为0,conf/all/arp_announce值为2,则对于lo接口来讲,arp_announce=0,由于all目录不影响lo接口。但最终,lo接口上设置的arp参数值是没有意义的。

一般,VS/TUN和VS/DR模式下,Real Server上的VIP设置在lo的别名接口上(如lo:0上),所以应该以下设置:

echo 1 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce

其中生效的为第二条和第四条规则,第一条和第三条对lo接口的设置语句无关紧要。

将conf/all/arp_ignore设置为1,能够保证不管哪一个对外通讯的网卡接口都只会向外响应本身接口上的IP地址(甚至可能有些同网段的接口由于路由顺序排在后面而响应不出去),这样就隐藏了设置在lo别名接口上的VIP地址。将conf/all/arp_announce设置为2,能够保证本机只向外通告普通网卡上的IP地址,lo别名接口上的VIP不可能被通告出去。

相关文章
相关标签/搜索