Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
Revert "Merge pull request #2475 from /issues/2419-withnetns"
Browse files Browse the repository at this point in the history
This reverts commit a5ff7ab, reversing
changes made to 04a6e6d.
  • Loading branch information
brb committed Nov 3, 2016
1 parent bb639db commit 00f8de6
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 280 deletions.
152 changes: 151 additions & 1 deletion common/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package common

import "strings"
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) {
Expand All @@ -16,3 +26,143 @@ func ErrorMessages(errors []error) string {
}
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
// Note that the predicate is called while the goroutine is inside the process' netns
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.WithNetNSUnsafe(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 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
}

// 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) {
indexes := make(map[int]struct{})

// Scan devices in root namespace to find those attached to weave bridge
err := weavenet.WithNetNSLinkByPidUnsafe(1, bridgeName,
func(br netlink.Link) error {
return forEachLink(func(link netlink.Link) error {
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.
// 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 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 process 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)
}
defer nsToplevel.Close()
nsContainr, 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 nsContainr.Close()
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.
// 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)
}
116 changes: 0 additions & 116 deletions net/netdev.go

This file was deleted.

18 changes: 14 additions & 4 deletions net/netns.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,33 @@ func WithNetNSLinkUnsafe(ns netns.NsHandle, ifName string, work func(link netlin
})
}

func WithNetNSLinkByPidUnsafe(pid int, ifName string, work func(link netlink.Link) error) error {
ns, err := netns.GetFromPid(pid)
if err != nil {
return err
}
defer ns.Close()

return WithNetNSLinkUnsafe(ns, ifName, work)
}

// A safe version of WithNetNS* which creates a process executing
// "nsenter --net=<ns-path> weaveutil <cmd> [args]".
func WithNetNS(nsPath string, cmd string, args ...string) ([]byte, error) {
func WithNetNS(nsPath string, cmd string, args ...string) (string, error) {
var stdout, stderr bytes.Buffer

args = append([]string{"--net=" + nsPath, "weaveutil", cmd}, args...)
c := exec.Command("nsenter", args...)
c.Stdout = &stdout
c.Stderr = &stderr
if err := c.Run(); err != nil {
return nil, fmt.Errorf("%s: %s", string(stderr.Bytes()), err)
return "", fmt.Errorf("%s: %s", string(stderr.Bytes()), err)
}

return stdout.Bytes(), nil
return string(stdout.Bytes()), nil
}

func WithNetNSByPid(pid int, cmd string, args ...string) ([]byte, error) {
func WithNetNSByPid(pid int, cmd string, args ...string) (string, error) {
return WithNetNS(NSPathByPid(pid), cmd, args...)
}

Expand Down
42 changes: 20 additions & 22 deletions net/veth.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,21 @@ const (
vethPrefix = "v" + VethName // starts with "veth" to suppress UI notifications
)

func interfaceExistsInNamespace(netNSPath string, ifName string) bool {
_, err := WithNetNS(netNSPath, "check-iface", ifName)
func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool {
err := WithNetNSUnsafe(ns, func() error {
_, err := netlink.LinkByName(ifName)
return err
})
return err == nil
}

// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
return err
}
defer ns.Close()

func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error {
ipt, err := iptables.New()
if err != nil {
return err
}

if !interfaceExistsInNamespace(netNSPath, ifName) {
if !interfaceExistsInNamespace(ns, ifName) {
maxIDLen := IFNAMSIZ - 1 - len(vethPrefix+"pl")
if len(id) > maxIDLen {
id = id[:maxIDLen] // trim passed ID if too long
Expand All @@ -134,7 +129,18 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil {
return fmt.Errorf("failed to move veth to container netns: %s", err)
}
if _, err := WithNetNS(netNSPath, "setup-iface", peerName, ifName); err != nil {
if err := WithNetNSUnsafe(ns, func() error {
if err := netlink.LinkSetName(veth, ifName); err != nil {
return err
}
if err := ConfigureARPCache(ifName); err != nil {
return err
}
if err := ipt.Append("filter", "INPUT", "-i", ifName, "-d", "224.0.0.0/4", "-j", "DROP"); err != nil {
return err
}
return nil
}); err != nil {
return fmt.Errorf("error setting up interface: %s", err)
}
return nil
Expand Down Expand Up @@ -195,15 +201,7 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
return nil
}

// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
func DetachContainer(netNSPath, id, ifName string, cidrs []*net.IPNet) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
return err
}
defer ns.Close()

func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) error {
ipt, err := iptables.New()
if err != nil {
return err
Expand Down
Loading

0 comments on commit 00f8de6

Please sign in to comment.