zoukankan      html  css  js  c++  java
  • 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/
  • 相关阅读:
    通俗易懂----欧几里得算法
    安卓贴图源码--->记录旋转后位置..类似in/百度魔图
    wait、notify、sleep、interrupt对比分析
    安卓内存泄漏及检测内存泄漏
    美团多渠道打包
    高版本api在低版本中的兼容
    常用工具
    双守护进程(不死service)-5.0系统以下
    安卓log4k问题解决
    10、面向对象以及winform的简单运用(isMdicontainer的设置、timer控件进行倒计时的制作)
  • 原文地址:https://www.cnblogs.com/cwind/p/10085146.html
Copyright © 2011-2022 走看看