浏览代码

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>
Jana Radhakrishnan 10 年之前
父节点
当前提交
2dd9a6fa75
共有 1 个文件被更改,包括 35 次插入1 次删除
  1. 35 1
      libnetwork/drivers/bridge/bridge.go

+ 35 - 1
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
 		}