func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool) error { var hostVethName string err := netns.Do(func(hostNS ns.NetNS) error { // create the veth pair in the container and move host end into host netns hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS) if err != nil { return err } hostVethName = hostVeth.Attrs().Name return nil }) if err != nil { return err } // need to lookup hostVeth again as its index has changed during ns move hostVeth, err := netlink.LinkByName(hostVethName) if err != nil { return fmt.Errorf("failed to lookup %q: %v", hostVethName, err) } // connect host veth end to the bridge if err = netlink.LinkSetMaster(hostVeth, br); err != nil { return fmt.Errorf("failed to connect %q to bridge %v: %v", hostVethName, br.Attrs().Name, err) } // set hairpin mode if err = netlink.LinkSetHairpin(hostVeth, hairpinMode); err != nil { return fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVethName, err) } return nil }
func removeIfFromNSIfExists(netNs ns.NetNS, ifName string) error { return netNs.Do(func(_ ns.NetNS) error { l, err := netlink.LinkByName(ifName) if err != nil { if strings.Contains(err.Error(), "Link not found") { return nil } return err } return netlink.LinkDel(l) }) }
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 }) }
func createIpvlan(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.IPVlan{ 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 ipvlan: %v", err) } return netns.Do(func(_ ns.NetNS) error { err := renameLink(tmpName, ifName) if err != nil { return fmt.Errorf("failed to rename ipvlan to %q: %v", ifName, err) } return nil }) }
// SetupVeth sets up a virtual ethernet link. // Should be in container netns, and will switch back to hostNS to set the host // veth end up. func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (hostVeth, contVeth netlink.Link, err error) { var hostVethName string hostVethName, contVeth, err = makeVeth(contVethName, mtu) if err != nil { return } if err = netlink.LinkSetUp(contVeth); err != nil { err = fmt.Errorf("failed to set %q up: %v", contVethName, err) return } hostVeth, err = netlink.LinkByName(hostVethName) if err != nil { err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err) return } if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil { err = fmt.Errorf("failed to move veth to host netns: %v", err) return } err = hostNS.Do(func(_ ns.NetNS) error { hostVeth, err := netlink.LinkByName(hostVethName) if err != nil { return fmt.Errorf("failed to lookup %q in %q: %v", hostVethName, hostNS.Path(), err) } if err = netlink.LinkSetUp(hostVeth); err != nil { return fmt.Errorf("failed to set %q up: %v", hostVethName, err) } return nil }) return }
Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { Expect(targetNetNS.Close()).To(Succeed()) Expect(originalNetNS.Close()).To(Succeed()) }) It("executes the callback within the target network namespace", func() { expectedInode, err := getInodeNS(targetNetNS) Expect(err).NotTo(HaveOccurred()) err = targetNetNS.Do(func(ns.NetNS) error { defer GinkgoRecover() actualInode, err := getInodeCurNetNS() Expect(err).NotTo(HaveOccurred()) Expect(actualInode).To(Equal(expectedInode)) return nil }) Expect(err).NotTo(HaveOccurred()) }) It("provides the original namespace as the argument to the callback", func() { // Ensure we start in originalNetNS err := originalNetNS.Do(func(ns.NetNS) error { defer GinkgoRecover() origNSInode, err := getInodeNS(originalNetNS) Expect(err).NotTo(HaveOccurred()) err = targetNetNS.Do(func(hostNS ns.NetNS) error {
Expect(err).NotTo(HaveOccurred()) defer targetNs.Close() args := &skel.CmdArgs{ ContainerID: "dummy", Netns: targetNs.Path(), IfName: IFNAME, StdinData: []byte(conf), } // Execute the plugin with the ADD command, creating the veth endpoints err = originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover() _, err := testutils.CmdAddWithResult(targetNs.Path(), IFNAME, func() error { return cmdAdd(args) }) Expect(err).NotTo(HaveOccurred()) return nil }) Expect(err).NotTo(HaveOccurred()) // Make sure ptp link exists in the target namespace err = targetNs.Do(func(ns.NetNS) error { defer GinkgoRecover() link, err := netlink.LinkByName(IFNAME) Expect(err).NotTo(HaveOccurred()) Expect(link.Attrs().Name).To(Equal(IFNAME)) return nil })
Expect(err).NotTo(HaveOccurred()) containerNetNS, err = ns.NewNS() Expect(err).NotTo(HaveOccurred()) fakeBytes := make([]byte, 20) //to be reset in AfterEach block rand.Reader = bytes.NewReader(fakeBytes) _ = containerNetNS.Do(func(ns.NetNS) error { defer GinkgoRecover() hostVeth, containerVeth, err = ip.SetupVeth(fmt.Sprintf(ifaceFormatString, ifaceCounter), mtu, hostNetNS) if err != nil { return err } Expect(err).NotTo(HaveOccurred()) hostVethName = hostVeth.Attrs().Name containerVethName = containerVeth.Attrs().Name return nil }) }) AfterEach(func() { Expect(containerNetNS.Close()).To(Succeed()) Expect(hostNetNS.Close()).To(Succeed()) ifaceCounter++ rand.Reader = originalRandReader })
}) Context("when given a network namespace", func() { It("sets the lo device to UP", func() { command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "ADD")) session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) Eventually(session).Should(gbytes.Say(`{.*}`)) Eventually(session).Should(gexec.Exit(0)) var lo *net.Interface err = networkNS.Do(func(ns.NetNS) error { var err error lo, err = net.InterfaceByName("lo") return err }) Expect(err).NotTo(HaveOccurred()) Expect(lo.Flags & net.FlagUp).To(Equal(net.FlagUp)) }) It("sets the lo device to DOWN", func() { command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "DEL")) session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) Eventually(session).Should(gbytes.Say(``)) Eventually(session).Should(gexec.Exit(0))
var _ = Describe("ipvlan Operations", func() { var originalNS ns.NetNS BeforeEach(func() { // Create a new NetNS so we don't modify the host var err error originalNS, err = ns.NewNS() Expect(err).NotTo(HaveOccurred()) err = originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover() // Add master err = netlink.LinkAdd(&netlink.Dummy{ LinkAttrs: netlink.LinkAttrs{ Name: MASTER_NAME, }, }) Expect(err).NotTo(HaveOccurred()) _, err = netlink.LinkByName(MASTER_NAME) Expect(err).NotTo(HaveOccurred()) return nil }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { Expect(originalNS.Close()).To(Succeed()) }) It("creates an ipvlan link in a non-default namespace", func() { conf := &NetConf{
Name: "testConfig", Type: "bridge", }, BrName: IFNAME, IsGW: false, IPMasq: false, MTU: 5000, } err := originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover() bridge, err := setupBridge(conf) Expect(err).NotTo(HaveOccurred()) Expect(bridge.Attrs().Name).To(Equal(IFNAME)) // Double check that the link was added link, err := netlink.LinkByName(IFNAME) Expect(err).NotTo(HaveOccurred()) Expect(link.Attrs().Name).To(Equal(IFNAME)) return nil }) Expect(err).NotTo(HaveOccurred()) }) It("handles an existing bridge", func() { const IFNAME = "bridge0" err := originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover()
func setupVF(conf *NetConf, ifName string, netns ns.NetNS) error { masterName := conf.Master vfIdx := conf.VF m, err := netlink.LinkByName(masterName) if err != nil { return fmt.Errorf("failed to lookup master %q: %v", conf.Master, err) } vfDir := fmt.Sprintf("/sys/class/net/%s/device/virtfn%d/net", masterName, vfIdx) if _, err := os.Lstat(vfDir); err != nil { return err } infos, err := ioutil.ReadDir(vfDir) if err != nil { return err } if len(infos) != 1 { return fmt.Errorf("Mutiple network devices in directory %s", vfDir) } // VF NIC name vfDevName := infos[0].Name() vfDev, err := netlink.LinkByName(vfDevName) if err != nil { return fmt.Errorf("failed to lookup vf device %q: %v", vfDevName, err) } // set hardware address if conf.MAC != "" { macAddr, err := net.ParseMAC(conf.MAC) if err != nil { return err } if err = netlink.LinkSetVfHardwareAddr(m, conf.VF, macAddr); err != nil { return fmt.Errorf("failed to set vf %d macaddress: %v", conf.VF, err) } } if conf.Vlan != 0 { if err = netlink.LinkSetVfVlan(m, conf.VF, conf.Vlan); err != nil { return fmt.Errorf("failed to set vf %d vlan: %v", conf.VF, err) } } if err = netlink.LinkSetUp(vfDev); err != nil { return fmt.Errorf("failed to setup vf %d device: %v", conf.VF, err) } // move VF device to ns if err = netlink.LinkSetNsFd(vfDev, int(netns.Fd())); err != nil { return fmt.Errorf("failed to move vf %d to netns: %v", conf.VF, err) } return netns.Do(func(_ ns.NetNS) error { err := renameLink(vfDevName, ifName) if err != nil { return fmt.Errorf("failed to rename vf %d device %q to %q: %v", conf.VF, vfDevName, ifName, err) } return nil }) }