浏览代码

Merge pull request #2349 from DataDog/lbernail/ipvs-timeouts

IPVS: Add support for GetConfig/SetConfig
Flavio Crisciani 6 年之前
父节点
当前提交
ff7e9788f2
共有 3 个文件被更改,包括 103 次插入0 次删除
  1. 17 0
      libnetwork/ipvs/ipvs.go
  2. 31 0
      libnetwork/ipvs/ipvs_test.go
  3. 55 0
      libnetwork/ipvs/netlink.go

+ 17 - 0
libnetwork/ipvs/ipvs.go

@@ -68,6 +68,13 @@ type Destination struct {
 // DstStats defines IPVS destination (real server) statistics
 type DstStats SvcStats
 
+// Config defines IPVS timeout configuration
+type Config struct {
+	TimeoutTCP    time.Duration
+	TimeoutTCPFin time.Duration
+	TimeoutUDP    time.Duration
+}
+
 // Handle provides a namespace specific ipvs handle to program ipvs
 // rules.
 type Handle struct {
@@ -188,3 +195,13 @@ func (i *Handle) GetService(s *Service) (*Service, error) {
 
 	return res[0], nil
 }
+
+// GetConfig returns the current timeout configuration
+func (i *Handle) GetConfig() (*Config, error) {
+	return i.doGetConfigCmd()
+}
+
+// SetConfig set the current timeout configuration. 0: no change
+func (i *Handle) SetConfig(c *Config) error {
+	return i.doSetConfigCmd(c)
+}

+ 31 - 0
libnetwork/ipvs/ipvs_test.go

@@ -6,6 +6,7 @@ import (
 	"net"
 	"syscall"
 	"testing"
+	"time"
 
 	"github.com/docker/libnetwork/testutils"
 	"github.com/vishvananda/netlink"
@@ -342,3 +343,33 @@ func TestDestination(t *testing.T) {
 		}
 	}
 }
+
+func TestTimeouts(t *testing.T) {
+	if testutils.RunningOnCircleCI() {
+		t.Skip("Skipping as not supported on CIRCLE CI kernel")
+	}
+	defer testutils.SetupTestOSContext(t)()
+
+	i, err := New("")
+	assert.NilError(t, err)
+
+	_, err = i.GetConfig()
+	assert.NilError(t, err)
+
+	cfg := Config{66 * time.Second, 66 * time.Second, 66 * time.Second}
+	err = i.SetConfig(&cfg)
+	assert.NilError(t, err)
+
+	c2, err := i.GetConfig()
+	assert.NilError(t, err)
+	assert.DeepEqual(t, cfg, *c2)
+
+	//  A timeout value 0 means that the current timeout value of the corresponding entry is preserved
+	cfg = Config{77 * time.Second, 0 * time.Second, 77 * time.Second}
+	err = i.SetConfig(&cfg)
+	assert.NilError(t, err)
+
+	c3, err := i.GetConfig()
+	assert.NilError(t, err)
+	assert.DeepEqual(t, *c3, Config{77 * time.Second, 66 * time.Second, 77 * time.Second})
+}

+ 55 - 0
libnetwork/ipvs/netlink.go

@@ -12,6 +12,7 @@ import (
 	"sync"
 	"sync/atomic"
 	"syscall"
+	"time"
 	"unsafe"
 
 	"github.com/sirupsen/logrus"
@@ -503,6 +504,60 @@ func (i *Handle) doGetDestinationsCmd(s *Service, d *Destination) ([]*Destinatio
 	return res, nil
 }
 
+// parseConfig given a ipvs netlink response this function will respond with a valid config entry, an error otherwise
+func (i *Handle) parseConfig(msg []byte) (*Config, error) {
+	var c Config
+
+	//Remove General header for this message
+	hdr := deserializeGenlMsg(msg)
+	attrs, err := nl.ParseRouteAttr(msg[hdr.Len():])
+	if err != nil {
+		return nil, err
+	}
+
+	for _, attr := range attrs {
+		attrType := int(attr.Attr.Type)
+		switch attrType {
+		case ipvsCmdAttrTimeoutTCP:
+			c.TimeoutTCP = time.Duration(native.Uint32(attr.Value)) * time.Second
+		case ipvsCmdAttrTimeoutTCPFin:
+			c.TimeoutTCPFin = time.Duration(native.Uint32(attr.Value)) * time.Second
+		case ipvsCmdAttrTimeoutUDP:
+			c.TimeoutUDP = time.Duration(native.Uint32(attr.Value)) * time.Second
+		}
+	}
+
+	return &c, nil
+}
+
+// doGetConfigCmd a wrapper function to be used by GetConfig
+func (i *Handle) doGetConfigCmd() (*Config, error) {
+	msg, err := i.doCmdWithoutAttr(ipvsCmdGetConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	res, err := i.parseConfig(msg[0])
+	if err != nil {
+		return res, err
+	}
+	return res, nil
+}
+
+// doSetConfigCmd a wrapper function to be used by SetConfig
+func (i *Handle) doSetConfigCmd(c *Config) error {
+	req := newIPVSRequest(ipvsCmdSetConfig)
+	req.Seq = atomic.AddUint32(&i.seq, 1)
+
+	req.AddData(nl.NewRtAttr(ipvsCmdAttrTimeoutTCP, nl.Uint32Attr(uint32(c.TimeoutTCP.Seconds()))))
+	req.AddData(nl.NewRtAttr(ipvsCmdAttrTimeoutTCPFin, nl.Uint32Attr(uint32(c.TimeoutTCPFin.Seconds()))))
+	req.AddData(nl.NewRtAttr(ipvsCmdAttrTimeoutUDP, nl.Uint32Attr(uint32(c.TimeoutUDP.Seconds()))))
+
+	_, err := execute(i.sock, req, 0)
+
+	return err
+}
+
 // IPVS related netlink message format explained
 
 /* EACH NETLINK MSG is of the below format, this is what we will receive from execute() api.