flannel vxlan 實現原理【轉】



flannel是coreos為kubernets提供的網絡解決方案,主要為打通跨節點的容器通信,其中vxlan模式為flannel實現的一種后端模式,其他模式還包括udp, host-gw等,可以通過flannel官網了解更多信息。

linux vxlan工作原理

flannel的vxlan模式使用的是原生的linux vxlan實現,因此了解linux vxlan工作原理對於理解flannel的代碼實現很有幫助。

在linux vxlan中,主要術語:

  • L3 Miss: 目標IP在鄰居表中未找到 (IP Miss,所以才叫L3 Miss嗎?)
  • L2 Miss: 目標MAC在vxlan FDB中未找到對應項 (2層的Miss)
  • NOLEARNING: 禁止洪泛數據包 (在FDB中未找到相應表項)

vxlan fdb 主要映射目標MAC到vtep IP。

如圖flannel-ovs

創建vxlan device
$ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev eth0 $ip link set vxlan0 address 54:8:20:0:0:A $ip address add 10.10.10.1 dev vxlan0 $ip link set up vxlan0 

host-A 10.10.10.1 ping host-B 10.10.11.1

Host-A $ping 10.10.11.1 
  1. host-A vxlan0接口生成arp請求10.10.11.1的mac地址
  2. vxlan 驅動封裝添加VNI header,沒有已知的目的mac,使用多播地址
  3. eth0 發出數據包

在host-B上,

  1. host-B收到數據包然后轉發給相應的udp端口(vxlan)
  2. vxlan驅動解封裝,vxlan0接收到arp request包,並生成相應的arp reply包,添加相應的vxlan header,目的mac為56:bb:01:0f:cb:A

這樣在host-B的fdb中,會學到56:bb:01:0f:cb:A到轉發規則,如下:

Host-B $bridge fdb show dev vxlan0 56:bb:01:0f:cb:A dev vxlan0 dst 192.168.1.10 self 0:0:0:0:0:0 dev vxlan0 dst 239.1.1.1 via eth0 self permanent 

第二條規則就是在目的mac為止時使用多播地址的相應規則。

flannel實現方式

因為flannel是為k8s提供的網絡解決方案,而在k8s中,每一台host會分配一個網段,該網段所有啟動的容器均在這台機器上,所以,對於flnanel來說,很多信息都是已知的,可以簡化flannel的vxlan fdb(不需要處理未知的MAC地址情況)以及相應的代碼實現。

在flannel中,flannel會在每一台啟動了flannel agentd的機器上創建一個vxlan device(上述的vxlan0),名稱是flannel.1(1為vni號),flannel agent會根據分配的網段信息和vxlan device信息(vxlan device的mac地址),動態的修改host上的鄰居表,並結合vxlan device的fdb實現跨主機的docker容器的通信。

一個例子

flannel的網段分配信息是通過etcd 記錄的,在etcd中設置相應信息:

etcd $etcdctl get /flannel/network/config { "Network": "10.10.0.0/16", "Backend": { "Type": "vxlan", "VNI": 1 } } 

在host-A上運行flannel agent,agent在etcd中分配網段10.10.10.0/24,agent創建flannel.1設備接口,配置IP 10.10.10.0 MAC 56:bb:01:0f:cb:A,配置路由,整個大段通過flannel.1, 這樣overlay網絡流量通過flannel.1轉發處理,然后啟動docker0,通過指定bip 10.10.10.1/24啟動,這樣在host-A上的容器使用網段10.10.10.1/24。

同理在host-B上運行flannel agent,agent進行的相應配置過程類似。

整個例子如圖flannel-vxlan

flannel vxlan相應工作流程

由於flannel agentd知道所有的網段分配信息以及每台host上的flannel.1設備的IP,MAC,因此每一個網段在進行vxlan fdb轉發時,可以使用host上flannel.1的MAC地址。

在host-A上,運行

host-A# bridge fdb show dev flannel.1 56:bb:01:0f:cb:B dst 192.168.1.11 self permanent 

在host-B上,運行

host-B# bridge fdb show dev flannel.1 56:bb:01:0f:cb:A dst 192.168.1.10 self permanent 

如圖c1 ping c2時,如果容器c1 IP(10.10.10.2), 容器c2 IP(10.10.11.2), 因為host-A 的鄰居表里沒有c2 IP到MAC表項,flannel agent會收到相應的l3 miss(netlink)消息,然后flannel agent會反應式的設置c2 的IP到MAC表項為10.10.11.2-56:bb:01:0f:cb:B,這樣在fdb中MAC 56:bb:01:0f:cb:B就對應到host-B的flannel.1。

因為flannel知道必要的網絡信息,所以flannel直接按段處理了L3 miss的消息,L2的fdb直接在啟動時根據etcd信息靜態配置好,這樣整個網絡就連通了。

L3 miss代碼

如代碼,在L3 miss代碼中,通過miss的IP在所有段里匹配然后設置對應的vtepMac,即: 上述的c2 IP是對應到網段10.10.11.0/24的,然后相應的vtepMAC就對應到host-B的flannel.1的MAC,代碼中是通過路由信息記錄的,也保存了設備的MAC。

func (n *network) handleL3Miss(miss *netlink.Neigh) {
    log.Infof("L3 miss: %v", miss.IP) rt := n.rts.findByNetwork(ip.FromIP(miss.IP)) if rt == nil { log.Infof("Route for %v not found", miss.IP) return } if err := n.dev.AddL3(neigh{IP: ip.FromIP(miss.IP), MAC: rt.vtepMAC}); err != nil { log.Errorf("AddL3 failed: %v", err) } else { log.Info("AddL3 succeeded") } } 

L2的代碼也可以在該函數所在文件中找到。

參考資料

  1. http://events.linuxfoundation.org/sites/events/files/slides/2013-linuxcon.pdf
  2. http://lartc.org/howto/lartc.kernel.obscure.html
  3. http://hustcat.github.io/vxlan-l3miss-problem/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM