Files
weave/common/utils.go
T
Bryan Boreham 85023e0a76 Extract AttachContainer() function
Also move netlink and netns code from common to net

Creates interface if not already there
Adds addresses
Move the set link 'up' to after addresses are added
2016-05-25 17:29:45 +01:00

140 lines
3.2 KiB
Go

package common
import (
"fmt"
"net"
"os"
"strings"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
weavenet "github.com/weaveworks/weave/net"
)
// 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")
}
type NetDev struct {
Name string
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 {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
defer ns.Close()
err = weavenet.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{Name: link.Attrs().Name, 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, 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
}
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 {
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
}
return FindNetDevs(processID, func(link netlink.Link) bool {
_, isveth := link.(*netlink.Veth)
_, found := indexes[link.Attrs().Index]
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
})
}