From 05baa566c61b435538d890680d87b09b924cc973 Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Thu, 30 Jun 2016 17:06:29 +0100 Subject: [PATCH 1/4] Refactor common.GetBridgeNetDev - Optimize. Use LinkByName instead of iterating over list of available links. Linux does not support interfaces with the same names. - Remove unnecessary indirection in utility functions which return common.NetDev. --- common/utils.go | 25 +++++++++++++++++-------- net/netns.go | 10 ++++++++++ plugin/net/cni.go | 11 ++++------- prog/weaveutil/addrs.go | 6 +++++- prog/weaveutil/main.go | 1 + proxy/proxy.go | 6 +++--- 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/common/utils.go b/common/utils.go index 7086cd9f54..4189271452 100644 --- a/common/utils.go +++ b/common/utils.go @@ -55,7 +55,7 @@ func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, e if err != nil { return err } - netDevs = append(netDevs, *netDev) + netDevs = append(netDevs, netDev) } return nil }) @@ -77,13 +77,13 @@ func forEachLink(f func(netlink.Link) error) error { return nil } -func linkToNetDev(link netlink.Link) (*NetDev, error) { +func linkToNetDev(link netlink.Link) (NetDev, error) { addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) if err != nil { - return nil, err + return NetDev{}, err } - netDev := &NetDev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr} + netDev := NetDev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr} for _, addr := range addrs { netDev.CIDRs = append(netDev.CIDRs, addr.IPNet) } @@ -133,11 +133,20 @@ func GetWeaveNetDevs(processID int) ([]NetDev, error) { }) } -// Get the weave bridge interface -func GetBridgeNetDev(bridgeName string) ([]NetDev, error) { - return FindNetDevs(1, func(link netlink.Link) bool { - return link.Attrs().Name == bridgeName +// Get the weave bridge interface. +func GetBridgeNetDev(bridgeName string) (NetDev, error) { + var netdev NetDev + + err := weavenet.WithNetNSLinkByPid(1, bridgeName, func(link netlink.Link) error { + var err error + netdev, err = linkToNetDev(link) + if err != nil { + return err + } + return nil }) + + return netdev, err } // Do post-attach configuration of all veths we have created diff --git a/net/netns.go b/net/netns.go index aeb8214c79..ac2cea4a50 100644 --- a/net/netns.go +++ b/net/netns.go @@ -35,3 +35,13 @@ func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link return work(link) }) } + +func WithNetNSLinkByPid(pid int, ifName string, work func(link netlink.Link) error) error { + ns, err := netns.GetFromPid(pid) + if err != nil { + return err + } + defer ns.Close() + + return WithNetNSLink(ns, ifName, work) +} diff --git a/plugin/net/cni.go b/plugin/net/cni.go index ec73b5f0af..ac8c1d2c0b 100644 --- a/plugin/net/cni.go +++ b/plugin/net/cni.go @@ -131,23 +131,20 @@ func setupRoutes(link netlink.Link, name string, ipnet net.IPNet, gw net.IP, rou } func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) { - netdevs, err := common.GetBridgeNetDev(bridgeName) + netdev, err := common.GetBridgeNetDev(bridgeName) if err != nil { return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err) } - if len(netdevs) == 0 { - return nil, fmt.Errorf("Could not find %q bridge", bridgeName) - } - if len(netdevs[0].CIDRs) == 0 { + if len(netdev.CIDRs) == 0 { return nil, fmt.Errorf("Bridge %q has no IP addresses; did you forget to run 'weave expose'?", bridgeName) } - for _, cidr := range netdevs[0].CIDRs { + for _, cidr := range netdev.CIDRs { if subnet.Contains(cidr.IP) { return cidr.IP, nil } } // None in the required subnet; just return the first one - return netdevs[0].CIDRs[0].IP, nil + return netdev.CIDRs[0].IP, nil } func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error { diff --git a/prog/weaveutil/addrs.go b/prog/weaveutil/addrs.go index 9c0d45f5b1..3708fc327e 100644 --- a/prog/weaveutil/addrs.go +++ b/prog/weaveutil/addrs.go @@ -41,7 +41,11 @@ func containerAddrs(args []string) error { func getNetDevs(bridgeName string, c *docker.Client, containerID string) ([]common.NetDev, error) { if containerID == "weave:expose" { - return common.GetBridgeNetDev(bridgeName) + if netDev, err := common.GetBridgeNetDev(bridgeName); err != nil { + return nil, err + } else { + return []common.NetDev{netDev}, nil + } } container, err := c.InspectContainer(containerID) diff --git a/prog/weaveutil/main.go b/prog/weaveutil/main.go index 2550d56d6d..da338994ef 100644 --- a/prog/weaveutil/main.go +++ b/prog/weaveutil/main.go @@ -30,6 +30,7 @@ func main() { usage() os.Exit(1) } + cmd, found := commands[os.Args[1]] if !found { usage() diff --git a/proxy/proxy.go b/proxy/proxy.go index 83c4ce10c4..53985ffcc9 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -149,14 +149,14 @@ func NewProxy(c Config) (*Proxy, error) { p.client = client.Client if !p.WithoutDNS { - netDevs, err := common.GetBridgeNetDev(c.DockerBridge) + netDev, err := common.GetBridgeNetDev(c.DockerBridge) if err != nil { return nil, err } - if len(netDevs) != 1 || len(netDevs[0].CIDRs) != 1 { + if len(netDev.CIDRs) != 1 { return nil, fmt.Errorf("Could not obtain address of %s", c.DockerBridge) } - p.dockerBridgeIP = netDevs[0].CIDRs[0].IP.String() + p.dockerBridgeIP = netDev.CIDRs[0].IP.String() } p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch) From 7f5c37ef1e8365ccc64e5b61fe1e4c9e35d7475b Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Fri, 1 Jul 2016 21:32:03 +0100 Subject: [PATCH 2/4] Fix "weave ps" Make sure that any network namespace changes happens at the end of the cmd invocation. Otherwise, we are risking to end up in a situation in which OS scheduling threads are in a "wrong" namespace. See WithNetNS for more details. --- common/utils.go | 63 ++++++++++++++++++++++++++------------- prog/weaveutil/addrs.go | 66 +++++++++++++++++++++++++---------------- 2 files changed, 84 insertions(+), 45 deletions(-) diff --git a/common/utils.go b/common/utils.go index 4189271452..f79ad9e053 100644 --- a/common/utils.go +++ b/common/utils.go @@ -90,29 +90,24 @@ func linkToNetDev(link netlink.Link) (NetDev, error) { return netDev, nil } -// Lookup the weave interface of a container -func GetWeaveNetDevs(processID int) ([]NetDev, error) { - // Bail out if this container is running in the root namespace - nsToplevel, err := netns.GetFromPid(1) - if err != nil { - return nil, fmt.Errorf("unable to open root namespace: %s", err) - } - nsContainr, err := netns.GetFromPid(processID) - if err != nil { - return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err) - } - if nsToplevel.Equal(nsContainr) { - return nil, nil - } +// ConnectedToBridgePredicate returns a function which is used to query whether +// a given link is a veth interface which one end is connected to a bridge. +// The returned function should be called from a container network namespace which +// the bridge does NOT belong to. +func ConnectedToBridgePredicate(bridgeName string) (func(link netlink.Link) bool, error) { + var br netlink.Link - weaveBridge, err := netlink.LinkByName("weave") + err := weavenet.WithNetNSLinkByPid(1, bridgeName, func(link netlink.Link) error { + br = link + return nil + }) if err != nil { - return nil, fmt.Errorf("Cannot find weave bridge: %s", err) + return nil, err } - // Scan devices in root namespace to find those attached to weave bridge + indexes := make(map[int]struct{}) err = forEachLink(func(link netlink.Link) error { - if link.Attrs().MasterIndex == weaveBridge.Attrs().Index { + if link.Attrs().MasterIndex == br.Attrs().Index { peerIndex := link.Attrs().ParentIndex if peerIndex == 0 { // perhaps running on an older kernel where ParentIndex doesn't work. @@ -126,11 +121,39 @@ func GetWeaveNetDevs(processID int) ([]NetDev, error) { if err != nil { return nil, err } - return FindNetDevs(processID, func(link netlink.Link) bool { + + return func(link netlink.Link) bool { _, isveth := link.(*netlink.Veth) _, found := indexes[link.Attrs().Index] return isveth && found - }) + }, nil + +} + +func GetNetDevsWithPredicate(processID int, predicate func(link netlink.Link) bool) ([]NetDev, error) { + // Bail out if this container is running in the root namespace + nsToplevel, err := netns.GetFromPid(1) + if err != nil { + return nil, fmt.Errorf("unable to open root namespace: %s", err) + } + nsContainr, err := netns.GetFromPid(processID) + if err != nil { + return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err) + } + if nsToplevel.Equal(nsContainr) { + return nil, nil + } + + return FindNetDevs(processID, predicate) +} + +// Lookup the weave interface of a container +func GetWeaveNetDevs(processID int) ([]NetDev, error) { + p, err := ConnectedToBridgePredicate("weave") + if err != nil { + return nil, err + } + return GetNetDevsWithPredicate(processID, p) } // Get the weave bridge interface. diff --git a/prog/weaveutil/addrs.go b/prog/weaveutil/addrs.go index 3708fc327e..c35213a12a 100644 --- a/prog/weaveutil/addrs.go +++ b/prog/weaveutil/addrs.go @@ -2,7 +2,9 @@ package main import ( "fmt" + "github.com/fsouza/go-dockerclient" + "github.com/vishvananda/netlink" "github.com/weaveworks/weave/common" ) @@ -11,51 +13,65 @@ func containerAddrs(args []string) error { cmdUsage("container-addrs", " [containerID ...]") } bridgeName := args[0] + containerIDs := args[1:] - c, err := docker.NewVersionedClientFromEnv("1.18") + client, err := docker.NewVersionedClientFromEnv("1.18") if err != nil { return err } - for _, containerID := range args[1:] { - netDevs, err := getNetDevs(bridgeName, c, containerID) - if err != nil { - if _, ok := err.(*docker.NoSuchContainer); ok { - continue + pred, err := common.ConnectedToBridgePredicate(bridgeName) + if err != nil { + return err + } + + containers := make(map[string]*docker.Container) + for _, cid := range containerIDs { + if containers[cid], err = client.InspectContainer(cid); err != nil { + containers[cid] = nil + if _, ok := err.(*docker.NoSuchContainer); !ok { + return err } - return err } + } - for _, netDev := range netDevs { - fmt.Printf("%12s %s %s", containerID, netDev.Name, netDev.MAC.String()) - for _, cidr := range netDev.CIDRs { - prefixLength, _ := cidr.Mask.Size() - fmt.Printf(" %v/%v", cidr.IP, prefixLength) - } - fmt.Println() + // NB: Because network namespaces (netns) are changed many times inside the loop, + // it's NOT safe to exec any code depending on the host netns without + // wrapping with WithNetNS*. + for _, cid := range containerIDs { + netDevs, err := getNetDevs(bridgeName, client, cid, containers[cid], pred) + if err != nil { + return err } + printNetDevs(cid, netDevs) } return nil } -func getNetDevs(bridgeName string, c *docker.Client, containerID string) ([]common.NetDev, error) { - if containerID == "weave:expose" { - if netDev, err := common.GetBridgeNetDev(bridgeName); err != nil { - return nil, err - } else { - return []common.NetDev{netDev}, nil +func printNetDevs(cid string, netDevs []common.NetDev) { + for _, netDev := range netDevs { + fmt.Printf("%12s %s %s", cid, netDev.Name, netDev.MAC.String()) + for _, cidr := range netDev.CIDRs { + prefixLength, _ := cidr.Mask.Size() + fmt.Printf(" %v/%v", cidr.IP, prefixLength) } + fmt.Println() } +} - container, err := c.InspectContainer(containerID) - if err != nil { - return nil, err +func getNetDevs(bridgeName string, c *docker.Client, cid string, container *docker.Container, pred func(netlink.Link) bool) ([]common.NetDev, error) { + if cid == "weave:expose" { + netDev, err := common.GetBridgeNetDev(bridgeName) + if err != nil { + return nil, err + } + return []common.NetDev{netDev}, nil } - if container.State.Pid == 0 { + if container == nil || container.State.Pid == 0 { return nil, nil } - return common.GetWeaveNetDevs(container.State.Pid) + return common.GetNetDevsWithPredicate(container.State.Pid, pred) } From 89221f117b2fdb82e3cef5e28a6c8b206b202480 Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Fri, 1 Jul 2016 22:27:12 +0100 Subject: [PATCH 3/4] Denote WithNetNS* functions with unsafe Please see https://github.com/weaveworks/weave/issues/2388#issuecomment-228365069 for more details. --- common/utils.go | 6 +++--- net/netns.go | 22 +++++++++++++++++----- net/veth.go | 8 ++++---- plugin/net/cni.go | 4 ++-- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/common/utils.go b/common/utils.go index f79ad9e053..a5a07f8244 100644 --- a/common/utils.go +++ b/common/utils.go @@ -48,7 +48,7 @@ func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, e } defer ns.Close() - err = weavenet.WithNetNS(ns, func() error { + err = weavenet.WithNetNSUnsafe(ns, func() error { return forEachLink(func(link netlink.Link) error { if match(link) { netDev, err := linkToNetDev(link) @@ -97,7 +97,7 @@ func linkToNetDev(link netlink.Link) (NetDev, error) { func ConnectedToBridgePredicate(bridgeName string) (func(link netlink.Link) bool, error) { var br netlink.Link - err := weavenet.WithNetNSLinkByPid(1, bridgeName, func(link netlink.Link) error { + err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName, func(link netlink.Link) error { br = link return nil }) @@ -160,7 +160,7 @@ func GetWeaveNetDevs(processID int) ([]NetDev, error) { func GetBridgeNetDev(bridgeName string) (NetDev, error) { var netdev NetDev - err := weavenet.WithNetNSLinkByPid(1, bridgeName, func(link netlink.Link) error { + err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName, func(link netlink.Link) error { var err error netdev, err = linkToNetDev(link) if err != nil { diff --git a/net/netns.go b/net/netns.go index ac2cea4a50..b067690938 100644 --- a/net/netns.go +++ b/net/netns.go @@ -7,7 +7,19 @@ import ( "github.com/vishvananda/netns" ) -func WithNetNS(ns netns.NsHandle, work func() error) error { +// NB: The following function is unsafe, because: +// - It changes a network namespace (netns) of an OS thread which runs +// the function. During execution, the Go runtime might clone a new OS thread +// for scheduling other go-routines, thus they might end up running in +// a "wrong" netns. +// - runtime.LockOSThread does not guarantee that a spawned go-routine on +// the locked thread will be run by it. Thus, the work function is +// not allowed to spawn any go-routine which is dependent on the given netns. + +// Please see https://github.com/weaveworks/weave/issues/2388#issuecomment-228365069 +// for more details and make sure that you understand the implications before +// using the function! +func WithNetNSUnsafe(ns netns.NsHandle, work func() error) error { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -26,8 +38,8 @@ func WithNetNS(ns netns.NsHandle, work func() error) error { return err } -func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error { - return WithNetNS(ns, func() error { +func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlink.Link) error) error { + return WithNetNSUnsafe(ns, func() error { link, err := netlink.LinkByName(ifName) if err != nil { return err @@ -36,12 +48,12 @@ func WithNetNSLink(ns netns.NsHandle, ifName string, work func(link netlink.Link }) } -func WithNetNSLinkByPid(pid int, ifName string, work func(link netlink.Link) error) error { +func WithNetNSLinkByPidUnsafe(pid int, ifName string, work func(link netlink.Link) error) error { ns, err := netns.GetFromPid(pid) if err != nil { return err } defer ns.Close() - return WithNetNSLink(ns, ifName, work) + return WithNetNSLinkUnsafe(ns, ifName, work) } diff --git a/net/veth.go b/net/veth.go index fbca71c3a3..49c1f96a64 100644 --- a/net/veth.go +++ b/net/veth.go @@ -104,7 +104,7 @@ const ( ) func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool { - err := WithNetNS(ns, func() error { + err := WithNetNSUnsafe(ns, func() error { _, err := netlink.LinkByName(ifName) return err }) @@ -122,7 +122,7 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil { return fmt.Errorf("failed to move veth to container netns: %s", err) } - if err := WithNetNS(ns, func() error { + if err := WithNetNSUnsafe(ns, func() error { if err := netlink.LinkSetName(veth, ifName); err != nil { return err } @@ -140,7 +140,7 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, } } - if err := WithNetNSLink(ns, ifName, func(veth netlink.Link) error { + if err := WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error { newAddresses, err := AddAddresses(veth, cidrs) if err != nil { return err @@ -177,7 +177,7 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, } func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) error { - return WithNetNSLink(ns, ifName, func(veth netlink.Link) error { + return WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error { existingAddrs, err := netlink.AddrList(veth, netlink.FAMILY_V4) if err != nil { return fmt.Errorf("failed to get IP address for %q: %v", veth.Attrs().Name, err) diff --git a/plugin/net/cni.go b/plugin/net/cni.go index ac8c1d2c0b..566675a7be 100644 --- a/plugin/net/cni.go +++ b/plugin/net/cni.go @@ -95,7 +95,7 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error { if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}, false); err != nil { return err } - if err := weavenet.WithNetNSLink(ns, args.IfName, func(link netlink.Link) error { + if err := weavenet.WithNetNSLinkUnsafe(ns, args.IfName, func(link netlink.Link) error { return setupRoutes(link, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes) }); err != nil { return fmt.Errorf("error setting up routes: %s", err) @@ -158,7 +158,7 @@ func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error { return err } defer ns.Close() - err = weavenet.WithNetNS(ns, func() error { + err = weavenet.WithNetNSUnsafe(ns, func() error { link, err := netlink.LinkByName(args.IfName) if err != nil { return err From 0861d055226a989cf5ec4afd122deab821adf6da Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Tue, 5 Jul 2016 14:47:51 +0100 Subject: [PATCH 4/4] Address PR comments - Do not re-enter the root netns when querying weave bridge. - Enter the root netns when constructing the predicate. --- common/utils.go | 58 +++++++++++++++++------------------------ prog/weaveutil/addrs.go | 48 ++++++++++++++++++---------------- prog/weaveutil/main.go | 1 - 3 files changed, 49 insertions(+), 58 deletions(-) diff --git a/common/utils.go b/common/utils.go index a5a07f8244..51129500a6 100644 --- a/common/utils.go +++ b/common/utils.go @@ -95,29 +95,24 @@ func linkToNetDev(link netlink.Link) (NetDev, error) { // The returned function should be called from a container network namespace which // the bridge does NOT belong to. func ConnectedToBridgePredicate(bridgeName string) (func(link netlink.Link) bool, error) { - var br netlink.Link - - err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName, func(link netlink.Link) error { - br = link - return nil - }) - if err != nil { - return nil, err - } - indexes := make(map[int]struct{}) - err = forEachLink(func(link netlink.Link) error { - if link.Attrs().MasterIndex == br.Attrs().Index { - peerIndex := link.Attrs().ParentIndex - if peerIndex == 0 { - // perhaps running on an older kernel where ParentIndex doesn't work. - // as fall-back, assume the indexes are consecutive - peerIndex = link.Attrs().Index - 1 - } - indexes[peerIndex] = struct{}{} - } - return nil - }) + + // Scan devices in root namespace to find those attached to weave bridge + err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName, + func(br netlink.Link) error { + return forEachLink(func(link netlink.Link) error { + if link.Attrs().MasterIndex == br.Attrs().Index { + peerIndex := link.Attrs().ParentIndex + if peerIndex == 0 { + // perhaps running on an older kernel where ParentIndex doesn't work. + // as fall-back, assume the indexes are consecutive + peerIndex = link.Attrs().Index - 1 + } + indexes[peerIndex] = struct{}{} + } + return nil + }) + }) if err != nil { return nil, err } @@ -127,7 +122,6 @@ func ConnectedToBridgePredicate(bridgeName string) (func(link netlink.Link) bool _, found := indexes[link.Attrs().Index] return isveth && found }, nil - } func GetNetDevsWithPredicate(processID int, predicate func(link netlink.Link) bool) ([]NetDev, error) { @@ -153,23 +147,19 @@ func GetWeaveNetDevs(processID int) ([]NetDev, error) { if err != nil { return nil, err } + return GetNetDevsWithPredicate(processID, p) } // Get the weave bridge interface. +// NB: Should be called from the root network namespace. func GetBridgeNetDev(bridgeName string) (NetDev, error) { - var netdev NetDev - - err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName, func(link netlink.Link) error { - var err error - netdev, err = linkToNetDev(link) - if err != nil { - return err - } - return nil - }) + link, err := netlink.LinkByName(bridgeName) + if err != nil { + return NetDev{}, err + } - return netdev, err + return linkToNetDev(link) } // Do post-attach configuration of all veths we have created diff --git a/prog/weaveutil/addrs.go b/prog/weaveutil/addrs.go index c35213a12a..efdf535780 100644 --- a/prog/weaveutil/addrs.go +++ b/prog/weaveutil/addrs.go @@ -13,7 +13,6 @@ func containerAddrs(args []string) error { cmdUsage("container-addrs", " [containerID ...]") } bridgeName := args[0] - containerIDs := args[1:] client, err := docker.NewVersionedClientFromEnv("1.18") if err != nil { @@ -25,21 +24,33 @@ func containerAddrs(args []string) error { return err } + var containerIDs []string containers := make(map[string]*docker.Container) - for _, cid := range containerIDs { - if containers[cid], err = client.InspectContainer(cid); err != nil { - containers[cid] = nil - if _, ok := err.(*docker.NoSuchContainer); !ok { + + for _, cid := range args[1:] { + if cid == "weave:expose" { + netDev, err := common.GetBridgeNetDev(bridgeName) + if err != nil { return err } + printNetDevs(cid, []common.NetDev{netDev}) + continue } + if containers[cid], err = client.InspectContainer(cid); err != nil { + if _, ok := err.(*docker.NoSuchContainer); ok { + continue + } + return err + } + // To output in the right order, we keep the list of container IDs + containerIDs = append(containerIDs, cid) } // NB: Because network namespaces (netns) are changed many times inside the loop, - // it's NOT safe to exec any code depending on the host netns without + // it's NOT safe to exec any code depending on the root netns without // wrapping with WithNetNS*. for _, cid := range containerIDs { - netDevs, err := getNetDevs(bridgeName, client, cid, containers[cid], pred) + netDevs, err := getNetDevs(client, containers[cid], pred) if err != nil { return err } @@ -49,6 +60,13 @@ func containerAddrs(args []string) error { return nil } +func getNetDevs(c *docker.Client, container *docker.Container, pred func(netlink.Link) bool) ([]common.NetDev, error) { + if container.State.Pid == 0 { + return nil, nil + } + return common.GetNetDevsWithPredicate(container.State.Pid, pred) +} + func printNetDevs(cid string, netDevs []common.NetDev) { for _, netDev := range netDevs { fmt.Printf("%12s %s %s", cid, netDev.Name, netDev.MAC.String()) @@ -59,19 +77,3 @@ func printNetDevs(cid string, netDevs []common.NetDev) { fmt.Println() } } - -func getNetDevs(bridgeName string, c *docker.Client, cid string, container *docker.Container, pred func(netlink.Link) bool) ([]common.NetDev, error) { - if cid == "weave:expose" { - netDev, err := common.GetBridgeNetDev(bridgeName) - if err != nil { - return nil, err - } - return []common.NetDev{netDev}, nil - } - - if container == nil || container.State.Pid == 0 { - return nil, nil - } - - return common.GetNetDevsWithPredicate(container.State.Pid, pred) -} diff --git a/prog/weaveutil/main.go b/prog/weaveutil/main.go index da338994ef..2550d56d6d 100644 --- a/prog/weaveutil/main.go +++ b/prog/weaveutil/main.go @@ -30,7 +30,6 @@ func main() { usage() os.Exit(1) } - cmd, found := commands[os.Args[1]] if !found { usage()