在linux命令行执行 lsmod | grep macvlan
查看当前内核是否加载了该driver;如果没有查看到,可以通过 modprobe macvlan
来载入
macvlan:使用 macvlan 技术,从某个物理网卡虚拟出多个虚拟网卡有独立的 ip 和 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
{
"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.
type NetConf struct {
types.NetConf
Master string `json:"master"`
Mode string `json:"mode"`
MTU int `json:"mtu"`
}
// 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"`
}
主要是将参数转为NetConf结构体
n, cniVersion, err := loadConf(args.StdinData)
if err != nil {
return err
}
路径为/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()
第2章节讲解,相当于执行命令ip link add link eth0 name macv1 type macvlan mode bridge
macvlanInterface, err := createMacvlan(n, args.IfName, netns)
if err != nil {
return err
}
这个函数最终调用的是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
}
第3章节讲解,主要是将网卡启动,设置IP MASK ROUTE等
if err := ipam.ConfigureIface(args.IfName, result); err != nil {
return err
}
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,
}
相当于命令执行: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)
}
路径plugins/pkg/ipam/ipam_linux.go
将网卡启动,相当于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)
}
设置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)
}
添加路由,相当于命令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)
}
}
}