diff --git a/common/utils.go b/common/utils.go index d856e40e..666eb4f7 100644 --- a/common/utils.go +++ b/common/utils.go @@ -2,12 +2,14 @@ package common import ( "fmt" - "github.com/vishvananda/netlink" - "github.com/vishvananda/netns" "net" "os" - "runtime" "strings" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" + + weavenet "github.com/weaveworks/weave/net" ) // Assert test is true, panic otherwise @@ -25,25 +27,6 @@ func ErrorMessages(errors []error) string { return strings.Join(result, "\n") } -func WithNetNS(ns netns.NsHandle, work func() error) error { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - oldNs, err := netns.Get() - if err == nil { - defer oldNs.Close() - - err = netns.Set(ns) - if err == nil { - defer netns.Set(oldNs) - - err = work() - } - } - - return err -} - type NetDev struct { Name string MAC net.HardwareAddr @@ -63,7 +46,7 @@ func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, e } defer ns.Close() - err = WithNetNS(ns, func() error { + err = weavenet.WithNetNS(ns, func() error { return forEachLink(func(link netlink.Link) error { if match(link) { netDev, err := linkToNetDev(link) diff --git a/common/arp.go b/net/arp.go similarity index 98% rename from common/arp.go rename to net/arp.go index 094d6b16..8315db94 100644 --- a/common/arp.go +++ b/net/arp.go @@ -1,4 +1,4 @@ -package common +package net import "fmt" import "io" diff --git a/net/netns.go b/net/netns.go new file mode 100644 index 00000000..aeb8214c --- /dev/null +++ b/net/netns.go @@ -0,0 +1,37 @@ +package net + +import ( + "runtime" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" +) + +func WithNetNS(ns netns.NsHandle, work func() error) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + oldNs, err := netns.Get() + if err == nil { + defer oldNs.Close() + + err = netns.Set(ns) + if err == nil { + defer netns.Set(oldNs) + + err = work() + } + } + + return err +} + +func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error { + return WithNetNS(ns, func() error { + link, err := netlink.LinkByName(ifName) + if err != nil { + return err + } + return work(link) + }) +} diff --git a/net/veth.go b/net/veth.go index 0c11a325..3710fd7c 100644 --- a/net/veth.go +++ b/net/veth.go @@ -4,9 +4,10 @@ import ( "fmt" "net" + "github.com/j-keck/arping" "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" - "github.com/weaveworks/weave/common" "github.com/weaveworks/weave/common/odp" ) @@ -73,22 +74,65 @@ func CreateAndAttachVeth(localName, peerName, bridgeName string, mtu int, init f return local, nil } -func SetupGuest(guest netlink.Link, name string, cidrs []net.IPNet) error { +func SetupGuest(guest netlink.Link, name string) error { var err error if err = netlink.LinkSetName(guest, name); err != nil { return err } - if err = netlink.LinkSetUp(guest); err != nil { + if err = ConfigureARPCache(name); err != nil { return err } - if err = common.ConfigureARPCache(name); err != nil { + return nil +} + +func AddAddresses(guest netlink.Link, cidrs []*net.IPNet) error { + for _, ipnet := range cidrs { + if err := netlink.AddrAdd(guest, &netlink.Addr{IPNet: ipnet}); err != nil { + return fmt.Errorf("failed to add IP address to %q: %v", guest.Attrs().Name, err) + } + arping.GratuitousArpOverIfaceByName(ipnet.IP, guest.Attrs().Name) + } + return nil +} + +func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool { + err := WithNetNS(ns, func() error { + _, err := netlink.LinkByName(ifName) return err + }) + return err == nil +} + +func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, cidrs []*net.IPNet) error { + if !interfaceExistsInNamespace(ns, ifName) { + if len(id) > 5 { + id = id[:5] + } + name, peerName := "vethwepl"+id, "vethwg"+id + _, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, func(local, guest netlink.Link) error { + if err := netlink.LinkSetNsFd(guest, int(ns)); err != nil { + return fmt.Errorf("failed to move veth to container netns: %s", err) + } + if err := WithNetNS(ns, func() error { + return SetupGuest(guest, ifName) + }); err != nil { + return fmt.Errorf("error setting up interface: %s", err) + } + return nil + }) + if err != nil { + return err + } } - for _, ipnet := range cidrs { - if err = netlink.AddrAdd(guest, &netlink.Addr{IPNet: &ipnet}); err != nil { - return fmt.Errorf("failed to add IP address to %q: %v", name, err) + + if err := WithNetNSLink(ns, ifName, func(guest netlink.Link) error { + if err := AddAddresses(guest, cidrs); err != nil { + return err } - arping.GratuitousArpOverIfaceByName(ipnet.IP, name) + return netlink.LinkSetUp(guest) + }); err != nil { + return err } + return nil } diff --git a/plugin/net/cni.go b/plugin/net/cni.go index 574882d7..178b67e7 100644 --- a/plugin/net/cni.go +++ b/plugin/net/cni.go @@ -10,7 +10,6 @@ import ( "github.com/appc/cni/pkg/ipam" "github.com/appc/cni/pkg/skel" "github.com/appc/cni/pkg/types" - "github.com/j-keck/arping" "github.com/vishvananda/netlink" "github.com/vishvananda/netns" weaveapi "github.com/weaveworks/weave/api" @@ -94,24 +93,14 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error { id = fmt.Sprintf("%x", data) } - name, peerName := vethPair(id) - _, err = weavenet.CreateAndAttachVeth(name, peerName, conf.BrName, conf.MTU, func(local, guest netlink.Link) error { - if err = netlink.LinkSetNsFd(guest, int(ns)); err != nil { - return fmt.Errorf("failed to move veth to container netns: %s", err) - } - if err = common.WithNetNS(ns, func() error { - if err := weavenet.SetupGuest(guest, args.IfName, []net.IPNet{result.IP4.IP}); err != nil { - return err - } - return setupRoutes(guest, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes) - }); err != nil { - return fmt.Errorf("error setting up interface: %s", err) - } - return nil - }) - if err != nil { + if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, []*net.IPNet{&result.IP4.IP}); err != nil { return err } + if err := weavenet.WithNetNSLink(ns, args.IfName, func(guest netlink.Link) error { + return setupRoutes(guest, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes) + }); err != nil { + return fmt.Errorf("error setting up routes: %s", err) + } result.DNS = conf.DNS return result.Print() @@ -186,7 +175,7 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error { return err } defer ns.Close() - err = common.WithNetNS(ns, func() error { + err = weavenet.WithNetNS(ns, func() error { link, err := netlink.LinkByName(args.IfName) if err != nil { return err