From 6901ea51dc9f99b916bc189308543567cc72e1cb Mon Sep 17 00:00:00 2001 From: Madhu Venugopal Date: Thu, 30 Jul 2015 06:02:23 -0700 Subject: [PATCH] Prefer Netlink calls over ioctl As seen in https://github.com/docker/docker/issues/14738 there is general instability in the later kernels under race conditions when ioctl calls are used in parallel with netlink calls for various operations. (We are yet to narrow down to the exact root-cause on the kernel). For those older kernels which doesnt support some of the netlink APIs, we can fallback to using ioctl calls. Hence bringing back the original code that used netlink (https://github.com/docker/libnetwork/pull/349). Also, there was an existing bug in bridge creation using netlink which was setting bridge mac during bridge creation. That operation is not supported in the netlink library (and doesnt throw an error either). Included a fix for that condition by setting the bridge mac after creating the bridge. Signed-off-by: Madhu Venugopal --- libnetwork/drivers/bridge/bridge.go | 21 +++++++++++++++------ libnetwork/drivers/bridge/setup_device.go | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 0faa7588cc..8fc05ae64f 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -763,17 +763,26 @@ func (d *driver) DeleteNetwork(nid types.UUID) error { } func addToBridge(ifaceName, bridgeName string) error { - iface, err := net.InterfaceByName(ifaceName) + link, err := netlink.LinkByName(ifaceName) if err != nil { return fmt.Errorf("could not find interface %s: %v", ifaceName, err) } + if err = netlink.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) + if err != nil { + return fmt.Errorf("could not find network interface %s: %v", ifaceName, err) + } - master, err := net.InterfaceByName(bridgeName) - if err != nil { - return fmt.Errorf("could not find bridge %s: %v", bridgeName, err) + master, err := net.InterfaceByName(bridgeName) + if err != nil { + return fmt.Errorf("could not find bridge %s: %v", bridgeName, err) + } + + return ioctlAddToBridge(iface, master) } - - return ioctlAddToBridge(iface, master) + return nil } func setHairpinMode(link netlink.Link, enable bool) error { diff --git a/libnetwork/drivers/bridge/setup_device.go b/libnetwork/drivers/bridge/setup_device.go index f58be985b0..22bf64b2f7 100644 --- a/libnetwork/drivers/bridge/setup_device.go +++ b/libnetwork/drivers/bridge/setup_device.go @@ -1,8 +1,11 @@ package bridge import ( + "fmt" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/parsers/kernel" + "github.com/docker/libnetwork/netutils" "github.com/vishvananda/netlink" ) @@ -32,7 +35,19 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error { setMac = kv.Kernel > 3 || (kv.Kernel == 3 && kv.Major >= 3) } - return ioctlCreateBridge(config.BridgeName, setMac) + if err = netlink.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 { + return fmt.Errorf("failed to set bridge mac-address %s : %s", hwAddr, err.Error()) + } + logrus.Debugf("Setting bridge mac address to %s", hwAddr) + } + return err } // SetupDeviceUp ups the given bridge interface.