// setupTapDevice creates persistent macvtap device // and returns a newly created netlink.Link structure // using part of pod hash and interface number in interface name func setupMacVTapDevice(podID types.UUID, config MacVTapNetConf, interfaceNumber int) (netlink.Link, error) { master, err := netlink.LinkByName(config.Master) if err != nil { return nil, errwrap.Wrap(fmt.Errorf("cannot find master device '%v'", config.Master), err) } var mode netlink.MacvlanMode switch config.Mode { // if not set - defaults to bridge mode as in: // https://github.com/coreos/rkt/blob/master/Documentation/networking.md#macvlan case "", "bridge": mode = netlink.MACVLAN_MODE_BRIDGE case "private": mode = netlink.MACVLAN_MODE_PRIVATE case "vepa": mode = netlink.MACVLAN_MODE_VEPA case "passthru": mode = netlink.MACVLAN_MODE_PASSTHRU default: return nil, fmt.Errorf("unsupported macvtap mode: %v", config.Mode) } mtu := master.Attrs().MTU if config.MTU != 0 { mtu = config.MTU } interfaceName := fmt.Sprintf("rkt-%s-vtap%d", podID.String()[0:4], interfaceNumber) link := &netlink.Macvtap{ Macvlan: netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ Name: interfaceName, MTU: mtu, ParentIndex: master.Attrs().Index, }, Mode: mode, }, } if err := netlink.LinkAdd(link); err != nil { return nil, errwrap.Wrap(errors.New("cannot create macvtap interface"), err) } // TODO: duplicate following lines for ipv6 support, when it will be added in other places ipv4SysctlValueName := fmt.Sprintf(IPv4InterfaceArpProxySysctlTemplate, interfaceName) if _, err := cnisysctl.Sysctl(ipv4SysctlValueName, "1"); err != nil { // remove the newly added link and ignore errors, because we already are in a failed state _ = netlink.LinkDel(link) return nil, errwrap.Wrap(fmt.Errorf("failed to set proxy_arp on newly added interface %q", interfaceName), err) } if err := netlink.LinkSetUp(link); err != nil { // remove the newly added link and ignore errors, because we already are in a failed state _ = netlink.LinkDel(link) return nil, errwrap.Wrap(errors.New("cannot set up macvtap interface"), err) } return link, nil }
func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) error { mode, err := modeFromString(conf.Mode) if err != nil { return err } m, err := netlink.LinkByName(conf.Master) if err != nil { return 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 err } mv := &netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ MTU: conf.MTU, Name: tmpName, ParentIndex: m.Attrs().Index, Namespace: netlink.NsFd(int(netns.Fd())), }, Mode: mode, } if err := netlink.LinkAdd(mv); err != nil { return fmt.Errorf("failed to create macvlan: %v", err) } return netns.Do(func(_ ns.NetNS) error { // TODO: duplicate following lines for ipv6 support, when it will be added in other places ipv4SysctlValueName := fmt.Sprintf(IPv4InterfaceArpProxySysctlTemplate, tmpName) if _, err := sysctl.Sysctl(ipv4SysctlValueName, "1"); err != nil { // remove the newly added link and ignore errors, because we already are in a failed state _ = netlink.LinkDel(mv) return fmt.Errorf("failed to set proxy_arp on newly added interface %q: %v", tmpName, err) } err := renameLink(tmpName, ifName) if err != nil { _ = netlink.LinkDel(mv) return fmt.Errorf("failed to rename macvlan to %q: %v", ifName, err) } return nil }) }