diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 7a86239a8f..e3817e53fe 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -3,10 +3,13 @@ package bridge import ( "errors" "fmt" + "io/ioutil" "net" "os/exec" + "path/filepath" "strconv" "sync" + "syscall" "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/driverapi" @@ -772,6 +775,37 @@ func addToBridge(ifaceName, bridgeName string) error { return ioctlAddToBridge(iface, master) } +func setHairpinMode(link netlink.Link, enable bool) error { + err := netlink.LinkSetHairpin(link, enable) + if err != nil && err != syscall.EINVAL { + // If error is not EINVAL something else went wrong, bail out right away + return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v", + link.Attrs().Name, err) + } + + // Hairpin mode successfully set up + if err == nil { + return nil + } + + // The netlink method failed with EINVAL which is probably because of an older + // kernel. Try one more time via the sysfs method. + path := filepath.Join("/sys/class/net", link.Attrs().Name, "brport/hairpin_mode") + + var val []byte + if enable { + val = []byte{'1', '\n'} + } else { + val = []byte{'0', '\n'} + } + + if err := ioutil.WriteFile(path, val, 0644); err != nil { + return fmt.Errorf("unable to set hairpin mode on %s via sysfs: %v", link.Attrs().Name, err) + } + + return nil +} + func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { var ( ipv6Addr *net.IPNet @@ -902,7 +936,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn } if !config.EnableUserlandProxy { - err = netlink.LinkSetHairpin(host, true) + err = setHairpinMode(host, true) if err != nil { return err }