轉:https://blog.csdn.net/xiewen99/article/details/54729112?utm_source=itdadao&utm_medium=referral
IP 別名(IP Alias),輔助ip地址(Secondary IP Address)
IP alias 是由 ifconfig 程序來創建和維護的,而 secondary IP address 則是由 ip 程序來創建和維護的。ip addr add 創建的 secondary IP address 不能在 ifconfig -a 中看到,反過來,ifconfig 創建的 ethX:Y 卻能在 ip addr show 中看到。實際上 ifconfig 只是取到第一個匹配的 IP 地址,而 ip addr show 卻是完全取。
multi-homing, IP aliasing, Primary address 與 Secondary address 概念辨析
host address: A unique address assigned to a communications device in a computer. If a computer has multiple communications devices (e.g., Ethernet cards or modems), each of these devices will have its own unique address. This means that a host (computer or router) can be multi-homed, i.e., have multiple IP addresses. This can also be artificially created by assigning different IP addresses to the same device (called IP aliasing).
Linux 中為同一個物理網卡增加多個 IP 地址,以前通過 ifconfig 命令來創建和維護 IP alias,而在新的 IPROUTE2 中通過 ip address 命令來創建和維護 Primary address 與 Secondary address。
* 在每一個接口上可以配置多個 Primary 地址和多個 Secondary 地址。
* 對一個特定的網絡掩碼(例子中的網絡掩碼為/24),只能有一個 Primary 地址。
在路由代碼中對許多事件和條件作出響應依賴於 IP 地址為 Primary 地址還是 Secondary 地址。下面給一些例子:
* Primary addresses contribute to the entropy of the CPU that happens to run the code that applies the configuration.
* 當刪除一個 Primary 地址時,所有相關的 Secondary 地址也被刪除。但通過 /proc 可以配置一個選項(net.ipv4.conf.*.promote_secondaries),在當前 Primary 地址被刪除時可以將 Secondary 地址提升為 Primary 地址。
* 當主機為本地生成的流量選擇源 IP 地址時,只考慮 Primary 地址。
原理
在 Linux 中,一個網卡可以有多個 IP,那么這多個 IP 有什么關系呢?其實這些 IP 組成了一個吊鏈結構,所謂吊鏈結構就是一些節點鏈接 成一條鏈,然后每個節點帶有自己的一條鏈,如下圖所示:
每個節點代表的 IP 地址標識一個網段,這個節點的 IP 就是這個網段的 Primary 地址,它下面所帶的 IP 就是這個網段的 Secondary 地址,也就是說一個網卡可以帶有各個節點所帶鏈表長度之和個 IP 地址,而且這些 IP 不是線形的,而是上述的吊鏈結構。
配置多個 IP 地址時源 IP 的選擇
如果一個主機綁定有多個 IP 地址,那么在被動響應和主動發起連接兩種方式中,源 IP 地址的選擇機制肯定是有所差異的。
主機在接收外部數據包,並發送響應數據包時,響應源地址顯然就是客戶端請求的地址,這是非常容易理解的,如客戶端向主機的 1.1.2.3:80 發起請求,那么主機響應數據包的源 IP 地址一定是 1.1.2.3 。
那么當主機對外主動發起請求時,數據包的源 IP 地址如何選擇?
當一個主機創建 IP 數據包時,必須選擇正確的源IP地址,這是至關重要的,因為只有源地址正確,才能讓接收者正確響應。如果源地址錯誤,則無法得到對端主機的任何回應。
Linux 2.2 選擇源 IP 地址使用以下三種機制:
- 應用程序可以通過 bind(2) 系統調用,應用至 sendmsg(2) 調用上,並通過輔助數據對象 IP_PKTINFO ,從而顯式指定源 IP 地址。在這種情況下,操作系統內核僅僅檢查其源 IP 地址是否正確,否則產生相應的錯誤。
- 如果應用程序沒有指定源 IP 地址,包含源 IP 的路由表將決定數據包源 IP 地址,通過設置 ip route 命令的 src 參數,從而指定源 IP 地址。如果路由表沒有包含 src 屬性,則使用主要 IP 地址。
- 其它情況下內核搜尋綁定定數據包路由接口上的 IP 地址, IPv6 選擇第一個可用的 IP 地址。 IPv4 情況下,盡量選擇與目標 IP 處於同一子網的源 IP ,如果目標 IP 與自己的所有 IP 沒有處於同一子網,則使用第二種算法。
默認情況下,如果 Linux 的網卡有多個 IP 且位於不同的子網之中,如果數據包目標地址為某個子網中的 IP, 那么對應的與目標同子網的 IP 將會被使用。如果 eth0 有兩個 IP 192.168.1.12/24、10.1.1.1/8,那么到 10.0.0.0 子網的數據包的源地址將使用 10.1.1.1。當然可以使用 ip route 的 src 屬性指定源址。
如果綁定的幾個 IP 處於同一個子網內,那么主要 IP 地址將被使用(如 eth0 接口上的 IP),也可以使用 iptables 修改數據包的源地址實現之,如:
iptables -t nat -I POSTROUTING -o eth0 -d 1.2.3.4/0 -s 192.168.100.1 -j SNAT --to-source 192.168.100.2
- 1
Keepalived virtual_ipaddress 是否要配子網掩碼
測試結果,添加 10.11.10.19/32 的類型是 Primary,添加 10.11.10.19/23 的類型是 Secondary。但是都沒有影響到 Route 源地址。見后。
因此 Keepalived virtual_ipaddress 可不用配子網掩碼。配置不帶子網掩碼的 IP 地址更簡單。
測試:
IP | Type | Route |
---|---|---|
10.11.10.19/32 | Primary | None |
10.11.10.19/23 | Secondary | None |
10.11.10.19/24 | Primary | 10.11.10.0/24 dev eth0 proto kernel scope link src 10.11.10.19 |
# 原 IP 地址是 10.11.10.23/23 # ip -4 -o a s 33: eth0 inet 10.11.10.23/23 brd 10.11.10.1 scope global eth0 # ip route 10.11.10.0/23 dev eth0 proto kernel scope link src 10.11.10.23 169.254.0.0/16 dev eth0 scope link metric 1033 # 添加 IP 地址 10.11.10.19/32 # ip addr add 10.11.10.19 dev eth0 # ip -4 -o a s 33: eth0 inet 10.11.10.23/23 brd 10.11.10.1 scope global eth0 33: eth0 inet 10.11.10.19/32 scope global eth0 # ip route 10.11.10.0/23 dev eth0 proto kernel scope link src 10.11.10.23 # ip addr del 10.11.10.19/32 dev eth0 # 添加 IP 地址 10.11.10.19/24 # ip addr add 10.11.10.19/24 dev eth0 # ip -4 -o a s 33: eth0 inet 10.11.10.23/23 brd 10.11.10.1 scope global eth0 33: eth0 inet 10.11.10.19/24 scope global eth0 # ip route 10.11.10.0/24 dev eth0 proto kernel scope link src 10.11.10.19 10.11.10.0/23 dev eth0 proto kernel scope link src 10.11.10.23 # ip addr del 10.11.10.19/24 dev eth0 # 添加 IP 地址 10.11.10.19/23 # ip addr add 10.11.10.19/23 dev eth0 # ip -4 -o a s 33: eth0 inet 10.11.10.23/23 brd 10.11.10.1 scope global eth0 33: eth0 inet 10.11.10.19/23 scope global secondary eth0 # ip route 10.11.10.0/23 dev eth0 proto kernel scope link src 10.11.10.23 # ip addr del 10.11.10.19/23 dev eth0