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.
This commit is contained in:
Martynas Pumputis committed 2016-07-05 15:12:39 +01:00
1 parent 05baa566c6
commit 7f5c37ef1e
2 files changed
+87 -48

No files matched your search

+43 -20
View File
@@ -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)
// 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
err := weavenet.WithNetNSLinkByPid(1, bridgeName, func(link netlink.Link) error {
br = link
return nil
})
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 nil, err
}
weaveBridge, err := netlink.LinkByName("weave")
if err != nil {
return nil, fmt.Errorf("Cannot find weave bridge: %s", 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.
+44 -28
View File
@@ -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", "<bridgeName> [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
}
}
}
// 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
}
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()
}
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()
}
}
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
}
container, err := c.InspectContainer(containerID)
if err != nil {
return nil, err
}
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)
}