【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 := ¤t.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)
}
}
}