Merge pull request #2993 from weaveworks/hairpin-option-1.9

Turn on hairpin mode on veth bridge ports
This commit is contained in:
Bryan Boreham authored and GitHub committed 2017-05-30 14:50:37 +01:00
commit 68f2cb9caa
6 files changed
+80 -12

No files matched your search

+6 -2
View File
@@ -113,7 +113,7 @@ func interfaceExistsInNamespace(netNSPath string, ifName string) bool {
// NB: This function can be used only by a process that terminates immediately
// after calling the function as it changes netns via WithNetNSLinkUnsafe.
func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error {
func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool, hairpinMode bool) error {
ns, err := netns.GetFromPath(netNSPath)
if err != nil {
return err
@@ -131,7 +131,7 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
id = id[:maxIDLen] // trim passed ID if too long
}
name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id
_, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error {
veth, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error {
if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil {
return fmt.Errorf("failed to move veth to container netns: %s", err)
}
@@ -143,6 +143,10 @@ func AttachContainer(netNSPath, id, ifName, bridgeName string, mtu int, withMult
if err != nil {
return err
}
if err = netlink.LinkSetHairpin(veth, hairpinMode); err != nil {
return fmt.Errorf("unable to set hairpin mode to %t for bridge side of veth %s: %s", hairpinMode, name, err)
}
}
if err := WithNetNSLinkUnsafe(ns, ifName, func(veth netlink.Link) error {
+8 -6
View File
@@ -34,7 +34,8 @@ func NewCNIPlugin(weave *weaveapi.Client) *CNIPlugin {
func loadNetConf(bytes []byte) (*NetConf, error) {
n := &NetConf{
BrName: weavenet.WeaveBridgeName,
BrName: weavenet.WeaveBridgeName,
HairpinMode: true,
}
if err := json.Unmarshal(bytes, n); err != nil {
return nil, fmt.Errorf("failed to load netconf: %v", err)
@@ -128,7 +129,7 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
id = fmt.Sprintf("%x", data)
}
if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&ip.Address}, false); err != nil {
if err := weavenet.AttachContainer(args.Netns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&ip.Address}, false, conf.HairpinMode); err != nil {
return err
}
if err := weavenet.WithNetNSLinkUnsafe(ns, args.IfName, func(link netlink.Link) error {
@@ -218,8 +219,9 @@ func logOnStderr(err error) {
type NetConf struct {
types.NetConf
BrName string `json:"bridge"`
IsGW bool `json:"isGateway"`
IPMasq bool `json:"ipMasq"`
MTU int `json:"mtu"`
BrName string `json:"bridge"`
IsGW bool `json:"isGateway"`
IPMasq bool `json:"ipMasq"`
MTU int `json:"mtu"`
HairpinMode bool `json:"hairpinMode"`
}
+6 -2
View File
@@ -14,11 +14,12 @@ import (
func attach(args []string) error {
if len(args) < 4 {
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] <container-id> <bridge-name> <mtu> <cidr>...")
cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] [--hairpin-mode=true|false] <container-id> <bridge-name> <mtu> <cidr>...")
}
keepTXOn := false
withMulticastRoute := true
hairpinMode := true
for i := 0; i < len(args); {
switch args[i] {
case "--no-multicast-route":
@@ -27,6 +28,9 @@ func attach(args []string) error {
case "--keep-tx-on":
keepTXOn = true
args = append(args[:i], args[i+1:]...)
case "--hairpin-mode=false":
hairpinMode = false
args = append(args[:i], args[i+1:]...)
default:
i++
}
@@ -55,7 +59,7 @@ func attach(args []string) error {
return err
}
err = weavenet.AttachContainer(weavenet.NSPathByPid(pid), fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs, keepTXOn)
err = weavenet.AttachContainer(weavenet.NSPathByPid(pid), fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs, keepTXOn, hairpinMode)
// If we detected an error but the container has died, tell the user that instead.
if err != nil && !processExists(pid) {
err = fmt.Errorf("Container %s died", args[0])
+4
View File
@@ -241,3 +241,7 @@ The list of variables you can set is:
a larger size for better performance if your network supports jumbo
frames - see [here](/site/using-weave/fastdp.md#mtu) for more
details.
* `HAIRPIN_MODE` - Weave Net defaults to enabling hairpin on the bridge side of
the `veth` pair for containers attached. If you need to disable hairpin, e.g. your
kernel is one of those that can panic if hairpin is enabled, then you can disable it
by setting `HAIRPIN_MODE=false`.
+51
View File
@@ -19,6 +19,11 @@ weave_on $HOST1 launch
C0=$(docker_on $HOST1 run --net=none --name=c0 -dt $SMALL_IMAGE /bin/sh)
C1=$(docker_on $HOST1 run --net=none --privileged --name=c1 -dt $SMALL_IMAGE /bin/sh)
C2=$(docker_on $HOST1 run --net=none --name=c2 -dt $SMALL_IMAGE /bin/sh)
CH0=$(docker_on $HOST1 run --net=none --name=ch0 -dt $SMALL_IMAGE /bin/sh)
CH1=$(docker_on $HOST1 run --net=none --name=ch1 -dt $SMALL_IMAGE /bin/sh)
CH2=$(docker_on $HOST1 run --net=none --name=ch2 -dt $SMALL_IMAGE /bin/sh)
# Enable unsolicited ARPs so that ping after the address reuse does not time out
exec_on $HOST1 c1 sysctl -w net.ipv4.conf.all.arp_accept=1
@@ -52,6 +57,29 @@ cni_connect $HOST1 c2 <<EOF
}
EOF
# examples to test hairpin
cni_connect $HOST1 ch0 <<EOF
{
"name": "weave",
"type": "weave-net",
"hairpinMode": true
}
EOF
cni_connect $HOST1 ch1 <<EOF
{
"name": "weave",
"type": "weave-net",
"hairpinMode": false
}
EOF
cni_connect $HOST1 ch2 <<EOF
{
"name": "weave",
"type": "weave-net"
}
EOF
C0IP=$(container_ip $HOST1 c0)
C1IP=$(container_ip $HOST1 c1)
C2IP=$(container_ip $HOST1 c2)
@@ -85,6 +113,29 @@ assert_raises "[ $C2IP != $C3IP ]"
assert_raises "[ $BRIP != $C3IP ]"
assert_raises "exec_on $HOST1 c1 $PING $C3IP"
#####
#
# Hairpin mode tests
#
# here we check that the bridge side of the veth is set to hairpin mode (true or false) correctly
# check for each of
# - ch0 explicitly true
# - ch1 explicitly false
# - ch2 unset, which should default to true
#
# we take advantage of the veth name being constructed from the container ID)
#
# should this reliance ever fail and we need to get it from the system, do the following for each:
# CH0_PEER_ID=$(exec_on $HOST1 ch0 cat /sys/class/net/eth0/iflink)
# CH0_PEER=$($SSH $HOST1 ip link show | awk "/^${CH0_PEER_ID}:/"' {print $2}' | sed 's/@.*$//g' )
# CH0_HAIRPIN=$($SSH $HOST1 cat /sys/devices/virtual/net/weave/brif/$CH0_PEER/hairpin_mode)
# assert_raises "[ $CH0_HAIRPIN == 1 ]"
#
assert "$SSH $HOST1 cat /sys/devices/virtual/net/weave/brif/vethwepl${CH0:0:7}/hairpin_mode" "1"
assert "$SSH $HOST1 cat /sys/devices/virtual/net/weave/brif/vethwepl${CH1:0:7}/hairpin_mode" "0"
assert "$SSH $HOST1 cat /sys/devices/virtual/net/weave/brif/vethwepl${CH2:0:7}/hairpin_mode" "1"
# Ensure existing containers can reclaim their IP addresses after CNI has been used -- see #2548
stop_weave_on $HOST1
+5 -2
View File
@@ -1070,17 +1070,20 @@ create_cni_config() {
cat >"$1" <<EOF
{
"name": "weave",
"type": "weave-net"
"type": "weave-net",
"hairpinMode": $2
}
EOF
}
setup_cni() {
# if env var HAIRPIN_MODE is not set, default it to true
HAIRPIN_MODE=${HAIRPIN_MODE:-true}
if install_cni_plugin $CNI_PLUGIN_DIR ; then
upgrade_cni_plugin $CNI_PLUGIN_DIR
fi
if [ -d $HOST_ROOT/etc/cni/net.d -a ! -f $HOST_ROOT/etc/cni/net.d/10-weave.conf ] ; then
create_cni_config $HOST_ROOT/etc/cni/net.d/10-weave.conf
create_cni_config $HOST_ROOT/etc/cni/net.d/10-weave.conf $HAIRPIN_MODE
fi
}