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>
| ... | ... |
@@ -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 |
+} |
| ... | ... |
@@ -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" |