From 4cdcea20474a9f42291fe6b6c6dee348343a7c05 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 31 Mar 2014 21:02:42 +0000 Subject: [PATCH] Set bridge mac addr on supported kernels Fixes #3200 Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/netlink/netlink_linux.go | 51 ++++++++++++++++++++++++++ pkg/netlink/netlink_unsupported.go | 4 ++ runtime/networkdriver/bridge/driver.go | 30 +++------------ 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/pkg/netlink/netlink_linux.go b/pkg/netlink/netlink_linux.go index f8bb6bac3c..f4aa92ed34 100644 --- a/pkg/netlink/netlink_linux.go +++ b/pkg/netlink/netlink_linux.go @@ -5,6 +5,7 @@ package netlink import ( "encoding/binary" "fmt" + "math/rand" "net" "syscall" "unsafe" @@ -17,10 +18,16 @@ const ( IFLA_INFO_DATA = 2 VETH_INFO_PEER = 1 IFLA_NET_NS_FD = 28 + SIOC_BRADDBR = 0x89a0 ) var nextSeqNr int +type ifreqHwaddr struct { + IfrnName [16]byte + IfruHwaddr syscall.RawSockaddr +} + func nativeEndian() binary.ByteOrder { var x uint32 = 0x01020304 if *(*byte)(unsafe.Pointer(&x)) == 0x01 { @@ -808,3 +815,47 @@ func NetworkCreateVethPair(name1, name2 string) error { } return s.HandleAck(wb.Seq) } + +// Create the actual bridge device. This is more backward-compatible than +// netlink.NetworkLinkAdd and works on RHEL 6. +func CreateBridge(name string, setMacAddr bool) error { + s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP) + if err != nil { + // ipv6 issue, creating with ipv4 + s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP) + if err != nil { + return err + } + } + defer syscall.Close(s) + + nameBytePtr, err := syscall.BytePtrFromString(name) + if err != nil { + return err + } + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 { + return err + } + if setMacAddr { + return setBridgeMacAddress(s, name) + } + return nil +} + +func setBridgeMacAddress(s int, name string) error { + ifr := ifreqHwaddr{} + ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER + copy(ifr.IfrnName[:], name) + + for i := 0; i < 6; i++ { + ifr.IfruHwaddr.Data[i] = int8(rand.Intn(255)) + } + + ifr.IfruHwaddr.Data[0] &^= 0x1 // clear multicast bit + ifr.IfruHwaddr.Data[0] |= 0x2 // set local assignment bit (IEEE802) + + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 { + return err + } + return nil +} diff --git a/pkg/netlink/netlink_unsupported.go b/pkg/netlink/netlink_unsupported.go index bd9e962d35..00a3b3fae8 100644 --- a/pkg/netlink/netlink_unsupported.go +++ b/pkg/netlink/netlink_unsupported.go @@ -59,3 +59,7 @@ func NetworkSetMaster(iface, master *net.Interface) error { func NetworkLinkDown(iface *net.Interface) error { return ErrNotImplemented } + +func CreateBridge(name string, setMacAddr bool) error { + return ErrNotImplemented +} diff --git a/runtime/networkdriver/bridge/driver.go b/runtime/networkdriver/bridge/driver.go index 61e82dd481..f7c3bc6b01 100644 --- a/runtime/networkdriver/bridge/driver.go +++ b/runtime/networkdriver/bridge/driver.go @@ -14,13 +14,10 @@ import ( "log" "net" "strings" - "syscall" - "unsafe" ) const ( DefaultNetworkBridge = "docker0" - siocBRADDBR = 0x89a0 ) // Network interface represents the networking stack of a container @@ -281,28 +278,13 @@ func createBridge(bridgeIP string) error { return nil } -// Create the actual bridge device. This is more backward-compatible than -// netlink.NetworkLinkAdd and works on RHEL 6. func createBridgeIface(name string) error { - s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP) - if err != nil { - utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err) - s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP) - if err != nil { - return fmt.Errorf("Error creating bridge creation socket: %s", err) - } - } - defer syscall.Close(s) - - nameBytePtr, err := syscall.BytePtrFromString(name) - if err != nil { - return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err) - } - - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 { - return fmt.Errorf("Error creating bridge: %s", err) - } - return nil + kv, err := utils.GetKernelVersion() + // only set the bridge's mac address if the kernel version is > 3.3 + // before that it was not supported + setBridgeMacAddr := err == nil && (kv.Kernel >= 3 && kv.Major >= 3) + utils.Debugf("setting bridge mac address = %v", setBridgeMacAddr) + return netlink.CreateBridge(name, setBridgeMacAddr) } // Allocate a network interface