1. 程式人生 > >【kubernetes/k8s概念】CNI macvlan原始碼分析

【kubernetes/k8s概念】CNI macvlan原始碼分析

macvlan原理

     在linux命令列執行 lsmod | grep macvlan 檢視當前核心是否載入了該driver;如果沒有檢視到,可以通過 modprobe macvlan 來載入 

     macvlan:使用 macvlan 技術,從某個物理網絡卡虛擬出多個虛擬網絡卡有獨立的 ip 和 mac 地址

工作模式(後面中提到的mode)

  • Bridge:屬於同一個parent介面的macvlan介面之間掛到同一個bridge上,可以二層互通(經過測試,發現這些macvlan介面都無法與parent 介面互通)。
  • VPEA:所有介面的流量都需要到外部switch才能夠到達其他介面。
  • Private:介面只接受傳送給自己MAC地址的報文。

手動新增macvlan
docker inspect -f '{{.State.Pid}}' 5c63ae4340f9
ip link set macvlan1 netns 4849
ip link add link eth0 name macv1 type macvlan mode bridge

ip netns exec 2109 ip link set macvlan1 name eth1
ip net exec 4849 ip addr add 10.12.51.180/24 dev eth1
ip net exec 4849 route add -net 10.12.51.186 netmask 255.255.255.255 dev eth0

macvlan cni配置

{
    "name": "macvlannet",
    "cniVersion": "0.1.0",
    "type": "macvlan",
    "master": "eth0",
    "mode": "vepa",
    "ipam": {
        "type": "host-local",
        "subnet": "10.12.0.0/16",
        "rangeStart": "10.12.52.100",
        "rangeEnd": "10.12.52.250",
        "gateway": "10.12.51.11",
        "routes": [
            { "dst": "0.0.0.0/0" }
        ]
    }
}

## Network configuration reference

* `name` (string, required): the name of the network
* `type` (string, required): "macvlan"
* `master` (string, required): name of the host interface to enslave
* `mode` (string, optional): one of "bridge", "private", "vepa", "passthrough". Defaults to "bridge".
* `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel.
* `ipam` (dictionary, required): IPAM configuration to be used for this network.

結構體

  NetConf結構體

type NetConf struct {
	types.NetConf
	Master string `json:"master"`
	Mode   string `json:"mode"`
	MTU    int    `json:"mtu"`
}

  NetConf結構體

// NetConf describes a network.
type NetConf struct {
	CNIVersion string `json:"cniVersion,omitempty"`
	Name         string          `json:"name,omitempty"`
	Type         string          `json:"type,omitempty"`
	Capabilities map[string]bool `json:"capabilities,omitempty"`
	IPAM         IPAM            `json:"ipam,omitempty"`
	DNS          DNS             `json:"dns"`
}

1. cmdAdd函式

  1.1 LoadIPAMConfig函式

    主要是將引數轉為NetConf結構體

	n, cniVersion, err := loadConf(args.StdinData)
	if err != nil {
		return err
	}

  1.2 GetNS函式

    路徑為/proc/${容器PID}/ns/net,開啟檔案描述符

	netns, err := ns.GetNS(args.Netns)
	if err != nil {
		return fmt.Errorf("failed to open netns %q: %v", netns, err)
	}
	defer netns.Close()

  1.3 createMacvlan函式

     第2章節講解,相當於執行命令ip link add link eth0 name macv1 type macvlan mode bridge

	macvlanInterface, err := createMacvlan(n, args.IfName, netns)
	if err != nil {
		return err
	}

  1.4 ipam.ExecAdd函式

    這個函式最終呼叫的是ipam外掛,本文使用的為host-local,將引數一起傳給host-local,主要是獲得ip,管理ip,先忽略這個,假設去呼叫這個函式正確返回IP,將結果存入如下結構體中

type Result struct {
   CNIVersion string         `json:"cniVersion,omitempty"`
   Interfaces []*Interface   `json:"interfaces,omitempty"`
   IPs        []*IPConfig    `json:"ips,omitempty"`
   Routes     []*types.Route `json:"routes,omitempty"`
   DNS        types.DNS      `json:"dns,omitempty"`
}
	// run the IPAM plugin and get back the config to apply
	r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
	if err != nil {
		return err
	}

	// Convert whatever the IPAM result was into the current Result type
	result, err := current.NewResultFromResult(r)
	if err != nil {
		return err
	}

  1.5 ipam.ConfigureIface函式

    第3章節講解,主要是將網絡卡啟動,設定IP MASK ROUTE等

		if err := ipam.ConfigureIface(args.IfName, result); err != nil {
			return err
		}

2. createMacvlan函式

  2.1 預設為bridge mode,生成Macvlan結構體

	macvlan := &current.Interface{}

	mode, err := modeFromString(conf.Mode)
	if err != nil {
		return nil, err
	}

	m, err := netlink.LinkByName(conf.Master)
	if err != nil {
		return nil, fmt.Errorf("failed to lookup master %q: %v", conf.Master, err)
	}

	// due to kernel bug we have to create with tmpName or it might
	// collide with the name on the host and error out
	tmpName, err := ip.RandomVethName()
	if err != nil {
		return nil, err
	}

	mv := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			MTU:         conf.MTU,
			Name:        tmpName,
			ParentIndex: m.Attrs().Index,
			Namespace:   netlink.NsFd(int(netns.Fd())),
		},
		Mode: mode,
	}

  2.2 LinkAdd函式

     相當於命令執行:ip link add link eth0 name macv1 type macvlan mode bridge    

	if err := netlink.LinkAdd(mv); err != nil {
		return nil, fmt.Errorf("failed to create macvlan: %v", err)
	}

3. ConfigureIface函式

  路徑plugins/pkg/ipam/ipam_linux.go

  3.1 LinkSetUp函式

    將網絡卡啟動,相當於ip net exec 4849 ifconfig macv1 up

	if err := netlink.LinkSetUp(link); err != nil {
		return fmt.Errorf("failed to set %q UP: %v", ifName, err)
	}

  3.2 netlink.AddrAdd函式

    設定IP地址,相當於命令ip net exec 4849 ip addr add 10.12.51.250 netmask 255.255.0.0 dev eth0

		addr := &netlink.Addr{IPNet: &ipc.Address, Label: ""}
		if err = netlink.AddrAdd(link, addr); err != nil {
			return fmt.Errorf("failed to add IP addr %v to %q: %v", ipc, ifName, err)
		}

  3.3 ip.AddRoute函式

    新增路由,相當於命令ip net exec 4849 route add -net 10.12.51.186 netmask 255.255.255.255 dev eth0

	for _, r := range res.Routes {
		routeIsV4 := r.Dst.IP.To4() != nil
		gw := r.GW
		log.Infof("ipam_linux routeIsV4: %v gw: %v", routeIsV4, gw)
		if gw == nil {
			if routeIsV4 && v4gw != nil {
				gw = v4gw
			} else if !routeIsV4 && v6gw != nil {
				gw = v6gw
			}
		}

		if err = ip.AddRoute(&r.Dst, gw, link); err != nil {
			// we skip over duplicate routes as we assume the first one wins
			if !os.IsExist(err) {
				return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, ifName, err)
			}
		}
	}