// NewBridge creates new network bridge on Linux host. // // It is equivalent of running: ip link add name br${RANDOM STRING} type bridge // NewBridge returns Bridger which is initialized to a pointer of type Bridge if the // bridge was created successfully on the Linux host. Newly created bridge is assigned // a random name starting with "br". // It returns error if the bridge could not be created. func NewBridge() (Bridger, error) { brDev := makeNetInterfaceName("br") if ok, err := NetInterfaceNameValid(brDev); !ok { return nil, err } if _, err := net.InterfaceByName(brDev); err == nil { return nil, fmt.Errorf("Interface name %s already assigned on the host", brDev) } if err := netlink.NetworkLinkAdd(brDev, "bridge"); err != nil { return nil, err } newIfc, err := net.InterfaceByName(brDev) if err != nil { return nil, fmt.Errorf("Could not find the new interface: %s", err) } return &Bridge{ Link: Link{ ifc: newIfc, }, }, nil }
// NewLinkWithOptions creates new network link on Linux host and sets some of its network // parameters passed in as LinkOptions // // Calling NewLinkWithOptions is equivalent of running following commands one after another if // particular option is passed in as a parameter: // ip link add name ${ifcName} type dummy // ip link set dev ${ifcName} address ${MAC address} // ip link set dev ${ifcName} mtu ${MTU value} // ip link set dev ${ifcName} up // NewLinkWithOptions returns Linker which is initialized to a pointer of type Link if the network // link with given LinkOptions was created successfully on the Linux host. // It attempts to delete the link if any of the LinkOptions are incorrect or if setting the options // failed and returns error. func NewLinkWithOptions(ifcName string, opts LinkOptions) (Linker, error) { if ok, err := NetInterfaceNameValid(ifcName); !ok { return nil, err } if _, err := net.InterfaceByName(ifcName); err == nil { return nil, fmt.Errorf("Interface name %s already assigned on the host", ifcName) } if err := netlink.NetworkLinkAdd(ifcName, "dummy"); err != nil { return nil, fmt.Errorf("Could not create new link %s: %s", ifcName, err) } newIfc, err := net.InterfaceByName(ifcName) if err != nil { return nil, fmt.Errorf("Could not find the new interface: %s", err) } if (opts != LinkOptions{}) { errOpts := setLinkOptions(newIfc, opts) if errOpts != nil { if errDel := DeleteLink(newIfc.Name); err != nil { return nil, fmt.Errorf("Incorrect options specified: %s. Attempt to delete the link failed: %s", errOpts, errDel) } return nil, fmt.Errorf("Could not set link options: %s", errOpts) } } return &Link{ ifc: newIfc, }, nil }
// Create creates a bridge device and returns the interface. // If the device already exists, returns the existing interface. func (Bridge) Create(name string, ip net.IP, subnet *net.IPNet) (intf *net.Interface, err error) { netlinkMu.Lock() defer netlinkMu.Unlock() if err := netlink.NetworkLinkAdd(name, "bridge"); err != nil && err.Error() != "file exists" { return nil, fmt.Errorf("devices: create bridge: %v", err) } if intf, err = net.InterfaceByName(name); err != nil { return nil, fmt.Errorf("devices: look up created bridge interface: %v", err) } if err = netlink.NetworkLinkAddIp(intf, ip, subnet); err != nil && err.Error() != "file exists" { return nil, fmt.Errorf("devices: add IP to bridge: %v", err) } return intf, nil }
// NewLink creates new network link on Linux host. // // It is equivalent of running: ip link add name ${ifcName} type dummy // NewLink returns Linker which is initialized to a pointer of type Link if the // link was created successfully on the Linux host. // It returns error if the network link could not be created on Linux host. func NewLink(ifcName string) (Linker, error) { if ok, err := NetInterfaceNameValid(ifcName); !ok { return nil, err } if _, err := net.InterfaceByName(ifcName); err == nil { return nil, fmt.Errorf("Interface name %s already assigned on the host", ifcName) } if err := netlink.NetworkLinkAdd(ifcName, "dummy"); err != nil { return nil, fmt.Errorf("Could not create new link %s: %s", ifcName, err) } newIfc, err := net.InterfaceByName(ifcName) if err != nil { return nil, fmt.Errorf("Could not find the new interface: %s", err) } return &Link{ ifc: newIfc, }, nil }
// NewBridge creates new network bridge on Linux host with the name passed as a parameter. // It is equivalent of running: ip link add name ${ifcName} type bridge // It returns error if the bridge can not be created. func NewBridgeWithName(ifcName string) (Bridger, error) { if ok, err := NetInterfaceNameValid(ifcName); !ok { return nil, err } if _, err := net.InterfaceByName(ifcName); err == nil { return nil, fmt.Errorf("Interface name %s already assigned on the host", ifcName) } if err := netlink.NetworkLinkAdd(ifcName, "bridge"); err != nil { return nil, err } newIfc, err := net.InterfaceByName(ifcName) if err != nil { return nil, fmt.Errorf("Could not find the new interface: %s", err) } return &Bridge{ Link: Link{ ifc: newIfc, }, }, nil }
) var _ = Describe("Link Management", func() { var ( l devices.Link name string intf *net.Interface ) BeforeEach(func() { cmd, err := gexec.Start(exec.Command("sh", "-c", "mountpoint /sys || mount -t sysfs sysfs /sys"), GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) Eventually(cmd).Should(gexec.Exit(0)) name = fmt.Sprintf("gdn-test-%d", GinkgoParallelNode()) Expect(netlink.NetworkLinkAdd(name, "dummy")).To(Succeed()) intf, _ = net.InterfaceByName(name) }) AfterEach(func() { cleanup(name) }) Describe("AddIP", func() { Context("when the interface exists", func() { It("adds the IP succesffuly", func() { ip, subnet, _ := net.ParseCIDR("1.2.3.4/5") Expect(l.AddIP(intf, ip, subnet)).To(Succeed()) intf, err := net.InterfaceByName(name) Expect(err).ToNot(HaveOccurred())
Eventually(sess).Should(gexec.Exit(0)) }) AfterEach(func() { sess, err := gexec.Start(exec.Command("ip", "netns", "delete", fmt.Sprintf("gdn-netnstest-%d", GinkgoParallelNode())), GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) Eventually(sess).Should(gexec.Exit(0)) }) Describe("Executing a function inside the network namespace", func() { It("should be inside the namespace", func() { fd, err := os.Open(fmt.Sprintf("/var/run/netns/gdn-netnstest-%d", GinkgoParallelNode())) Expect(err).NotTo(HaveOccurred()) Expect(netns.Exec(fd, func() error { netlink.NetworkLinkAdd("banana-iface", "bridge") _, err := net.InterfaceByName("banana-iface") Expect(err).NotTo(HaveOccurred()) return nil })).To(Succeed()) _, err = net.InterfaceByName("banana-iface") Expect(err).To(HaveOccurred()) }) It("bubbles up any errors", func() { fd, err := os.Open(fmt.Sprintf("/var/run/netns/gdn-netnstest-%d", GinkgoParallelNode())) Expect(err).NotTo(HaveOccurred()) Expect(