From db1a1174502b38f7a7c85bdeed1ea0108550a004 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 9 Apr 2014 15:41:14 +0200 Subject: [PATCH] Fix libcontainer network support on rhel6 It seems that netlink in older kernels, including RHEL6, does not support RTM_SETLINK with IFLA_MASTER. It just silently ignores it, reporting no error, causing netlink.NetworkSetMaster() to not do anything yet return no error. We fix this by introducing and using AddToBridge() in a very similar manner to CreateBridge(), which use the old ioctls directly. This fixes https://github.com/dotcloud/docker/issues/4668 Docker-DCO-1.1-Signed-off-by: Alexander Larsson (github: alexlarsson) --- libcontainer/network/network.go | 2 +- netlink/netlink_linux.go | 30 ++++++++++++++++++++++++++++++ netlink/netlink_unsupported.go | 4 ++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/libcontainer/network/network.go b/libcontainer/network/network.go index 8c7a4b6..f8dee45 100644 --- a/libcontainer/network/network.go +++ b/libcontainer/network/network.go @@ -50,7 +50,7 @@ func SetInterfaceMaster(name, master string) error { if err != nil { return err } - return netlink.NetworkSetMaster(iface, masterIface) + return netlink.AddToBridge(iface, masterIface) } func SetDefaultGateway(ip string) error { diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index f4aa92e..6de293d 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -19,6 +19,7 @@ const ( VETH_INFO_PEER = 1 IFLA_NET_NS_FD = 28 SIOC_BRADDBR = 0x89a0 + SIOC_BRADDIF = 0x89a2 ) var nextSeqNr int @@ -28,6 +29,11 @@ type ifreqHwaddr struct { IfruHwaddr syscall.RawSockaddr } +type ifreqIndex struct { + IfrnName [16]byte + IfruIndex int32 +} + func nativeEndian() binary.ByteOrder { var x uint32 = 0x01020304 if *(*byte)(unsafe.Pointer(&x)) == 0x01 { @@ -842,6 +848,30 @@ func CreateBridge(name string, setMacAddr bool) error { return nil } +// Add a slave to abridge device. This is more backward-compatible than +// netlink.NetworkSetMaster and works on RHEL 6. +func AddToBridge(iface, master *net.Interface) 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) + + ifr := ifreqIndex{} + copy(ifr.IfrnName[:], master.Name) + ifr.IfruIndex = int32(iface.Index) + + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDIF, uintptr(unsafe.Pointer(&ifr))); err != 0 { + return err + } + + return nil +} + func setBridgeMacAddress(s int, name string) error { ifr := ifreqHwaddr{} ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER diff --git a/netlink/netlink_unsupported.go b/netlink/netlink_unsupported.go index 00a3b3f..8a5531b 100644 --- a/netlink/netlink_unsupported.go +++ b/netlink/netlink_unsupported.go @@ -63,3 +63,7 @@ func NetworkLinkDown(iface *net.Interface) error { func CreateBridge(name string, setMacAddr bool) error { return ErrNotImplemented } + +func AddToBridge(iface, master *net.Interface) error { + return ErrNotImplemented +}