Merge pull request #2349 from DataDog/lbernail/ipvs-timeouts
IPVS: Add support for GetConfig/SetConfig
This commit is contained in:
commit
ff7e9788f2
3 changed files with 103 additions and 0 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue