應用負載均衡之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不可能被通告出去。

相關文章
相關標籤/搜索