Move NetDev utils from common/ to net/
This commit is contained in:
1 parent
3492cd93d0
commit
e611f04f41
7 files changed
+172
-175
No files matched your search
+1
-159
@@ -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)
|
||||
}
|
||||
+159
@@ -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)
|
||||
}
|
||||
+1
-2
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+2
-3
@@ -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
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user