Migrate libnetwork to use netlink.Handle

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2016-05-16 11:51:40 -07:00
parent 4c1ed2010b
commit 6d3fa9e0f2
37 changed files with 597 additions and 491 deletions

View file

@ -19,6 +19,7 @@ import (
"github.com/docker/libnetwork/iptables"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/portmapper"
@ -119,6 +120,7 @@ type driver struct {
isolationChain *iptables.ChainInfo
networks map[string]*bridgeNetwork
store datastore.DataStore
nlh *netlink.Handle
sync.Mutex
}
@ -615,8 +617,15 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
}
}()
// Initialize handle when needed
d.Lock()
if d.nlh == nil {
d.nlh = ns.NlHandle()
}
d.Unlock()
// Create or retrieve the bridge L3 interface
bridgeIface := newInterface(config)
bridgeIface := newInterface(d.nlh, config)
network.bridge = bridgeIface
// Verify the network configuration does not conflict with previously installed
@ -758,7 +767,7 @@ func (d *driver) DeleteNetwork(nid string) error {
// We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior.
if !config.DefaultBridge {
if err := netlink.LinkDel(n.bridge.Link); err != nil {
if err := d.nlh.LinkDel(n.bridge.Link); err != nil {
logrus.Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err)
}
}
@ -772,12 +781,12 @@ func (d *driver) DeleteNetwork(nid string) error {
return d.storeDelete(config)
}
func addToBridge(ifaceName, bridgeName string) error {
link, err := netlink.LinkByName(ifaceName)
func addToBridge(nlh *netlink.Handle, ifaceName, bridgeName string) error {
link, err := nlh.LinkByName(ifaceName)
if err != nil {
return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
}
if err = netlink.LinkSetMaster(link,
if err = nlh.LinkSetMaster(link,
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}); err != nil {
logrus.Debugf("Failed to add %s to bridge via netlink.Trying ioctl: %v", ifaceName, err)
iface, err := net.InterfaceByName(ifaceName)
@ -795,8 +804,8 @@ func addToBridge(ifaceName, bridgeName string) error {
return nil
}
func setHairpinMode(link netlink.Link, enable bool) error {
err := netlink.LinkSetHairpin(link, enable)
func setHairpinMode(nlh *netlink.Handle, link netlink.Link, enable bool) error {
err := nlh.LinkSetHairpin(link, enable)
if err != nil && err != syscall.EINVAL {
// If error is not EINVAL something else went wrong, bail out right away
return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v",
@ -887,13 +896,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}()
// Generate a name for what will be the host side pipe interface
hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
hostIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
if err != nil {
return err
}
// Generate a name for what will be the sandbox side pipe interface
containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
containerIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
if err != nil {
return err
}
@ -902,29 +911,29 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
PeerName: containerIfName}
if err = netlink.LinkAdd(veth); err != nil {
if err = d.nlh.LinkAdd(veth); err != nil {
return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
}
// Get the host side pipe interface handler
host, err := netlink.LinkByName(hostIfName)
host, err := d.nlh.LinkByName(hostIfName)
if err != nil {
return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
}
defer func() {
if err != nil {
netlink.LinkDel(host)
d.nlh.LinkDel(host)
}
}()
// Get the sandbox side pipe interface handler
sbox, err := netlink.LinkByName(containerIfName)
sbox, err := d.nlh.LinkByName(containerIfName)
if err != nil {
return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
}
defer func() {
if err != nil {
netlink.LinkDel(sbox)
d.nlh.LinkDel(sbox)
}
}()
@ -934,23 +943,23 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
// Add bridge inherited attributes to pipe interfaces
if config.Mtu != 0 {
err = netlink.LinkSetMTU(host, config.Mtu)
err = d.nlh.LinkSetMTU(host, config.Mtu)
if err != nil {
return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
}
err = netlink.LinkSetMTU(sbox, config.Mtu)
err = d.nlh.LinkSetMTU(sbox, config.Mtu)
if err != nil {
return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
}
}
// Attach host side pipe interface into the bridge
if err = addToBridge(hostIfName, config.BridgeName); err != nil {
if err = addToBridge(d.nlh, hostIfName, config.BridgeName); err != nil {
return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
}
if !dconfig.EnableUserlandProxy {
err = setHairpinMode(host, true)
err = setHairpinMode(d.nlh, host, true)
if err != nil {
return err
}
@ -971,7 +980,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}
// Up the host interface after finishing all netlink configuration
if err = netlink.LinkSetUp(host); err != nil {
if err = d.nlh.LinkSetUp(host); err != nil {
return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
}
@ -1056,8 +1065,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
// Try removal of link. Discard error: it is a best effort.
// Also make sure defer does not see this error either.
if link, err := netlink.LinkByName(ep.srcName); err == nil {
netlink.LinkDel(link)
if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
d.nlh.LinkDel(link)
}
return nil

View file

@ -46,7 +46,7 @@ func (d *driver) populateNetworks() error {
for _, kvo := range kvol {
ncfg := kvo.(*networkConfiguration)
if err = d.createNetwork(ncfg); err != nil {
logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state", ncfg.ID, ncfg.BridgeName)
logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err)
}
}

View file

@ -88,7 +88,9 @@ func TestCreateFullOptions(t *testing.T) {
}
func TestCreateNoConfig(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
@ -101,7 +103,9 @@ func TestCreateNoConfig(t *testing.T) {
}
func TestCreateFullOptionsLabels(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
config := &configuration{
@ -200,7 +204,10 @@ func TestCreateFullOptionsLabels(t *testing.T) {
}
func TestCreate(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
if err := d.configure(nil); err != nil {
@ -225,7 +232,10 @@ func TestCreate(t *testing.T) {
}
func TestCreateFail(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
if err := d.configure(nil); err != nil {
@ -242,7 +252,10 @@ func TestCreateFail(t *testing.T) {
}
func TestCreateMultipleNetworks(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
config := &configuration{
@ -445,6 +458,7 @@ func TestQueryEndpointInfoHairpin(t *testing.T) {
func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
defer testutils.SetupTestOSContext(t)()
d := newDriver()
config := &configuration{
@ -545,7 +559,9 @@ func getPortMapping() []types.PortBinding {
}
func TestLinkContainers(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
@ -698,6 +714,9 @@ func TestLinkContainers(t *testing.T) {
}
func TestValidateConfig(t *testing.T) {
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
// Test mtu
c := networkConfiguration{Mtu: -2}
@ -768,7 +787,10 @@ func TestValidateConfig(t *testing.T) {
}
func TestSetDefaultGw(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()
}
d := newDriver()
if err := d.configure(nil); err != nil {

View file

@ -4,6 +4,7 @@ import (
"fmt"
"net"
"github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
)
@ -20,14 +21,16 @@ type bridgeInterface struct {
bridgeIPv6 *net.IPNet
gatewayIPv4 net.IP
gatewayIPv6 net.IP
nlh *netlink.Handle
}
// newInterface creates a new bridge interface structure. It attempts to find
// an already existing device identified by the configuration BridgeName field,
// or the default bridge name when unspecified, but doesn't attempt to create
// one when missing
func newInterface(config *networkConfiguration) *bridgeInterface {
i := &bridgeInterface{}
func newInterface(nlh *netlink.Handle, config *networkConfiguration) *bridgeInterface {
var err error
i := &bridgeInterface{nlh: nlh}
// Initialize the bridge name to the default if unspecified.
if config.BridgeName == "" {
@ -35,7 +38,10 @@ func newInterface(config *networkConfiguration) *bridgeInterface {
}
// Attempt to find an existing bridge named with the specified name.
i.Link, _ = netlink.LinkByName(config.BridgeName)
i.Link, err = nlh.LinkByName(config.BridgeName)
if err != nil {
logrus.Debugf("Did not find any interface with name %s: %v", config.BridgeName, err)
}
return i
}
@ -47,14 +53,14 @@ func (i *bridgeInterface) exists() bool {
// addresses returns a single IPv4 address and all IPv6 addresses for the
// bridge interface.
func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
v4addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V4)
v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4)
if err != nil {
return netlink.Addr{}, nil, err
return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
}
v6addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V6)
v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6)
if err != nil {
return netlink.Addr{}, nil, err
return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
}
if len(v4addr) == 0 {
@ -72,7 +78,7 @@ func (i *bridgeInterface) programIPv6Address() error {
if findIPv6Address(nlAddr, nlAddressList) {
return nil
}
if err := netlink.AddrAdd(i.Link, &nlAddr); err != nil {
if err := i.nlh.AddrAdd(i.Link, &nlAddr); err != nil {
return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
}
return nil

View file

@ -10,8 +10,12 @@ import (
func TestInterfaceDefaultName(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
config := &networkConfiguration{}
if _ = newInterface(config); config.BridgeName != DefaultBridgeName {
if _ = newInterface(nh, config); config.BridgeName != DefaultBridgeName {
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
}
}
@ -19,7 +23,11 @@ func TestInterfaceDefaultName(t *testing.T) {
func TestAddressesEmptyInterface(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
inf := newInterface(&networkConfiguration{})
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
inf := newInterface(nh, &networkConfiguration{})
addrv4, addrsv6, err := inf.addresses()
if err != nil {
t.Fatalf("Failed to get addresses of default interface: %v", err)

View file

@ -35,14 +35,14 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
setMac = kv.Kernel > 3 || (kv.Kernel == 3 && kv.Major >= 3)
}
if err = netlink.LinkAdd(i.Link); err != nil {
if err = i.nlh.LinkAdd(i.Link); err != nil {
logrus.Debugf("Failed to create bridge %s via netlink. Trying ioctl", config.BridgeName)
return ioctlCreateBridge(config.BridgeName, setMac)
}
if setMac {
hwAddr := netutils.GenerateRandomMAC()
if err = netlink.LinkSetHardwareAddr(i.Link, hwAddr); err != nil {
if err = i.nlh.LinkSetHardwareAddr(i.Link, hwAddr); err != nil {
return fmt.Errorf("failed to set bridge mac-address %s : %s", hwAddr, err.Error())
}
logrus.Debugf("Setting bridge mac address to %s", hwAddr)
@ -52,15 +52,17 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
// SetupDeviceUp ups the given bridge interface.
func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
err := netlink.LinkSetUp(i.Link)
err := i.nlh.LinkSetUp(i.Link)
if err != nil {
return err
return fmt.Errorf("Failed to set link up for %s: %v", config.BridgeName, err)
}
// Attempt to update the bridge interface to refresh the flags status,
// ignoring any failure to do so.
if lnk, err := netlink.LinkByName(config.BridgeName); err == nil {
if lnk, err := i.nlh.LinkByName(config.BridgeName); err == nil {
i.Link = lnk
} else {
logrus.Warnf("Failed to retrieve link for interface (%s): %v", config.BridgeName, err)
}
return nil
}

View file

@ -13,8 +13,14 @@ import (
func TestSetupNewBridge(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
config := &networkConfiguration{BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
br := &bridgeInterface{nlh: nh}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
@ -22,7 +28,7 @@ func TestSetupNewBridge(t *testing.T) {
if br.Link == nil {
t.Fatal("bridgeInterface link is nil (expected valid link)")
}
if _, err := netlink.LinkByName(DefaultBridgeName); err != nil {
if _, err := nh.LinkByName(DefaultBridgeName); err != nil {
t.Fatalf("Failed to retrieve bridge device: %v", err)
}
if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
@ -33,10 +39,16 @@ func TestSetupNewBridge(t *testing.T) {
func TestSetupNewNonDefaultBridge(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
br := &bridgeInterface{}
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
err := setupDevice(config, br)
config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
br := &bridgeInterface{nlh: nh}
err = setupDevice(config, br)
if err == nil {
t.Fatal("Expected bridge creation failure with \"non default name\", succeeded")
}
@ -49,8 +61,14 @@ func TestSetupNewNonDefaultBridge(t *testing.T) {
func TestSetupDeviceUp(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
config := &networkConfiguration{BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
br := &bridgeInterface{nlh: nh}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
@ -59,7 +77,7 @@ func TestSetupDeviceUp(t *testing.T) {
t.Fatalf("Failed to up bridge device: %v", err)
}
lnk, _ := netlink.LinkByName(DefaultBridgeName)
lnk, _ := nh.LinkByName(DefaultBridgeName)
if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
t.Fatalf("bridgeInterface should be up")
}

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/libnetwork/iptables"
"github.com/docker/libnetwork/portmapper"
"github.com/docker/libnetwork/testutils"
"github.com/vishvananda/netlink"
)
const (
@ -16,7 +17,13 @@ const (
func TestProgramIPTable(t *testing.T) {
// Create a test bridge with a basic bridge configuration (name + IPv4).
defer testutils.SetupTestOSContext(t)()
createTestBridge(getBasicTestConfig(), &bridgeInterface{}, t)
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t)
// Store various iptables chain rules we care for.
rules := []struct {
@ -41,6 +48,11 @@ func TestSetupIPChains(t *testing.T) {
// Create a test bridge with a basic bridge configuration (name + IPv4).
defer testutils.SetupTestOSContext(t)()
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
driverconfig := &configuration{
EnableIPTables: true,
}
@ -50,7 +62,7 @@ func TestSetupIPChains(t *testing.T) {
assertChainConfig(d, t)
config := getBasicTestConfig()
br := &bridgeInterface{}
br := &bridgeInterface{nlh: nh}
createTestBridge(config, br, t)
assertBridgeConfig(config, br, d, t)

View file

@ -18,12 +18,12 @@ func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
if addrv4.IPNet != nil {
if err := netlink.AddrDel(i.Link, &addrv4); err != nil {
if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
}
}
log.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
}
}

View file

@ -8,10 +8,10 @@ import (
"github.com/vishvananda/netlink"
)
func setupTestInterface(t *testing.T) (*networkConfiguration, *bridgeInterface) {
func setupTestInterface(t *testing.T, nh *netlink.Handle) (*networkConfiguration, *bridgeInterface) {
config := &networkConfiguration{
BridgeName: DefaultBridgeName}
br := &bridgeInterface{}
br := &bridgeInterface{nlh: nh}
if err := setupDevice(config, br); err != nil {
t.Fatalf("Bridge creation failed: %v", err)
@ -27,13 +27,19 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
t.Fatalf("Failed to parse bridge IPv4: %v", err)
}
config, br := setupTestInterface(t)
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
config, br := setupTestInterface(t, nh)
config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
if err := setupBridgeIPv4(config, br); err != nil {
t.Fatalf("Failed to setup bridge IPv4: %v", err)
}
addrsv4, err := netlink.AddrList(br.Link, netlink.FAMILY_V4)
addrsv4, err := nh.AddrList(br.Link, netlink.FAMILY_V4)
if err != nil {
t.Fatalf("Failed to list device IPv4 addresses: %v", err)
}
@ -54,6 +60,12 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
func TestSetupGatewayIPv4(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
ip, nw, _ := net.ParseCIDR("192.168.0.24/16")
nw.IP = ip
gw := net.ParseIP("192.168.2.254")
@ -62,7 +74,7 @@ func TestSetupGatewayIPv4(t *testing.T) {
BridgeName: DefaultBridgeName,
DefaultGatewayIPv4: gw}
br := &bridgeInterface{bridgeIPv4: nw}
br := &bridgeInterface{bridgeIPv4: nw, nlh: nh}
if err := setupGatewayIPv4(config, br); err != nil {
t.Fatalf("Set Default Gateway failed: %v", err)

View file

@ -64,7 +64,7 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
// Setting route to global IPv6 subnet
logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
err = netlink.RouteAdd(&netlink.Route{
err = i.nlh.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: i.Link.Attrs().Index,
Dst: config.AddressIPv6,

View file

@ -14,7 +14,13 @@ import (
func TestSetupIPv6(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
config, br := setupTestInterface(t)
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
config, br := setupTestInterface(t, nh)
if err := setupBridgeIPv6(config, br); err != nil {
t.Fatalf("Failed to setup bridge IPv6: %v", err)
}
@ -28,7 +34,7 @@ func TestSetupIPv6(t *testing.T) {
t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting))
}
addrsv6, err := netlink.AddrList(br.Link, netlink.FAMILY_V6)
addrsv6, err := nh.AddrList(br.Link, netlink.FAMILY_V6)
if err != nil {
t.Fatalf("Failed to list device IPv6 addresses: %v", err)
}
@ -58,7 +64,13 @@ func TestSetupGatewayIPv6(t *testing.T) {
AddressIPv6: nw,
DefaultGatewayIPv6: gw}
br := &bridgeInterface{}
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
defer nh.Delete()
br := &bridgeInterface{nlh: nh}
if err := setupGatewayIPv6(config, br); err != nil {
t.Fatalf("Set Default Gateway failed: %v", err)

View file

@ -1,6 +1,8 @@
package bridge
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
@ -10,7 +12,7 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e
// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
addrv4, addrsv6, err := i.addresses()
if err != nil {
return err
return fmt.Errorf("Failed to verify ip addresses: %v", err)
}
// Verify that the bridge does have an IPv4 address.
@ -32,7 +34,7 @@ func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) e
// Release any residual IPv6 address that might be there because of older daemon instances
for _, addrv6 := range addrsv6 {
if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
if err := netlink.AddrDel(i.Link, &addrv6); err != nil {
if err := i.nlh.AddrDel(i.Link, &addrv6); err != nil {
log.Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
}
}

View file

@ -9,11 +9,15 @@ import (
)
func setupVerifyTest(t *testing.T) *bridgeInterface {
inf := &bridgeInterface{}
nh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
inf := &bridgeInterface{nlh: nh}
br := netlink.Bridge{}
br.LinkAttrs.Name = "default0"
if err := netlink.LinkAdd(&br); err == nil {
if err := nh.LinkAdd(&br); err == nil {
inf.Link = &br
} else {
t.Fatalf("Failed to create bridge interface: %v", err)

View file

@ -6,9 +6,9 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
)
// CreateEndpoint assigns the mac, ip and endpoint id for the new container
@ -70,8 +70,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
if ep == nil {
return fmt.Errorf("endpoint id %q not found", eid)
}
if link, err := netlink.LinkByName(ep.srcName); err == nil {
netlink.LinkDel(link)
if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
ns.NlHandle().LinkDel(link)
}
return nil

View file

@ -7,6 +7,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/types"
)
@ -34,7 +35,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not find endpoint with id %s", eid)
}
// generate a name for the iface that will be renamed to eth0 in the sbox
containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
if err != nil {
return fmt.Errorf("error generating an interface name: %v", err)
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/ns"
"github.com/vishvananda/netlink"
)
@ -27,7 +28,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent)
}
// Get the link for the master index (Example: the docker host eth iface)
parentLink, err := netlink.LinkByName(parent)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, parent, err)
}
@ -39,7 +40,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
},
Mode: mode,
}
if err := netlink.LinkAdd(ipvlan); err != nil {
if err := ns.NlHandle().LinkAdd(ipvlan); err != nil {
// If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time.
return "", fmt.Errorf("failed to create the %s port: %v", ipvlanType, err)
}
@ -61,7 +62,7 @@ func setIPVlanMode(mode string) (netlink.IPVlanMode, error) {
// parentExists check if the specified interface exists in the default namespace
func parentExists(ifaceStr string) bool {
_, err := netlink.LinkByName(ifaceStr)
_, err := ns.NlHandle().LinkByName(ifaceStr)
if err != nil {
return false
}
@ -81,7 +82,7 @@ func createVlanLink(parentName string) error {
return fmt.Errorf("vlan id must be between 1-4094, received: %d", vidInt)
}
// get the parent link to attach a vlan subinterface
parentLink, err := netlink.LinkByName(parent)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return fmt.Errorf("failed to find master interface %s on the Docker host: %v", parent, err)
}
@ -93,11 +94,11 @@ func createVlanLink(parentName string) error {
VlanId: vidInt,
}
// create the subinterface
if err := netlink.LinkAdd(vlanLink); err != nil {
if err := ns.NlHandle().LinkAdd(vlanLink); err != nil {
return fmt.Errorf("failed to create %s vlan link: %v", vlanLink.Name, err)
}
// Bring the new netlink iface up
if err := netlink.LinkSetUp(vlanLink); err != nil {
if err := ns.NlHandle().LinkSetUp(vlanLink); err != nil {
return fmt.Errorf("failed to enable %s the ipvlan parent link %v", vlanLink.Name, err)
}
logrus.Debugf("Added a vlan tagged netlink subinterface: %s with a vlan id: %d", parentName, vidInt)
@ -115,7 +116,7 @@ func delVlanLink(linkName string) error {
return err
}
// delete the vlan subinterface
vlanLink, err := netlink.LinkByName(linkName)
vlanLink, err := ns.NlHandle().LinkByName(linkName)
if err != nil {
return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
}
@ -124,7 +125,7 @@ func delVlanLink(linkName string) error {
return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
}
// delete the ipvlan slave device
if err := netlink.LinkDel(vlanLink); err != nil {
if err := ns.NlHandle().LinkDel(vlanLink); err != nil {
return fmt.Errorf("failed to delete %s link: %v", linkName, err)
}
logrus.Debugf("Deleted a vlan tagged netlink subinterface: %s", linkName)
@ -163,15 +164,15 @@ func createDummyLink(dummyName, truncNetID string) error {
Name: dummyName,
},
}
if err := netlink.LinkAdd(parent); err != nil {
if err := ns.NlHandle().LinkAdd(parent); err != nil {
return err
}
parentDummyLink, err := netlink.LinkByName(dummyName)
parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
if err != nil {
return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, dummyName, err)
}
// bring the new netlink iface up
if err := netlink.LinkSetUp(parentDummyLink); err != nil {
if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {
return fmt.Errorf("failed to enable %s the ipvlan parent link: %v", dummyName, err)
}
@ -181,7 +182,7 @@ func createDummyLink(dummyName, truncNetID string) error {
// delDummyLink deletes the link type dummy used when -o parent is not passed
func delDummyLink(linkName string) error {
// delete the vlan subinterface
dummyLink, err := netlink.LinkByName(linkName)
dummyLink, err := ns.NlHandle().LinkByName(linkName)
if err != nil {
return fmt.Errorf("failed to find link %s on the Docker host : %v", linkName, err)
}
@ -190,7 +191,7 @@ func delDummyLink(linkName string) error {
return fmt.Errorf("link %s is not a parent dummy interface", linkName)
}
// delete the ipvlan dummy device
if err := netlink.LinkDel(dummyLink); err != nil {
if err := ns.NlHandle().LinkDel(dummyLink); err != nil {
return fmt.Errorf("failed to delete the dummy %s link: %v", linkName, err)
}
logrus.Debugf("Deleted a dummy parent link: %s", linkName)

View file

@ -7,9 +7,9 @@ import (
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
)
// CreateEndpoint assigns the mac, ip and endpoint id for the new container
@ -74,8 +74,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
if ep == nil {
return fmt.Errorf("endpoint id %q not found", eid)
}
if link, err := netlink.LinkByName(ep.srcName); err == nil {
netlink.LinkDel(link)
if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
ns.NlHandle().LinkDel(link)
}
return nil

View file

@ -7,6 +7,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
)
@ -22,7 +23,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not find endpoint with id %s", eid)
}
// generate a name for the iface that will be renamed to eth0 in the sbox
containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
containerIfName, err := netutils.GenerateIfaceName(ns.NlHandle(), vethPrefix, vethLen)
if err != nil {
return fmt.Errorf("error generating an interface name: %s", err)
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/ns"
"github.com/vishvananda/netlink"
)
@ -27,7 +28,7 @@ func createMacVlan(containerIfName, parent, macvlanMode string) (string, error)
return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent)
}
// Get the link for the master index (Example: the docker host eth iface)
parentLink, err := netlink.LinkByName(parent)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, parent, err)
}
@ -39,7 +40,7 @@ func createMacVlan(containerIfName, parent, macvlanMode string) (string, error)
},
Mode: mode,
}
if err := netlink.LinkAdd(macvlan); err != nil {
if err := ns.NlHandle().LinkAdd(macvlan); err != nil {
// If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time.
return "", fmt.Errorf("failed to create the %s port: %v", macvlanType, err)
}
@ -65,7 +66,7 @@ func setMacVlanMode(mode string) (netlink.MacvlanMode, error) {
// parentExists check if the specified interface exists in the default namespace
func parentExists(ifaceStr string) bool {
_, err := netlink.LinkByName(ifaceStr)
_, err := ns.NlHandle().LinkByName(ifaceStr)
if err != nil {
return false
}
@ -85,7 +86,7 @@ func createVlanLink(parentName string) error {
return fmt.Errorf("vlan id must be between 1-4094, received: %d", vidInt)
}
// get the parent link to attach a vlan subinterface
parentLink, err := netlink.LinkByName(parent)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return fmt.Errorf("failed to find master interface %s on the Docker host: %v", parent, err)
}
@ -97,11 +98,11 @@ func createVlanLink(parentName string) error {
VlanId: vidInt,
}
// create the subinterface
if err := netlink.LinkAdd(vlanLink); err != nil {
if err := ns.NlHandle().LinkAdd(vlanLink); err != nil {
return fmt.Errorf("failed to create %s vlan link: %v", vlanLink.Name, err)
}
// Bring the new netlink iface up
if err := netlink.LinkSetUp(vlanLink); err != nil {
if err := ns.NlHandle().LinkSetUp(vlanLink); err != nil {
return fmt.Errorf("failed to enable %s the macvlan parent link %v", vlanLink.Name, err)
}
logrus.Debugf("Added a vlan tagged netlink subinterface: %s with a vlan id: %d", parentName, vidInt)
@ -119,7 +120,7 @@ func delVlanLink(linkName string) error {
return err
}
// delete the vlan subinterface
vlanLink, err := netlink.LinkByName(linkName)
vlanLink, err := ns.NlHandle().LinkByName(linkName)
if err != nil {
return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
}
@ -128,7 +129,7 @@ func delVlanLink(linkName string) error {
return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
}
// delete the macvlan slave device
if err := netlink.LinkDel(vlanLink); err != nil {
if err := ns.NlHandle().LinkDel(vlanLink); err != nil {
return fmt.Errorf("failed to delete %s link: %v", linkName, err)
}
logrus.Debugf("Deleted a vlan tagged netlink subinterface: %s", linkName)
@ -167,15 +168,15 @@ func createDummyLink(dummyName, truncNetID string) error {
Name: dummyName,
},
}
if err := netlink.LinkAdd(parent); err != nil {
if err := ns.NlHandle().LinkAdd(parent); err != nil {
return err
}
parentDummyLink, err := netlink.LinkByName(dummyName)
parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
if err != nil {
return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, dummyName, err)
}
// bring the new netlink iface up
if err := netlink.LinkSetUp(parentDummyLink); err != nil {
if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {
return fmt.Errorf("failed to enable %s the macvlan parent link: %v", dummyName, err)
}
@ -185,7 +186,7 @@ func createDummyLink(dummyName, truncNetID string) error {
// delDummyLink deletes the link type dummy used when -o parent is not passed
func delDummyLink(linkName string) error {
// delete the vlan subinterface
dummyLink, err := netlink.LinkByName(linkName)
dummyLink, err := ns.NlHandle().LinkByName(linkName)
if err != nil {
return fmt.Errorf("failed to find link %s on the Docker host : %v", linkName, err)
}
@ -194,7 +195,7 @@ func delDummyLink(linkName string) error {
return fmt.Errorf("link %s is not a parent dummy interface", linkName)
}
// delete the macvlan dummy device
if err := netlink.LinkDel(dummyLink); err != nil {
if err := ns.NlHandle().LinkDel(dummyLink); err != nil {
return fmt.Errorf("failed to delete the dummy %s link: %v", linkName, err)
}
logrus.Debugf("Deleted a dummy parent link: %s", linkName)

View file

@ -6,9 +6,9 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/types"
"github.com/gogo/protobuf/proto"
"github.com/vishvananda/netlink"
)
// Join method is invoked when a Sandbox is attached to an endpoint.
@ -57,14 +57,16 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
ep.ifName = containerIfName
nlh := ns.NlHandle()
// Set the container interface and its peer MTU to 1450 to allow
// for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) +
// outer UDP(8) + vxlan header(8))
veth, err := netlink.LinkByName(overlayIfName)
veth, err := nlh.LinkByName(overlayIfName)
if err != nil {
return fmt.Errorf("cound not find link by name %s: %v", overlayIfName, err)
}
err = netlink.LinkSetMTU(veth, vxlanVethMTU)
err = nlh.LinkSetMTU(veth, vxlanVethMTU)
if err != nil {
return err
}
@ -74,16 +76,16 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err)
}
veth, err = netlink.LinkByName(containerIfName)
veth, err = nlh.LinkByName(containerIfName)
if err != nil {
return fmt.Errorf("could not find link by name %s: %v", containerIfName, err)
}
err = netlink.LinkSetMTU(veth, vxlanVethMTU)
err = nlh.LinkSetMTU(veth, vxlanVethMTU)
if err != nil {
return err
}
if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil {
if err := nlh.LinkSetHardwareAddr(veth, ep.mac); err != nil {
return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err)
}

View file

@ -7,7 +7,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netutils"
"github.com/vishvananda/netlink"
"github.com/docker/libnetwork/ns"
)
type endpointTable map[string]*endpoint
@ -84,6 +84,8 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
}
func (d *driver) DeleteEndpoint(nid, eid string) error {
nlh := ns.NlHandle()
if err := validateID(nid, eid); err != nil {
return err
}
@ -104,12 +106,12 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
return nil
}
link, err := netlink.LinkByName(ep.ifName)
link, err := nlh.LinkByName(ep.ifName)
if err != nil {
log.Debugf("Failed to retrieve interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err)
return nil
}
if err := netlink.LinkDel(link); err != nil {
if err := nlh.LinkDel(link); err != nil {
log.Debugf("Failed to delete interface (%s)'s link on endpoint (%s) delete: %v", ep.ifName, ep.id, err)
}

View file

@ -16,6 +16,7 @@ import (
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/types"
@ -308,24 +309,24 @@ func networkOnceInit() {
defer deleteInterface("testvxlan")
path := "/proc/self/ns/net"
f, err := os.OpenFile(path, os.O_RDONLY, 0)
hNs, err := netns.GetFromPath(path)
if err != nil {
logrus.Errorf("Failed to open path %s for network namespace for setting host mode: %v", path, err)
logrus.Errorf("Failed to get network namespace from path %s while setting host mode: %v", path, err)
return
}
defer f.Close()
defer hNs.Close()
nsFD := f.Fd()
nlh := ns.NlHandle()
iface, err := netlink.LinkByName("testvxlan")
iface, err := nlh.LinkByName("testvxlan")
if err != nil {
logrus.Errorf("Failed to get link testvxlan: %v", err)
logrus.Errorf("Failed to get link testvxlan while setting host mode: %v", err)
return
}
// If we are not able to move the vxlan interface to a namespace
// then fallback to host mode
if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil {
if err := nlh.LinkSetNsFd(iface, int(hNs)); err != nil {
hostMode = true
}
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
@ -23,15 +24,16 @@ func validateID(nid, eid string) error {
func createVethPair() (string, string, error) {
defer osl.InitOSContext()()
nlh := ns.NlHandle()
// Generate a name for what will be the host side pipe interface
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
name1, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
if err != nil {
return "", "", fmt.Errorf("error generating veth name1: %v", err)
}
// Generate a name for what will be the sandbox side pipe interface
name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
name2, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
if err != nil {
return "", "", fmt.Errorf("error generating veth name2: %v", err)
}
@ -40,7 +42,7 @@ func createVethPair() (string, string, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
PeerName: name2}
if err := netlink.LinkAdd(veth); err != nil {
if err := nlh.LinkAdd(veth); err != nil {
return "", "", fmt.Errorf("error creating veth pair: %v", err)
}
@ -60,7 +62,7 @@ func createVxlan(name string, vni uint32) error {
L2miss: true,
}
if err := netlink.LinkAdd(vxlan); err != nil {
if err := ns.NlHandle().LinkAdd(vxlan); err != nil {
return fmt.Errorf("error creating vxlan interface: %v", err)
}
@ -70,12 +72,12 @@ func createVxlan(name string, vni uint32) error {
func deleteInterface(name string) error {
defer osl.InitOSContext()()
link, err := netlink.LinkByName(name)
link, err := ns.NlHandle().LinkByName(name)
if err != nil {
return fmt.Errorf("failed to find interface with name %s: %v", name, err)
}
if err := netlink.LinkDel(link); err != nil {
if err := ns.NlHandle().LinkDel(link); err != nil {
return fmt.Errorf("error deleting interface with name %s: %v", name, err)
}
@ -85,20 +87,9 @@ func deleteInterface(name string) error {
func deleteVxlanByVNI(path string, vni uint32) error {
defer osl.InitOSContext()()
var nlh *netlink.Handle
if path == "" {
var err error
nlh, err = netlink.NewHandle()
if err != nil {
return fmt.Errorf("failed to get netlink handle for current ns: %v", err)
}
} else {
var (
err error
ns netns.NsHandle
)
ns, err = netns.GetFromPath(path)
nlh := ns.NlHandle()
if path != "" {
ns, err := netns.GetFromPath(path)
if err != nil {
return fmt.Errorf("failed to get ns handle for %s: %v", path, err)
}
@ -108,8 +99,8 @@ func deleteVxlanByVNI(path string, vni uint32) error {
if err != nil {
return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err)
}
defer nlh.Delete()
}
defer nlh.Delete()
links, err := nlh.LinkList()
if err != nil {
@ -118,11 +109,10 @@ func deleteVxlanByVNI(path string, vni uint32) error {
for _, l := range links {
if l.Type() == "vxlan" && (vni == 0 || l.(*netlink.Vxlan).VxlanId == int(vni)) {
err = netlink.LinkDel(l)
err = nlh.LinkDel(l)
if err != nil {
return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
}
return nil
}
}

View file

@ -969,34 +969,24 @@ func TestNetworkQuery(t *testing.T) {
const containerID = "valid_c"
func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
origns, err := netns.Get()
if err != nil {
t.Fatalf("Could not get the current netns: %v", err)
}
defer origns.Close()
key := info.Sandbox().Key()
f, err := os.OpenFile(key, os.O_RDONLY, 0)
sbNs, err := netns.GetFromPath(key)
if err != nil {
t.Fatalf("Failed to open network namespace path %q: %v", key, err)
t.Fatalf("Failed to get network namespace path %q: %v", key, err)
}
defer f.Close()
defer sbNs.Close()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
nsFD := f.Fd()
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err)
nh, err := netlink.NewHandleAt(sbNs)
if err != nil {
t.Fatal(err)
}
defer netns.Set(origns)
_, err = netlink.LinkByName("eth0")
_, err = nh.LinkByName("eth0")
if err != nil {
t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
}
_, err = netlink.LinkByName("eth1")
_, err = nh.LinkByName("eth1")
if err != nil {
t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err)
}
@ -1093,13 +1083,11 @@ func TestEndpointJoin(t *testing.T) {
}()
err = ep1.Join(sb)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep1.Leave(sb)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1162,10 +1150,8 @@ func TestEndpointJoin(t *testing.T) {
if err != nil {
t.Fatal(err)
}
runtime.LockOSThread()
defer func() {
err = ep2.Leave(sb)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1291,13 +1277,11 @@ func externalKeyTest(t *testing.T, reexec bool) {
// Join endpoint to sandbox before SetKey
err = ep.Join(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep.Leave(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1347,10 +1331,8 @@ func externalKeyTest(t *testing.T, reexec bool) {
if err != nil {
t.Fatal(err)
}
runtime.LockOSThread()
defer func() {
err = ep2.Leave(sbox)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1426,13 +1408,11 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
}()
err = ep.Join(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep.Leave(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1492,17 +1472,14 @@ func TestEndpointMultipleJoins(t *testing.T) {
if err := sbx2.Delete(); err != nil {
t.Fatal(err)
}
runtime.LockOSThread()
}()
err = ep.Join(sbx1)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep.Leave(sbx1)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1558,13 +1535,11 @@ func TestLeaveAll(t *testing.T) {
if err != nil {
t.Fatalf("Failed to join ep1: %v", err)
}
runtime.LockOSThread()
err = ep2.Join(cnt)
if err != nil {
t.Fatalf("Failed to join ep2: %v", err)
}
runtime.LockOSThread()
err = cnt.Delete()
if err != nil {
@ -1695,13 +1670,11 @@ func TestEndpointUpdateParent(t *testing.T) {
}()
err = ep1.Join(sbx1)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
err = ep2.Join(sbx2)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1924,7 +1897,6 @@ func TestResolvConf(t *testing.T) {
}()
err = ep.Join(sb1)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1950,7 +1922,6 @@ func TestResolvConf(t *testing.T) {
}
err = ep.Leave(sb1)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1970,7 +1941,6 @@ func TestResolvConf(t *testing.T) {
}()
err = ep.Join(sb2)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
@ -1989,13 +1959,11 @@ func TestResolvConf(t *testing.T) {
}
err = ep.Leave(sb2)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
err = ep.Join(sb2)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}

View file

@ -9,6 +9,7 @@ import (
"strings"
"github.com/docker/libnetwork/ipamutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/types"
@ -16,16 +17,18 @@ import (
)
var (
networkGetRoutesFct = netlink.RouteList
networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
)
// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
func CheckRouteOverlaps(toCheck *net.IPNet) error {
if networkGetRoutesFct == nil {
networkGetRoutesFct = ns.NlHandle().RouteList
}
networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
if err != nil {
return err
}
for _, network := range networks {
if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) {
return ErrNetworkOverlaps
@ -37,13 +40,18 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
// GenerateIfaceName returns an interface name using the passed in
// prefix and the length of random bytes. The api ensures that the
// there are is no interface which exists with that name.
func GenerateIfaceName(prefix string, len int) (string, error) {
func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
linkByName := netlink.LinkByName
if nlh != nil {
linkByName = nlh.LinkByName
}
for i := 0; i < 3; i++ {
name, err := GenerateRandomName(prefix, len)
if err != nil {
continue
}
if _, err := netlink.LinkByName(name); err != nil {
_, err = linkByName(name)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return name, nil
}
@ -67,13 +75,13 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
defer osl.InitOSContext()()
link, _ := netlink.LinkByName(name)
link, _ := ns.NlHandle().LinkByName(name)
if link != nil {
v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4)
v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, nil, err
}
v6addr, err := netlink.AddrList(link, netlink.FAMILY_V6)
v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
if err != nil {
return nil, nil, err
}

View file

@ -40,13 +40,8 @@ func TestOverlapingNameservers(t *testing.T) {
}
func TestCheckRouteOverlaps(t *testing.T) {
orig := networkGetRoutesFct
defer func() {
networkGetRoutesFct = orig
}()
networkGetRoutesFct = func(netlink.Link, int) ([]netlink.Route, error) {
routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
routes := []netlink.Route{}
for _, addr := range routesData {
_, netX, _ := net.ParseCIDR(addr)
@ -54,6 +49,7 @@ func TestCheckRouteOverlaps(t *testing.T) {
}
return routes, nil
}
defer func() { networkGetRoutesFct = nil }()
_, netX, _ := net.ParseCIDR("172.16.0.1/24")
if err := CheckRouteOverlaps(netX); err != nil {

View file

@ -3,13 +3,19 @@ package ns
import (
"fmt"
"os"
"sync"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
var initNs netns.NsHandle
var (
initNs netns.NsHandle
initNl *netlink.Handle
initOnce sync.Once
)
// Init initializes a new network namespace
func Init() {
@ -18,6 +24,10 @@ func Init() {
if err != nil {
log.Errorf("could not get initial namespace: %v", err)
}
initNl, err = netlink.NewHandle()
if err != nil {
log.Errorf("could not create netlink handle on initial namespace: %v", err)
}
}
// SetNamespace sets the initial namespace handler
@ -27,7 +37,6 @@ func SetNamespace() error {
if linkErr != nil {
linkInfo = linkErr.Error()
}
return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err)
}
return nil
@ -35,9 +44,21 @@ func SetNamespace() error {
// ParseHandlerInt transforms the namespace handler into an integer
func ParseHandlerInt() int {
return int(initNs)
return int(getHandler())
}
// GetHandler returns the namespace handler
func getHandler() netns.NsHandle {
initOnce.Do(Init)
return initNs
}
func getLink() (string, error) {
return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
}
// NlHandle returns the netlink handler
func NlHandle() *netlink.Handle {
initOnce.Do(Init)
return initNl
}

View file

@ -3,14 +3,15 @@ package osl
import (
"fmt"
"net"
"os/exec"
"regexp"
"sync"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
// IfaceOption is a function option type to set interface options
@ -126,52 +127,50 @@ func (i *nwIface) Remove() error {
i.Unlock()
n.Lock()
path := n.path
isDefault := n.isDefault
nlh := n.nlHandle
n.Unlock()
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
// Find the network inteerface identified by the DstName attribute.
iface, err := netlink.LinkByName(i.DstName())
if err != nil {
// Find the network inteerface identified by the DstName attribute.
iface, err := nlh.LinkByName(i.DstName())
if err != nil {
return err
}
// Down the interface before configuring
if err := nlh.LinkSetDown(iface); err != nil {
return err
}
err = nlh.LinkSetName(iface, i.SrcName())
if err != nil {
log.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
return err
}
// if it is a bridge just delete it.
if i.Bridge() {
if err := nlh.LinkDel(iface); err != nil {
return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
}
} else if !isDefault {
// Move the network interface to caller namespace.
if err := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); err != nil {
log.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
return err
}
}
// Down the interface before configuring
if err := netlink.LinkSetDown(iface); err != nil {
return err
n.Lock()
for index, intf := range n.iFaces {
if intf == i {
n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
break
}
}
n.Unlock()
err = netlink.LinkSetName(iface, i.SrcName())
if err != nil {
log.Debugf("LinkSetName failed for interface %s: %v", i.SrcName(), err)
return err
}
// if it is a bridge just delete it.
if i.Bridge() {
if err := netlink.LinkDel(iface); err != nil {
return fmt.Errorf("failed deleting bridge %q: %v", i.SrcName(), err)
}
} else if !isDefault {
// Move the network interface to caller namespace.
if err := netlink.LinkSetNsFd(iface, callerFD); err != nil {
log.Debugf("LinkSetNsPid failed for interface %s: %v", i.SrcName(), err)
return err
}
}
n.Lock()
for index, intf := range n.iFaces {
if intf == i {
n.iFaces = append(n.iFaces[:index], n.iFaces[index+1:]...)
break
}
}
n.Unlock()
return nil
})
return nil
}
// Returns the sandbox's side veth interface statistics
@ -180,28 +179,24 @@ func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
n := i.ns
i.Unlock()
n.Lock()
path := n.path
n.Unlock()
s := &types.InterfaceStatistics{}
err := nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
// For some reason ioutil.ReadFile(netStatsFile) reads the file in
// the default netns when this code is invoked from docker.
// Executing "cat <netStatsFile>" works as expected.
data, err := exec.Command("cat", netStatsFile).Output()
if err != nil {
return fmt.Errorf("failure opening %s: %v", netStatsFile, err)
}
return scanInterfaceStats(string(data), i.DstName(), s)
})
l, err := n.nlHandle.LinkByName(i.DstName())
if err != nil {
err = fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), path, err)
return nil, fmt.Errorf("failed to retrieve the statistics for %s in netns %s: %v", i.DstName(), n.path, err)
}
return s, err
stats := l.Attrs().Statistics
if stats == nil {
return nil, fmt.Errorf("no statistics were returned")
}
return &types.InterfaceStatistics{
RxBytes: uint64(stats.RxBytes),
TxBytes: uint64(stats.TxBytes),
RxPackets: uint64(stats.RxPackets),
TxPackets: uint64(stats.TxPackets),
RxDropped: uint64(stats.RxDropped),
TxDropped: uint64(stats.TxDropped),
}, nil
}
func (n *networkNamespace) findDst(srcName string, isBridge bool) string {
@ -241,17 +236,24 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
path := n.path
isDefault := n.isDefault
nlh := n.nlHandle
nlhHost := ns.NlHandle()
n.Unlock()
return nsInvoke(path, func(nsFD int) error {
// If it is a bridge interface we have to create the bridge inside
// the namespace so don't try to lookup the interface using srcName
if i.bridge {
return nil
// If it is a bridge interface we have to create the bridge inside
// the namespace so don't try to lookup the interface using srcName
if i.bridge {
link := &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: i.srcName,
},
}
if err := nlh.LinkAdd(link); err != nil {
return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
}
} else {
// Find the network interface identified by the SrcName attribute.
iface, err := netlink.LinkByName(i.srcName)
iface, err := nlhHost.LinkByName(i.srcName)
if err != nil {
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
}
@ -260,63 +262,54 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
// namespace only if the namespace is not a default
// type
if !isDefault {
if err := netlink.LinkSetNsFd(iface, nsFD); err != nil {
newNs, err := netns.GetFromPath(path)
if err != nil {
return fmt.Errorf("failed get network namespace %q: %v", path, err)
}
defer newNs.Close()
if err := nlhHost.LinkSetNsFd(iface, int(newNs)); err != nil {
return fmt.Errorf("failed to set namespace on link %q: %v", i.srcName, err)
}
}
}
return nil
}, func(callerFD int) error {
if i.bridge {
link := &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: i.srcName,
},
}
// Find the network interface identified by the SrcName attribute.
iface, err := nlh.LinkByName(i.srcName)
if err != nil {
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
}
if err := netlink.LinkAdd(link); err != nil {
return fmt.Errorf("failed to create bridge %q: %v", i.srcName, err)
}
}
// Down the interface before configuring
if err := nlh.LinkSetDown(iface); err != nil {
return fmt.Errorf("failed to set link down: %v", err)
}
// Find the network interface identified by the SrcName attribute.
iface, err := netlink.LinkByName(i.srcName)
if err != nil {
return fmt.Errorf("failed to get link by name %q: %v", i.srcName, err)
}
// Configure the interface now this is moved in the proper namespace.
if err := configureInterface(nlh, iface, i); err != nil {
return err
}
// Down the interface before configuring
if err := netlink.LinkSetDown(iface); err != nil {
return fmt.Errorf("failed to set link down: %v", err)
}
// Up the interface.
if err := nlh.LinkSetUp(iface); err != nil {
return fmt.Errorf("failed to set link up: %v", err)
}
// Configure the interface now this is moved in the proper namespace.
if err := configureInterface(iface, i); err != nil {
return err
}
// Set the routes on the interface. This can only be done when the interface is up.
if err := setInterfaceRoutes(nlh, iface, i); err != nil {
return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
}
// Up the interface.
if err := netlink.LinkSetUp(iface); err != nil {
return fmt.Errorf("failed to set link up: %v", err)
}
n.Lock()
n.iFaces = append(n.iFaces, i)
n.Unlock()
// Set the routes on the interface. This can only be done when the interface is up.
if err := setInterfaceRoutes(iface, i); err != nil {
return fmt.Errorf("error setting interface %q routes to %q: %v", iface.Attrs().Name, i.Routes(), err)
}
n.Lock()
n.iFaces = append(n.iFaces, i)
n.Unlock()
return nil
})
return nil
}
func configureInterface(iface netlink.Link, i *nwIface) error {
func configureInterface(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
ifaceName := iface.Attrs().Name
ifaceConfigurators := []struct {
Fn func(netlink.Link, *nwIface) error
Fn func(*netlink.Handle, netlink.Link, *nwIface) error
ErrMessage string
}{
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
@ -328,63 +321,63 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
}
for _, config := range ifaceConfigurators {
if err := config.Fn(iface, i); err != nil {
if err := config.Fn(nlh, iface, i); err != nil {
return fmt.Errorf("%s: %v", config.ErrMessage, err)
}
}
return nil
}
func setInterfaceMaster(iface netlink.Link, i *nwIface) error {
func setInterfaceMaster(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
if i.DstMaster() == "" {
return nil
}
return netlink.LinkSetMaster(iface, &netlink.Bridge{
return nlh.LinkSetMaster(iface, &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
}
func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
func setInterfaceMAC(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
if i.MacAddress() == nil {
return nil
}
return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
return nlh.LinkSetHardwareAddr(iface, i.MacAddress())
}
func setInterfaceIP(iface netlink.Link, i *nwIface) error {
func setInterfaceIP(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
if i.Address() == nil {
return nil
}
ipAddr := &netlink.Addr{IPNet: i.Address(), Label: ""}
return netlink.AddrAdd(iface, ipAddr)
return nlh.AddrAdd(iface, ipAddr)
}
func setInterfaceIPv6(iface netlink.Link, i *nwIface) error {
func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
if i.AddressIPv6() == nil {
return nil
}
ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
return netlink.AddrAdd(iface, ipAddr)
return nlh.AddrAdd(iface, ipAddr)
}
func setInterfaceLinkLocalIPs(iface netlink.Link, i *nwIface) error {
func setInterfaceLinkLocalIPs(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
for _, llIP := range i.LinkLocalAddresses() {
ipAddr := &netlink.Addr{IPNet: llIP}
if err := netlink.AddrAdd(iface, ipAddr); err != nil {
if err := nlh.AddrAdd(iface, ipAddr); err != nil {
return err
}
}
return nil
}
func setInterfaceName(iface netlink.Link, i *nwIface) error {
return netlink.LinkSetName(iface, i.DstName())
func setInterfaceName(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
return nlh.LinkSetName(iface, i.DstName())
}
func setInterfaceRoutes(iface netlink.Link, i *nwIface) error {
func setInterfaceRoutes(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error {
for _, route := range i.Routes() {
err := netlink.RouteAdd(&netlink.Route{
err := nlh.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_LINK,
LinkIndex: iface.Attrs().Index,
Dst: route,

View file

@ -42,6 +42,7 @@ type networkNamespace struct {
neighbors []*neigh
nextIfIndex int
isDefault bool
nlHandle *netlink.Handle
sync.Mutex
}
@ -147,7 +148,25 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
return nil, err
}
return &networkNamespace{path: key, isDefault: !osCreate}, nil
n := &networkNamespace{path: key, isDefault: !osCreate}
sboxNs, err := netns.GetFromPath(n.path)
if err != nil {
return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
}
defer sboxNs.Close()
n.nlHandle, err = netlink.NewHandleAt(sboxNs)
if err != nil {
return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
}
if err = n.loopbackUp(); err != nil {
n.nlHandle.Delete()
return nil, err
}
return n, nil
}
func (n *networkNamespace) InterfaceOptions() IfaceOptionSetter {
@ -159,30 +178,37 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
}
func mountNetworkNamespace(basePath string, lnPath string) error {
if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
return err
}
if err := loopbackUp(); err != nil {
return err
}
return nil
return syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, "")
}
// GetSandboxForExternalKey returns sandbox object for the supplied path
func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
var err error
if err = createNamespaceFile(key); err != nil {
if err := createNamespaceFile(key); err != nil {
return nil, err
}
n := &networkNamespace{path: basePath}
n.InvokeFunc(func() {
err = mountNetworkNamespace(basePath, key)
})
if err := mountNetworkNamespace(basePath, key); err != nil {
return nil, err
}
n := &networkNamespace{path: key}
sboxNs, err := netns.GetFromPath(n.path)
if err != nil {
return nil, fmt.Errorf("failed get network namespace %q: %v", n.path, err)
}
defer sboxNs.Close()
n.nlHandle, err = netlink.NewHandleAt(sboxNs)
if err != nil {
return nil, fmt.Errorf("failed to create a netlink handle: %v", err)
}
if err = n.loopbackUp(); err != nil {
n.nlHandle.Delete()
return nil, err
}
return &networkNamespace{path: key}, nil
return n, nil
}
func reexecCreateNamespace() {
@ -243,12 +269,12 @@ func createNamespaceFile(path string) (err error) {
return err
}
func loopbackUp() error {
iface, err := netlink.LinkByName("lo")
func (n *networkNamespace) loopbackUp() error {
iface, err := n.nlHandle.LinkByName("lo")
if err != nil {
return err
}
return netlink.LinkSetUp(iface)
return n.nlHandle.LinkSetUp(iface)
}
func (n *networkNamespace) InvokeFunc(f func()) error {
@ -260,33 +286,30 @@ func (n *networkNamespace) InvokeFunc(f func()) error {
// InitOSContext initializes OS context while configuring network resources
func InitOSContext() func() {
runtime.LockOSThread()
nsOnce.Do(ns.Init)
runtime.LockOSThread()
if err := ns.SetNamespace(); err != nil {
log.Error(err)
}
return runtime.UnlockOSThread
}
func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
defer InitOSContext()()
f, err := os.OpenFile(path, os.O_RDONLY, 0)
newNs, err := netns.GetFromPath(path)
if err != nil {
return fmt.Errorf("failed get network namespace %q: %v", path, err)
}
defer f.Close()
nsFD := f.Fd()
defer newNs.Close()
// Invoked before the namespace switch happens but after the namespace file
// handle is obtained.
if err := prefunc(int(nsFD)); err != nil {
if err := prefunc(int(newNs)); err != nil {
return fmt.Errorf("failed in prefunc: %v", err)
}
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
if err = netns.Set(newNs); err != nil {
return err
}
defer ns.SetNamespace()
@ -311,6 +334,9 @@ func (n *networkNamespace) Key() string {
}
func (n *networkNamespace) Destroy() error {
if n.nlHandle != nil {
n.nlHandle.Delete()
}
// Assuming no running process is executing in this network namespace,
// unmounting is sufficient to destroy it.
if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil {

View file

@ -33,53 +33,62 @@ func (n *networkNamespace) findNeighbor(dstIP net.IP, dstMac net.HardwareAddr) *
}
func (n *networkNamespace) DeleteNeighbor(dstIP net.IP, dstMac net.HardwareAddr) error {
var (
iface netlink.Link
err error
)
nh := n.findNeighbor(dstIP, dstMac)
if nh == nil {
return fmt.Errorf("could not find the neighbor entry to delete")
}
return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
var iface netlink.Link
n.Lock()
nlh := n.nlHandle
n.Unlock()
if nh.linkDst != "" {
var err error
iface, err = netlink.LinkByName(nh.linkDst)
if err != nil {
return fmt.Errorf("could not find interface with destination name %s: %v",
nh.linkDst, err)
}
if nh.linkDst != "" {
iface, err = nlh.LinkByName(nh.linkDst)
if err != nil {
return fmt.Errorf("could not find interface with destination name %s: %v",
nh.linkDst, err)
}
}
nlnh := &netlink.Neigh{
IP: dstIP,
State: netlink.NUD_PERMANENT,
Family: nh.family,
nlnh := &netlink.Neigh{
IP: dstIP,
State: netlink.NUD_PERMANENT,
Family: nh.family,
}
if nlnh.Family > 0 {
nlnh.HardwareAddr = dstMac
nlnh.Flags = netlink.NTF_SELF
}
if nh.linkDst != "" {
nlnh.LinkIndex = iface.Attrs().Index
}
if err := nlh.NeighDel(nlnh); err != nil {
return fmt.Errorf("could not delete neighbor entry: %v", err)
}
for i, nh := range n.neighbors {
if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
}
}
if nlnh.Family > 0 {
nlnh.HardwareAddr = dstMac
nlnh.Flags = netlink.NTF_SELF
}
if nh.linkDst != "" {
nlnh.LinkIndex = iface.Attrs().Index
}
if err := netlink.NeighDel(nlnh); err != nil {
return fmt.Errorf("could not delete neighbor entry: %v", err)
}
for i, nh := range n.neighbors {
if nh.dstIP.Equal(dstIP) && bytes.Equal(nh.dstMac, dstMac) {
n.neighbors = append(n.neighbors[:i], n.neighbors[i+1:]...)
}
}
return nil
})
return nil
}
func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, options ...NeighOption) error {
var (
iface netlink.Link
err error
)
nh := n.findNeighbor(dstIP, dstMac)
if nh != nil {
// If it exists silently return
@ -100,39 +109,38 @@ func (n *networkNamespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, op
}
}
return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
var iface netlink.Link
n.Lock()
nlh := n.nlHandle
n.Unlock()
if nh.linkDst != "" {
var err error
iface, err = netlink.LinkByName(nh.linkDst)
if err != nil {
return fmt.Errorf("could not find interface with destination name %s: %v",
nh.linkDst, err)
}
if nh.linkDst != "" {
iface, err = nlh.LinkByName(nh.linkDst)
if err != nil {
return fmt.Errorf("could not find interface with destination name %s: %v",
nh.linkDst, err)
}
}
nlnh := &netlink.Neigh{
IP: dstIP,
HardwareAddr: dstMac,
State: netlink.NUD_PERMANENT,
Family: nh.family,
}
nlnh := &netlink.Neigh{
IP: dstIP,
HardwareAddr: dstMac,
State: netlink.NUD_PERMANENT,
Family: nh.family,
}
if nlnh.Family > 0 {
nlnh.Flags = netlink.NTF_SELF
}
if nlnh.Family > 0 {
nlnh.Flags = netlink.NTF_SELF
}
if nh.linkDst != "" {
nlnh.LinkIndex = iface.Attrs().Index
}
if nh.linkDst != "" {
nlnh.LinkIndex = iface.Attrs().Index
}
if err := netlink.NeighSet(nlnh); err != nil {
return fmt.Errorf("could not add neighbor entry: %v", err)
}
if err := nlh.NeighSet(nlnh); err != nil {
return fmt.Errorf("could not add neighbor entry: %v", err)
}
n.neighbors = append(n.neighbors, nh)
n.neighbors = append(n.neighbors, nh)
return nil
})
return nil
}

View file

@ -53,7 +53,7 @@ func (n *networkNamespace) SetGateway(gw net.IP) error {
return nil
}
err := programGateway(n.nsPath(), gw, true)
err := n.programGateway(gw, true)
if err == nil {
n.setGateway(gw)
}
@ -69,7 +69,7 @@ func (n *networkNamespace) UnsetGateway() error {
return nil
}
err := programGateway(n.nsPath(), gw, false)
err := n.programGateway(gw, false)
if err == nil {
n.setGateway(net.IP{})
}
@ -77,60 +77,54 @@ func (n *networkNamespace) UnsetGateway() error {
return err
}
func programGateway(path string, gw net.IP, isAdd bool) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(gw)
if err != nil {
return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
}
func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error {
gwRoutes, err := n.nlHandle.RouteGet(gw)
if err != nil {
return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err)
}
if isAdd {
return netlink.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gw,
})
}
return netlink.RouteDel(&netlink.Route{
if isAdd {
return n.nlHandle.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gw,
})
}
return n.nlHandle.RouteDel(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: gw,
})
}
// Program a route in to the namespace routing table.
func programRoute(path string, dest *net.IPNet, nh net.IP) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
}
func (n *networkNamespace) programRoute(path string, dest *net.IPNet, nh net.IP) error {
gwRoutes, err := n.nlHandle.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err)
}
return netlink.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: nh,
Dst: dest,
})
return n.nlHandle.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: nh,
Dst: dest,
})
}
// Delete a route from the namespace routing table.
func removeRoute(path string, dest *net.IPNet, nh net.IP) error {
return nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
gwRoutes, err := netlink.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop could not be found: %v", err)
}
func (n *networkNamespace) removeRoute(path string, dest *net.IPNet, nh net.IP) error {
gwRoutes, err := n.nlHandle.RouteGet(nh)
if err != nil {
return fmt.Errorf("route for the next hop could not be found: %v", err)
}
return netlink.RouteDel(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: nh,
Dst: dest,
})
return n.nlHandle.RouteDel(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: gwRoutes[0].LinkIndex,
Gw: nh,
Dst: dest,
})
}
@ -140,7 +134,7 @@ func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error {
return nil
}
err := programGateway(n.nsPath(), gwv6, true)
err := n.programGateway(gwv6, true)
if err == nil {
n.setGatewayIPv6(gwv6)
}
@ -156,7 +150,7 @@ func (n *networkNamespace) UnsetGatewayIPv6() error {
return nil
}
err := programGateway(n.nsPath(), gwv6, false)
err := n.programGateway(gwv6, false)
if err == nil {
n.Lock()
n.gwv6 = net.IP{}
@ -167,7 +161,7 @@ func (n *networkNamespace) UnsetGatewayIPv6() error {
}
func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
err := programRoute(n.nsPath(), r.Destination, r.NextHop)
err := n.programRoute(n.nsPath(), r.Destination, r.NextHop)
if err == nil {
n.Lock()
n.staticRoutes = append(n.staticRoutes, r)
@ -178,7 +172,7 @@ func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error {
func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error {
err := removeRoute(n.nsPath(), r.Destination, r.NextHop)
err := n.removeRoute(n.nsPath(), r.Destination, r.NextHop)
if err == nil {
n.Lock()
lastIndex := len(n.staticRoutes) - 1

View file

@ -7,7 +7,6 @@ import (
"net"
"os"
"path/filepath"
"runtime"
"syscall"
"testing"
"time"
@ -54,11 +53,11 @@ func newKey(t *testing.T) (string, error) {
return name, nil
}
func newInfo(t *testing.T) (Sandbox, error) {
func newInfo(hnd *netlink.Handle, t *testing.T) (Sandbox, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
PeerName: vethName2}
if err := netlink.LinkAdd(veth); err != nil {
if err := hnd.LinkAdd(veth); err != nil {
return nil, err
}
@ -99,7 +98,7 @@ func newInfo(t *testing.T) (Sandbox, error) {
LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
PeerName: vethName4}
if err := netlink.LinkAdd(veth); err != nil {
if err := hnd.LinkAdd(veth); err != nil {
return nil, err
}
@ -123,29 +122,20 @@ func verifySandbox(t *testing.T, s Sandbox, ifaceSuffixes []string) {
t.Fatalf("The sandox interface returned is not of type networkNamespace")
}
origns, err := netns.Get()
if err != nil {
t.Fatalf("Could not get the current netns: %v", err)
}
defer origns.Close()
f, err := os.OpenFile(s.Key(), os.O_RDONLY, 0)
sbNs, err := netns.GetFromPath(s.Key())
if err != nil {
t.Fatalf("Failed top open network namespace path %q: %v", s.Key(), err)
}
defer f.Close()
defer sbNs.Close()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
nsFD := f.Fd()
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", s.Key(), err)
nh, err := netlink.NewHandleAt(sbNs)
if err != nil {
t.Fatal(err)
}
defer netns.Set(origns)
defer nh.Delete()
for _, suffix := range ifaceSuffixes {
_, err = netlink.LinkByName(sboxIfaceName + suffix)
_, err = nh.LinkByName(sboxIfaceName + suffix)
if err != nil {
t.Fatalf("Could not find the interface %s inside the sandbox: %v",
sboxIfaceName+suffix, err)
@ -207,23 +197,26 @@ func TestDisableIPv6DAD(t *testing.T) {
LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
PeerName: "sideB",
}
err := netlink.LinkAdd(veth)
nlh, err := netlink.NewHandle()
if err != nil {
t.Fatal(err)
}
err = nlh.LinkAdd(veth)
if err != nil {
t.Fatal(err)
}
link, err := netlink.LinkByName("sideA")
link, err := nlh.LinkByName("sideA")
if err != nil {
t.Fatal(err)
}
err = setInterfaceIPv6(link, iface)
err = setInterfaceIPv6(nlh, link, iface)
if err != nil {
t.Fatal(err)
}
addrList, err := netlink.AddrList(link, nl.FAMILY_V6)
addrList, err := nlh.AddrList(link, nl.FAMILY_V6)
if err != nil {
t.Fatal(err)
}

View file

@ -6,6 +6,7 @@ import (
"testing"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/testutils"
)
@ -34,7 +35,7 @@ func TestSandboxCreate(t *testing.T) {
t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key)
}
tbox, err := newInfo(t)
tbox, err := newInfo(ns.NlHandle(), t)
if err != nil {
t.Fatalf("Failed to generate new sandbox info: %v", err)
}
@ -47,23 +48,19 @@ func TestSandboxCreate(t *testing.T) {
if err != nil {
t.Fatalf("Failed to add interfaces to sandbox: %v", err)
}
runtime.LockOSThread()
}
err = s.SetGateway(tbox.Info().Gateway())
if err != nil {
t.Fatalf("Failed to set gateway to sandbox: %v", err)
}
runtime.LockOSThread()
err = s.SetGatewayIPv6(tbox.Info().GatewayIPv6())
if err != nil {
t.Fatalf("Failed to set ipv6 gateway to sandbox: %v", err)
}
runtime.LockOSThread()
verifySandbox(t, s, []string{"0", "1", "2"})
runtime.LockOSThread()
err = s.Destroy()
if err != nil {
@ -140,7 +137,7 @@ func TestAddRemoveInterface(t *testing.T) {
t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key)
}
tbox, err := newInfo(t)
tbox, err := newInfo(ns.NlHandle(), t)
if err != nil {
t.Fatalf("Failed to generate new sandbox info: %v", err)
}
@ -153,20 +150,16 @@ func TestAddRemoveInterface(t *testing.T) {
if err != nil {
t.Fatalf("Failed to add interfaces to sandbox: %v", err)
}
runtime.LockOSThread()
}
verifySandbox(t, s, []string{"0", "1", "2"})
runtime.LockOSThread()
interfaces := s.Info().Interfaces()
if err := interfaces[0].Remove(); err != nil {
t.Fatalf("Failed to remove interfaces from sandbox: %v", err)
}
runtime.LockOSThread()
verifySandbox(t, s, []string{"1", "2"})
runtime.LockOSThread()
i := tbox.Info().Interfaces()[0]
if err := s.AddInterface(i.SrcName(), i.DstName(),
@ -175,10 +168,8 @@ func TestAddRemoveInterface(t *testing.T) {
tbox.InterfaceOptions().AddressIPv6(i.AddressIPv6())); err != nil {
t.Fatalf("Failed to add interfaces to sandbox: %v", err)
}
runtime.LockOSThread()
verifySandbox(t, s, []string{"1", "2", "3"})
runtime.LockOSThread()
err = s.Destroy()
if err != nil {

View file

@ -239,7 +239,7 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
if currHash != "" && currHash != currRC.Hash {
// Seems the user has changed the container resolv.conf since the last time
// we checked so return without doing anything.
log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
//log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
return nil
}

View file

@ -13,7 +13,7 @@ import (
"github.com/docker/libnetwork/options"
)
func TestZooKeeperBackend(t *testing.T) {
func testZooKeeperBackend(t *testing.T) {
c, err := testNewController(t, "zk", "127.0.0.1:2181/custom_prefix")
if err != nil {
t.Fatal(err)

View file

@ -33,6 +33,8 @@ func SetupTestOSContext(t *testing.T) func() {
// sure to re-initialize initNs context
ns.Init()
runtime.LockOSThread()
return func() {
if err := syscall.Close(fd); err != nil {
t.Logf("Warning: netns closing failed (%v)", err)