mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
![Madhu Venugopal](/assets/img/avatar_default.png)
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 <madhu@docker.com>
66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
package bridge
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
"github.com/docker/libnetwork/netutils"
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
// SetupDevice create a new bridge interface/
|
|
func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
|
|
var setMac bool
|
|
|
|
// We only attempt to create the bridge when the requested device name is
|
|
// the default one.
|
|
if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
|
|
return NonDefaultBridgeExistError(config.BridgeName)
|
|
}
|
|
|
|
// Set the bridgeInterface netlink.Bridge.
|
|
i.Link = &netlink.Bridge{
|
|
LinkAttrs: netlink.LinkAttrs{
|
|
Name: config.BridgeName,
|
|
},
|
|
}
|
|
|
|
// Only set the bridge's MAC address if the kernel version is > 3.3, as it
|
|
// was not supported before that.
|
|
kv, err := kernel.GetKernelVersion()
|
|
if err != nil {
|
|
logrus.Errorf("Failed to check kernel versions: %v. Will not assign a MAC address to the bridge interface", err)
|
|
} else {
|
|
setMac = kv.Kernel > 3 || (kv.Kernel == 3 && kv.Major >= 3)
|
|
}
|
|
|
|
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.
|
|
func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
|
|
err := netlink.LinkSetUp(i.Link)
|
|
if err != nil {
|
|
return 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 {
|
|
i.Link = lnk
|
|
}
|
|
return nil
|
|
}
|