Use sysfs to set hairpin mode

Set the hairpin mode using the sysfs interface which
looks like it is working all the way to the oldest
of RHEL6.6 kernels.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-07-23 13:00:36 -07:00
parent 413224ea84
commit 2dd9a6fa75
1 changed files with 35 additions and 1 deletions

View File

@ -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
}