Files
weave/common/utils.go
T
Bryan Boreham 2d6a916b2d Find weave veths by looking at what is connected to the bridge, not by name
and don't even look at containers running in the root namespace
2016-03-17 12:41:37 +00:00

147 lines
3.1 KiB
Go

package common
import (
"fmt"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"net"
"runtime"
"strings"
)
// Assert test is true, panic otherwise
func Assert(test bool) {
if !test {
panic("Assertion failure")
}
}
func ErrorMessages(errors []error) string {
var result []string
for _, err := range errors {
result = append(result, err.Error())
}
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 {
MAC net.HardwareAddr
CIDRs []*net.IPNet
}
// Search the network namespace of a process for interfaces matching a predicate
func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, error) {
var netDevs []NetDev
ns, err := netns.GetFromPid(processID)
if err != nil {
return nil, err
}
defer ns.Close()
err = WithNetNS(ns, func() error {
return forEachLink(func(link netlink.Link) error {
if match(link) {
netDev, err := linkToNetDev(link)
if err != nil {
return err
}
netDevs = append(netDevs, *netDev)
}
return nil
})
})
return netDevs, err
}
func forEachLink(f func(netlink.Link) error) error {
links, err := netlink.LinkList()
if err != nil {
return err
}
for _, link := range links {
if err := f(link); err != nil {
return err
}
}
return nil
}
func linkToNetDev(link netlink.Link) (*NetDev, error) {
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, err
}
netDev := &NetDev{MAC: link.Attrs().HardwareAddr}
for _, addr := range addrs {
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet)
}
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, _ := netns.GetFromPid(1)
nsContainr, _ := netns.GetFromPid(processID)
if nsToplevel.Equal(nsContainr) {
return nil, nil
}
var weaveBridge netlink.Link
forEachLink(func(link netlink.Link) error {
if link.Attrs().Name == "weave" {
weaveBridge = link
}
return nil
})
if weaveBridge == nil {
return nil, fmt.Errorf("Cannot find weave bridge")
}
// 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 {
indexes[link.Attrs().Index] = struct{}{}
}
return nil
})
if err != nil {
return nil, err
}
return FindNetDevs(processID, func(link netlink.Link) bool {
// For checking, rely on index number of veth end inside namespace being -1 of end outside
_, isveth := link.(*netlink.Veth)
_, found := indexes[link.Attrs().Index+1]
return isveth && found
})
}
// Get the weave bridge interface
func GetBridgeNetDev(bridgeName string) ([]NetDev, error) {
return FindNetDevs(1, func(link netlink.Link) bool {
return link.Attrs().Name == bridgeName
})
}