diff --git a/common/utils.go b/common/utils.go index fcf512d9..4307c44e 100644 --- a/common/utils.go +++ b/common/utils.go @@ -1,18 +1,6 @@ package common -import ( - "fmt" - "net" - "os" - "regexp" - "strconv" - "strings" - - "github.com/vishvananda/netlink" - "github.com/vishvananda/netns" - - weavenet "github.com/weaveworks/weave/net" -) +import "strings" // Assert test is true, panic otherwise func Assert(test bool) { @@ -28,149 +16,3 @@ func ErrorMessages(errors []error) string { } return strings.Join(result, "\n") } - -var netdevRegExp = regexp.MustCompile(`^([^ ]+?) ([^ ]+?) \[([^]]*)\]$`) - -type NetDev struct { - Name string - MAC net.HardwareAddr - CIDRs []*net.IPNet -} - -func (d NetDev) String() string { - return fmt.Sprintf("%s %s %s", d.Name, d.MAC, d.CIDRs) -} - -func ParseNetDev(netdev string) (NetDev, error) { - match := netdevRegExp.FindStringSubmatch(netdev) - if match == nil { - return NetDev{}, fmt.Errorf("invalid netdev: %s", netdev) - } - - iface := match[1] - mac, err := net.ParseMAC(match[2]) - if err != nil { - return NetDev{}, fmt.Errorf("cannot parse mac %s: %s", match[2], err) - } - - var cidrs []*net.IPNet - for _, cidr := range strings.Split(match[3], " ") { - if cidr != "" { - ip, ipnet, err := net.ParseCIDR(cidr) - if err != nil { - return NetDev{}, fmt.Errorf("cannot parse cidr %s: %s", cidr, err) - } - ipnet.IP = ip - cidrs = append(cidrs, ipnet) - } - } - - return NetDev{Name: iface, MAC: mac, CIDRs: cidrs}, nil -} - -func LinkToNetDev(link netlink.Link) (NetDev, error) { - addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) - if err != nil { - return NetDev{}, 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 -} - -// ConnectedToBridgeVethPeerIds returns peer indexes of veth links connected to -// the given bridge. The peer index is used to query from a container netns -// whether the container is connected to the bridge. -func ConnectedToBridgeVethPeerIds(bridgeName string) ([]int, error) { - var ids []int - - br, err := netlink.LinkByName(bridgeName) - if err != nil { - return nil, err - } - links, err := netlink.LinkList() - if err != nil { - return nil, err - } - - for _, link := range links { - if _, isveth := link.(*netlink.Veth); isveth && link.Attrs().MasterIndex == br.Attrs().Index { - peerID := link.Attrs().ParentIndex - if peerID == 0 { - // perhaps running on an older kernel where ParentIndex doesn't work. - // as fall-back, assume the peers are consecutive - peerID = link.Attrs().Index - 1 - } - ids = append(ids, peerID) - } - } - - return ids, nil -} - -// Lookup the weave interface of a container -func GetWeaveNetDevs(processID int) ([]NetDev, error) { - peerIDs, err := ConnectedToBridgeVethPeerIds("weave") - if err != nil { - return nil, err - } - - return GetNetDevsByVethPeerIds(processID, peerIDs) -} - -func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]NetDev, error) { - // Bail out if this container is running in the root namespace - netnsRoot, err := netns.GetFromPid(1) - if err != nil { - return nil, fmt.Errorf("unable to open root namespace: %s", err) - } - defer netnsRoot.Close() - netnsContainer, err := netns.GetFromPid(processID) - if err != nil { - // Unable to find a namespace for this process - just return nothing - if os.IsNotExist(err) { - return nil, nil - } - return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err) - } - defer netnsContainer.Close() - if netnsRoot.Equal(netnsContainer) { - return nil, nil - } - - var netdevs []NetDev - - peersStr := make([]string, len(peerIDs)) - for i, id := range peerIDs { - peersStr[i] = strconv.Itoa(id) - } - netdevsStr, err := weavenet.WithNetNSByPid(processID, "list-netdevs", strings.Join(peersStr, ",")) - if err != nil { - return nil, fmt.Errorf("list-netdevs failed: %s", err) - } - for _, netdevStr := range strings.Split(netdevsStr, "\n") { - if netdevStr != "" { - netdev, err := ParseNetDev(netdevStr) - if err != nil { - return nil, fmt.Errorf("cannot parse netdev %s: %s", netdevStr, err) - } - netdevs = append(netdevs, netdev) - } - } - - return netdevs, nil -} - -// Get the weave bridge interface. -// NB: Should be called from the root network namespace. -func GetBridgeNetDev(bridgeName string) (NetDev, error) { - link, err := netlink.LinkByName(bridgeName) - if err != nil { - return NetDev{}, err - } - - return LinkToNetDev(link) -} diff --git a/net/netdev.go b/net/netdev.go new file mode 100644 index 00000000..1c777d29 --- /dev/null +++ b/net/netdev.go @@ -0,0 +1,159 @@ +package net + +import ( + "fmt" + "net" + "os" + "regexp" + "strconv" + "strings" + + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" +) + +var netdevRegExp = regexp.MustCompile(`^([^ ]+?) ([^ ]+?) \[([^]]*)\]$`) + +type Dev struct { + Name string + MAC net.HardwareAddr + CIDRs []*net.IPNet +} + +func (d Dev) String() string { + return fmt.Sprintf("%s %s %s", d.Name, d.MAC, d.CIDRs) +} + +func ParseNetDev(netdev string) (Dev, error) { + match := netdevRegExp.FindStringSubmatch(netdev) + if match == nil { + return Dev{}, fmt.Errorf("invalid netdev: %s", netdev) + } + + iface := match[1] + mac, err := net.ParseMAC(match[2]) + if err != nil { + return Dev{}, fmt.Errorf("cannot parse mac %s: %s", match[2], err) + } + + var cidrs []*net.IPNet + for _, cidr := range strings.Split(match[3], " ") { + if cidr != "" { + ip, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return Dev{}, fmt.Errorf("cannot parse cidr %s: %s", cidr, err) + } + ipnet.IP = ip + cidrs = append(cidrs, ipnet) + } + } + + return Dev{Name: iface, MAC: mac, CIDRs: cidrs}, nil +} + +func LinkToNetDev(link netlink.Link) (Dev, error) { + addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) + if err != nil { + return Dev{}, err + } + + netDev := Dev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr} + for _, addr := range addrs { + netDev.CIDRs = append(netDev.CIDRs, addr.IPNet) + } + return netDev, nil +} + +// ConnectedToBridgeVethPeerIds returns peer indexes of veth links connected to +// the given bridge. The peer index is used to query from a container netns +// whether the container is connected to the bridge. +func ConnectedToBridgeVethPeerIds(bridgeName string) ([]int, error) { + var ids []int + + br, err := netlink.LinkByName(bridgeName) + if err != nil { + return nil, err + } + links, err := netlink.LinkList() + if err != nil { + return nil, err + } + + for _, link := range links { + if _, isveth := link.(*netlink.Veth); isveth && link.Attrs().MasterIndex == br.Attrs().Index { + peerID := link.Attrs().ParentIndex + if peerID == 0 { + // perhaps running on an older kernel where ParentIndex doesn't work. + // as fall-back, assume the peers are consecutive + peerID = link.Attrs().Index - 1 + } + ids = append(ids, peerID) + } + } + + return ids, nil +} + +// Lookup the weave interface of a container +func GetWeaveNetDevs(processID int) ([]Dev, error) { + peerIDs, err := ConnectedToBridgeVethPeerIds("weave") + if err != nil { + return nil, err + } + + return GetNetDevsByVethPeerIds(processID, peerIDs) +} + +func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]Dev, error) { + // Bail out if this container is running in the root namespace + netnsRoot, err := netns.GetFromPid(1) + if err != nil { + return nil, fmt.Errorf("unable to open root namespace: %s", err) + } + defer netnsRoot.Close() + netnsContainer, err := netns.GetFromPid(processID) + if err != nil { + // Unable to find a namespace for this process - just return nothing + if os.IsNotExist(err) { + return nil, nil + } + return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err) + } + defer netnsContainer.Close() + if netnsRoot.Equal(netnsContainer) { + return nil, nil + } + + var netdevs []Dev + + peersStr := make([]string, len(peerIDs)) + for i, id := range peerIDs { + peersStr[i] = strconv.Itoa(id) + } + netdevsStr, err := WithNetNSByPid(processID, "list-netdevs", strings.Join(peersStr, ",")) + if err != nil { + return nil, fmt.Errorf("list-netdevs failed: %s", err) + } + for _, netdevStr := range strings.Split(netdevsStr, "\n") { + if netdevStr != "" { + netdev, err := ParseNetDev(netdevStr) + if err != nil { + return nil, fmt.Errorf("cannot parse netdev %s: %s", netdevStr, err) + } + netdevs = append(netdevs, netdev) + } + } + + return netdevs, nil +} + +// Get the weave bridge interface. +// NB: Should be called from the root network namespace. +func GetBridgeNetDev(bridgeName string) (Dev, error) { + link, err := netlink.LinkByName(bridgeName) + if err != nil { + return Dev{}, err + } + + return LinkToNetDev(link) +} diff --git a/plugin/net/cni.go b/plugin/net/cni.go index 37ae5663..1d9e4407 100644 --- a/plugin/net/cni.go +++ b/plugin/net/cni.go @@ -12,7 +12,6 @@ import ( "github.com/vishvananda/netlink" "github.com/vishvananda/netns" weaveapi "github.com/weaveworks/weave/api" - "github.com/weaveworks/weave/common" weavenet "github.com/weaveworks/weave/net" ipamplugin "github.com/weaveworks/weave/plugin/ipam" ) @@ -159,7 +158,7 @@ func assignBridgeIP(bridgeName string, ipnet net.IPNet) error { var errBridgeNoIP = fmt.Errorf("Bridge has no IP address") func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) { - netdev, err := common.GetBridgeNetDev(bridgeName) + netdev, err := weavenet.GetBridgeNetDev(bridgeName) if err != nil { return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err) } diff --git a/prog/weaveutil/addrs.go b/prog/weaveutil/addrs.go index 3ab130ae..8c18ee20 100644 --- a/prog/weaveutil/addrs.go +++ b/prog/weaveutil/addrs.go @@ -5,7 +5,6 @@ import ( "github.com/fsouza/go-dockerclient" - "github.com/weaveworks/weave/common" weavenet "github.com/weaveworks/weave/net" ) @@ -20,7 +19,7 @@ func containerAddrs(args []string) error { return err } - peerIDs, err := common.ConnectedToBridgeVethPeerIds(bridgeName) + peerIDs, err := weavenet.ConnectedToBridgeVethPeerIds(bridgeName) if err != nil { if err == weavenet.ErrLinkNotFound { return nil @@ -33,11 +32,11 @@ func containerAddrs(args []string) error { for _, cid := range args[1:] { if cid == "weave:expose" { - netDev, err := common.GetBridgeNetDev(bridgeName) + netDev, err := weavenet.GetBridgeNetDev(bridgeName) if err != nil { return err } - printNetDevs(cid, []common.NetDev{netDev}) + printNetDevs(cid, []weavenet.Dev{netDev}) continue } if containers[cid], err = client.InspectContainer(cid); err != nil { @@ -61,14 +60,14 @@ func containerAddrs(args []string) error { return nil } -func getNetDevs(c *docker.Client, container *docker.Container, peerIDs []int) ([]common.NetDev, error) { +func getNetDevs(c *docker.Client, container *docker.Container, peerIDs []int) ([]weavenet.Dev, error) { if container.State.Pid == 0 { return nil, nil } - return common.GetNetDevsByVethPeerIds(container.State.Pid, peerIDs) + return weavenet.GetNetDevsByVethPeerIds(container.State.Pid, peerIDs) } -func printNetDevs(cid string, netDevs []common.NetDev) { +func printNetDevs(cid string, netDevs []weavenet.Dev) { for _, netDev := range netDevs { fmt.Printf("%12s %s %s", cid, netDev.Name, netDev.MAC.String()) for _, cidr := range netDev.CIDRs { diff --git a/prog/weaveutil/netdev.go b/prog/weaveutil/netdev.go index a89b82af..a2f29fb0 100644 --- a/prog/weaveutil/netdev.go +++ b/prog/weaveutil/netdev.go @@ -9,7 +9,6 @@ import ( "github.com/j-keck/arping" "github.com/vishvananda/netlink" - "github.com/weaveworks/weave/common" weavenet "github.com/weaveworks/weave/net" ) @@ -120,7 +119,7 @@ func listNetDevs(args []string) error { for _, link := range links { if _, found := indexes[link.Attrs().Index]; found { - netdev, err := common.LinkToNetDev(link) + netdev, err := weavenet.LinkToNetDev(link) if err != nil { return err } diff --git a/prog/weaveutil/proc-addrs.go b/prog/weaveutil/proc-addrs.go index bf11cb2e..17e08770 100644 --- a/prog/weaveutil/proc-addrs.go +++ b/prog/weaveutil/proc-addrs.go @@ -13,7 +13,7 @@ func processAddrs(args []string) error { } bridgeName := args[0] - peerIDs, err := common.ConnectedToBridgeVethPeerIds(bridgeName) + peerIDs, err := weavenet.ConnectedToBridgeVethPeerIds(bridgeName) if err != nil { if err == weavenet.ErrLinkNotFound { return nil @@ -27,7 +27,7 @@ func processAddrs(args []string) error { } for _, pid := range pids { - netDevs, err := common.GetNetDevsByVethPeerIds(pid, peerIDs) + netDevs, err := weavenet.GetNetDevsByVethPeerIds(pid, peerIDs) if err != nil { return err } diff --git a/proxy/proxy.go b/proxy/proxy.go index 53985ffc..6c2d4017 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -17,7 +17,6 @@ import ( docker "github.com/fsouza/go-dockerclient" weaveapi "github.com/weaveworks/weave/api" - "github.com/weaveworks/weave/common" weavedocker "github.com/weaveworks/weave/common/docker" weavenet "github.com/weaveworks/weave/net" "github.com/weaveworks/weave/net/address" @@ -149,7 +148,7 @@ func NewProxy(c Config) (*Proxy, error) { p.client = client.Client if !p.WithoutDNS { - netDev, err := common.GetBridgeNetDev(c.DockerBridge) + netDev, err := weavenet.GetBridgeNetDev(c.DockerBridge) if err != nil { return nil, err } @@ -625,7 +624,7 @@ func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error { if err := proxy.waitForStartByIdent(containerID); err != nil { return err } - netDevs, err := common.GetWeaveNetDevs(pid) + netDevs, err := weavenet.GetWeaveNetDevs(pid) if err != nil || len(netDevs) == 0 || len(netDevs[0].CIDRs) == 0 { return err }