From 2d4a71360264ae351428ab7d0cdefcb6dafa56b1 Mon Sep 17 00:00:00 2001 From: Patrick Hemmer Date: Tue, 1 Jul 2014 19:56:00 -0400 Subject: [PATCH] enable hairpin mode on virtual interface bridge port This is to support being able to DNAT/MASQ traffic from a container back into itself (dotcloud/docker#4442) Docker-DCO-1.1-Signed-off-by: Patrick Hemmer (github: phemmer) --- netlink/netlink_linux.go | 24 ++++++++++++++++++++++++ network/network.go | 8 ++++++++ network/veth.go | 3 +++ 3 files changed, 35 insertions(+) diff --git a/netlink/netlink_linux.go b/netlink/netlink_linux.go index c858b112..93ebade5 100644 --- a/netlink/netlink_linux.go +++ b/netlink/netlink_linux.go @@ -7,6 +7,7 @@ import ( "math/rand" "net" "os" + "path/filepath" "sync/atomic" "syscall" "unsafe" @@ -1204,6 +1205,28 @@ func SetMacAddress(name, addr string) error { return nil } +func SetHairpinMode(iface *net.Interface, enabled bool) error { + sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode") + + sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0) + if err != nil { + return err + } + defer sysFile.Close() + + var writeVal []byte + if enabled { + writeVal = []byte("1") + } else { + writeVal = []byte("0") + } + if _, err := sysFile.Write(writeVal); err != nil { + return err + } + + return nil +} + func ChangeName(iface *net.Interface, newName string) error { if len(newName) >= IFNAMSIZ { return fmt.Errorf("Interface name %s too long", newName) @@ -1224,5 +1247,6 @@ func ChangeName(iface *net.Interface, newName string) error { if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 { return errno } + return nil } diff --git a/network/network.go b/network/network.go index 2c3499b6..ba8f6f74 100644 --- a/network/network.go +++ b/network/network.go @@ -95,3 +95,11 @@ func SetMtu(name string, mtu int) error { } return netlink.NetworkSetMTU(iface, mtu) } + +func SetHairpinMode(name string, enabled bool) error { + iface, err := net.InterfaceByName(name) + if err != nil { + return err + } + return netlink.SetHairpinMode(iface, enabled) +} diff --git a/network/veth.go b/network/veth.go index 3d7dc872..240da579 100644 --- a/network/veth.go +++ b/network/veth.go @@ -39,6 +39,9 @@ func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error { if err := SetMtu(name1, n.Mtu); err != nil { return err } + if err := SetHairpinMode(name1, true); err != nil { + return err + } if err := InterfaceUp(name1); err != nil { return err }