Browse code

Allows to set generic knobs on the Sandbox

Refactor the ostweaks file to allows a more easy reuse
Add a method on the osl.Sandbox interface to allow setting
knobs on the sandbox

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2018/05/19 06:10:14
Showing 14 changed files
... ...
@@ -2,7 +2,6 @@ package main
2 2
 
3 3
 import (
4 4
 	"bytes"
5
-	"flag"
6 5
 	"fmt"
7 6
 	"io"
8 7
 	"io/ioutil"
... ...
@@ -12,10 +11,10 @@ import (
12 12
 	"time"
13 13
 
14 14
 	"github.com/ishidawataru/sctp"
15
+	// this takes care of the incontainer flag
16
+	_ "github.com/docker/libnetwork/testutils"
15 17
 )
16 18
 
17
-var _ = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
18
-
19 19
 var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
20 20
 var testBufSize = len(testBuf)
21 21
 
... ...
@@ -1144,6 +1144,11 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
1144 1144
 		}
1145 1145
 	}
1146 1146
 
1147
+	if sb.osSbox != nil {
1148
+		// Apply operating specific knobs on the load balancer sandbox
1149
+		sb.osSbox.ApplyOSTweaks(sb.oslTypes)
1150
+	}
1151
+
1147 1152
 	c.Lock()
1148 1153
 	c.sandboxes[sb.id] = sb
1149 1154
 	c.Unlock()
... ...
@@ -1,72 +1,23 @@
1 1
 package overlay
2 2
 
3 3
 import (
4
-	"io/ioutil"
5
-	"path"
6 4
 	"strconv"
7
-	"strings"
8 5
 
9
-	"github.com/sirupsen/logrus"
6
+	"github.com/docker/libnetwork/osl/kernel"
10 7
 )
11 8
 
12
-type conditionalCheck func(val1, val2 string) bool
13
-
14
-type osValue struct {
15
-	value   string
16
-	checkFn conditionalCheck
17
-}
18
-
19
-var osConfig = map[string]osValue{
9
+var ovConfig = map[string]*kernel.OSValue{
20 10
 	"net.ipv4.neigh.default.gc_thresh1": {"8192", checkHigher},
21 11
 	"net.ipv4.neigh.default.gc_thresh2": {"49152", checkHigher},
22 12
 	"net.ipv4.neigh.default.gc_thresh3": {"65536", checkHigher},
23 13
 }
24 14
 
25
-func propertyIsValid(val1, val2 string, check conditionalCheck) bool {
26
-	if check == nil || check(val1, val2) {
27
-		return true
28
-	}
29
-	return false
30
-}
31
-
32 15
 func checkHigher(val1, val2 string) bool {
33 16
 	val1Int, _ := strconv.ParseInt(val1, 10, 32)
34 17
 	val2Int, _ := strconv.ParseInt(val2, 10, 32)
35 18
 	return val1Int < val2Int
36 19
 }
37 20
 
38
-// writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
39
-// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
40
-func writeSystemProperty(key, value string) error {
41
-	keyPath := strings.Replace(key, ".", "/", -1)
42
-	return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
43
-}
44
-
45
-func readSystemProperty(key string) (string, error) {
46
-	keyPath := strings.Replace(key, ".", "/", -1)
47
-	value, err := ioutil.ReadFile(path.Join("/proc/sys", keyPath))
48
-	if err != nil {
49
-		return "", err
50
-	}
51
-	return string(value), nil
52
-}
53
-
54 21
 func applyOStweaks() {
55
-	for k, v := range osConfig {
56
-		// read the existing property from disk
57
-		oldv, err := readSystemProperty(k)
58
-		if err != nil {
59
-			logrus.Errorf("error reading the kernel parameter %s, error: %s", k, err)
60
-			continue
61
-		}
62
-
63
-		if propertyIsValid(oldv, v.value, v.checkFn) {
64
-			// write new prop value to disk
65
-			if err := writeSystemProperty(k, v.value); err != nil {
66
-				logrus.Errorf("error setting the kernel parameter %s = %s, (leaving as %s) error: %s", k, v.value, oldv, err)
67
-				continue
68
-			}
69
-			logrus.Debugf("updated kernel parameter %s = %s (was %s)", k, v.value, oldv)
70
-		}
71
-	}
22
+	kernel.ApplyOSTweaks(ovConfig)
72 23
 }
... ...
@@ -1,7 +1,6 @@
1 1
 package drvregistry
2 2
 
3 3
 import (
4
-	"flag"
5 4
 	"sort"
6 5
 	"testing"
7 6
 
... ...
@@ -13,10 +12,10 @@ import (
13 13
 	nullIpam "github.com/docker/libnetwork/ipams/null"
14 14
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
15 15
 	"github.com/stretchr/testify/assert"
16
-)
17 16
 
18
-var runningInContainer = flag.Bool("incontainer", false,
19
-	"Indicates if the test is running in a container")
17
+	// this takes care of the incontainer flag
18
+	_ "github.com/docker/libnetwork/testutils"
19
+)
20 20
 
21 21
 const mockDriverName = "mock-driver"
22 22
 
... ...
@@ -2125,7 +2125,8 @@ func (n *network) lbEndpointName() string {
2125 2125
 
2126 2126
 func (n *network) createLoadBalancerSandbox() (retErr error) {
2127 2127
 	sandboxName := n.lbSandboxName()
2128
-	sbOptions := []SandboxOption{}
2128
+	// Mark the sandbox to be a load balancer
2129
+	sbOptions := []SandboxOption{OptionLoadBalancer()}
2129 2130
 	if n.ingress {
2130 2131
 		sbOptions = append(sbOptions, OptionIngress())
2131 2132
 	}
... ...
@@ -1,7 +1,6 @@
1 1
 package networkdb
2 2
 
3 3
 import (
4
-	"flag"
5 4
 	"fmt"
6 5
 	"io/ioutil"
7 6
 	"log"
... ...
@@ -18,13 +17,13 @@ import (
18 18
 	"github.com/sirupsen/logrus"
19 19
 	"github.com/stretchr/testify/assert"
20 20
 	"github.com/stretchr/testify/require"
21
-)
22 21
 
23
-var (
24
-	dbPort             int32 = 10000
25
-	runningInContainer       = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
22
+	// this takes care of the incontainer flag
23
+	_ "github.com/docker/libnetwork/testutils"
26 24
 )
27 25
 
26
+var dbPort int32 = 10000
27
+
28 28
 func TestMain(m *testing.M) {
29 29
 	ioutil.WriteFile("/proc/sys/net/ipv6/conf/lo/disable_ipv6", []byte{'0', '\n'}, 0644)
30 30
 	logrus.SetLevel(logrus.ErrorLevel)
31 31
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+package kernel
1
+
2
+type conditionalCheck func(val1, val2 string) bool
3
+
4
+// OSValue represents a tuple, value defired, check function when to apply the value
5
+type OSValue struct {
6
+	Value   string
7
+	CheckFn conditionalCheck
8
+}
9
+
10
+func propertyIsValid(val1, val2 string, check conditionalCheck) bool {
11
+	if check == nil || check(val1, val2) {
12
+		return true
13
+	}
14
+	return false
15
+}
0 16
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+package kernel
1
+
2
+import (
3
+	"io/ioutil"
4
+	"path"
5
+	"strings"
6
+
7
+	"github.com/sirupsen/logrus"
8
+)
9
+
10
+// writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
11
+// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
12
+func writeSystemProperty(key, value string) error {
13
+	keyPath := strings.Replace(key, ".", "/", -1)
14
+	return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
15
+}
16
+
17
+// readSystemProperty reads the value from the path under /proc/sys and returns it
18
+func readSystemProperty(key string) (string, error) {
19
+	keyPath := strings.Replace(key, ".", "/", -1)
20
+	value, err := ioutil.ReadFile(path.Join("/proc/sys", keyPath))
21
+	if err != nil {
22
+		return "", err
23
+	}
24
+	return strings.TrimSpace(string(value)), nil
25
+}
26
+
27
+// ApplyOSTweaks applies the configuration values passed as arguments
28
+func ApplyOSTweaks(osConfig map[string]*OSValue) {
29
+	for k, v := range osConfig {
30
+		// read the existing property from disk
31
+		oldv, err := readSystemProperty(k)
32
+		if err != nil {
33
+			logrus.WithError(err).Errorf("error reading the kernel parameter %s", k)
34
+			continue
35
+		}
36
+
37
+		if propertyIsValid(oldv, v.Value, v.CheckFn) {
38
+			// write new prop value to disk
39
+			if err := writeSystemProperty(k, v.Value); err != nil {
40
+				logrus.WithError(err).Errorf("error setting the kernel parameter %s = %s, (leaving as %s)", k, v.Value, oldv)
41
+				continue
42
+			}
43
+			logrus.Debugf("updated kernel parameter %s = %s (was %s)", k, v.Value, oldv)
44
+		}
45
+	}
46
+}
0 47
new file mode 100644
... ...
@@ -0,0 +1,33 @@
0
+package kernel
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/sirupsen/logrus"
6
+	"github.com/stretchr/testify/assert"
7
+
8
+	_ "github.com/docker/libnetwork/testutils"
9
+)
10
+
11
+func TestReadWriteKnobs(t *testing.T) {
12
+	for _, k := range []string{
13
+		"net.ipv4.neigh.default.gc_thresh1",
14
+		"net.ipv4.neigh.default.gc_thresh2",
15
+		"net.ipv4.neigh.default.gc_thresh3",
16
+	} {
17
+		// Check if the test is able to read the value
18
+		v, err := readSystemProperty(k)
19
+		if err != nil {
20
+			logrus.WithError(err).Warnf("Path %v not readable", k)
21
+			// the path is not there, skip this key
22
+			continue
23
+		}
24
+		// Test the write
25
+		assert.NoError(t, writeSystemProperty(k, "10000"))
26
+		newV, err := readSystemProperty(k)
27
+		assert.NoError(t, err)
28
+		assert.Equal(t, newV, "10000")
29
+		// Restore value
30
+		assert.NoError(t, writeSystemProperty(k, v))
31
+	}
32
+}
0 33
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !linux
1
+
2
+package kernel
3
+
4
+// ApplyOSTweaks applies the configuration values passed as arguments
5
+func ApplyOSTweaks(osConfig map[string]*OSValue) {
6
+}
... ...
@@ -16,6 +16,7 @@ import (
16 16
 
17 17
 	"github.com/docker/docker/pkg/reexec"
18 18
 	"github.com/docker/libnetwork/ns"
19
+	"github.com/docker/libnetwork/osl/kernel"
19 20
 	"github.com/docker/libnetwork/types"
20 21
 	"github.com/sirupsen/logrus"
21 22
 	"github.com/vishvananda/netlink"
... ...
@@ -29,13 +30,18 @@ func init() {
29 29
 }
30 30
 
31 31
 var (
32
-	once             sync.Once
33
-	garbagePathMap   = make(map[string]bool)
34
-	gpmLock          sync.Mutex
35
-	gpmWg            sync.WaitGroup
36
-	gpmCleanupPeriod = 60 * time.Second
37
-	gpmChan          = make(chan chan struct{})
38
-	prefix           = defaultPrefix
32
+	once               sync.Once
33
+	garbagePathMap     = make(map[string]bool)
34
+	gpmLock            sync.Mutex
35
+	gpmWg              sync.WaitGroup
36
+	gpmCleanupPeriod   = 60 * time.Second
37
+	gpmChan            = make(chan chan struct{})
38
+	prefix             = defaultPrefix
39
+	loadBalancerConfig = map[string]*kernel.OSValue{
40
+		// expires connection from the IPVS connection table when the backend is not available
41
+		// more info: https://github.com/torvalds/linux/blob/master/Documentation/networking/ipvs-sysctl.txt#L126:1
42
+		"net.ipv4.vs.expire_nodest_conn": {"1", nil},
43
+	}
39 44
 )
40 45
 
41 46
 // The networkNamespace type is the linux implementation of the Sandbox
... ...
@@ -630,3 +636,13 @@ func setIPv6(path, iface string, enable bool) error {
630 630
 	}
631 631
 	return nil
632 632
 }
633
+
634
+// ApplyOSTweaks applies linux configs on the sandbox
635
+func (n *networkNamespace) ApplyOSTweaks(types []SandboxType) {
636
+	for _, t := range types {
637
+		switch t {
638
+		case SandboxTypeLoadBalancer:
639
+			kernel.ApplyOSTweaks(loadBalancerConfig)
640
+		}
641
+	}
642
+}
... ...
@@ -7,6 +7,16 @@ import (
7 7
 	"github.com/docker/libnetwork/types"
8 8
 )
9 9
 
10
+// SandboxType specify the time of the sandbox, this can be used to apply special configs
11
+type SandboxType int
12
+
13
+const (
14
+	// SandboxTypeIngress indicates that the sandbox is for the ingress
15
+	SandboxTypeIngress = iota
16
+	// SandboxTypeLoadBalancer indicates that the sandbox is a load balancer
17
+	SandboxTypeLoadBalancer = iota
18
+)
19
+
10 20
 // Sandbox represents a network sandbox, identified by a specific key.  It
11 21
 // holds a list of Interfaces, routes etc, and more can be added dynamically.
12 22
 type Sandbox interface {
... ...
@@ -70,6 +80,9 @@ type Sandbox interface {
70 70
 
71 71
 	// restore sandbox
72 72
 	Restore(ifsopt map[string][]IfaceOption, routes []*types.StaticRoute, gw net.IP, gw6 net.IP) error
73
+
74
+	// ApplyOSTweaks applies operating system specific knobs on the sandbox
75
+	ApplyOSTweaks([]SandboxType)
73 76
 }
74 77
 
75 78
 // NeighborOptionSetter interface defines the option setter methods for interface options
... ...
@@ -83,6 +83,7 @@ type sandbox struct {
83 83
 	inDelete           bool
84 84
 	ingress            bool
85 85
 	ndotsSet           bool
86
+	oslTypes           []osl.SandboxType // slice of properties of this sandbox
86 87
 	sync.Mutex
87 88
 	// This mutex is used to serialize service related operation for an endpoint
88 89
 	// The lock is here because the endpoint is saved into the store so is not unique
... ...
@@ -1162,6 +1163,15 @@ func OptionPortMapping(portBindings []types.PortBinding) SandboxOption {
1162 1162
 func OptionIngress() SandboxOption {
1163 1163
 	return func(sb *sandbox) {
1164 1164
 		sb.ingress = true
1165
+		sb.oslTypes = append(sb.oslTypes, osl.SandboxTypeIngress)
1166
+	}
1167
+}
1168
+
1169
+// OptionLoadBalancer function returns an option setter for marking a
1170
+// sandbox as a load balancer sandbox.
1171
+func OptionLoadBalancer() SandboxOption {
1172
+	return func(sb *sandbox) {
1173
+		sb.oslTypes = append(sb.oslTypes, osl.SandboxTypeLoadBalancer)
1165 1174
 	}
1166 1175
 }
1167 1176
 
... ...
@@ -1,13 +1,13 @@
1 1
 package types
2 2
 
3 3
 import (
4
-	"flag"
5
-	"github.com/stretchr/testify/require"
6 4
 	"net"
7 5
 	"testing"
8
-)
9 6
 
10
-var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
7
+	"github.com/stretchr/testify/require"
8
+
9
+	_ "github.com/docker/libnetwork/testutils"
10
+)
11 11
 
12 12
 func TestTransportPortConv(t *testing.T) {
13 13
 	sform := "tcp/23"