Migrate libnetwork to use netlink.Handle
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
4c1ed2010b
commit
6d3fa9e0f2
37 changed files with 597 additions and 491 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue