From 59ea541c803e2dab0a2895cc16f172a11a7e55ed Mon Sep 17 00:00:00 2001 From: kwanhur Date: Wed, 18 Mar 2020 19:55:03 +0800 Subject: [PATCH 1/3] Feature: support get ipvs info Signed-off-by: kwanhur --- constants.go | 7 +++++++ ipvs.go | 36 ++++++++++++++++++++++++++++++++++++ ipvs_test.go | 13 +++++++++++++ netlink.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/constants.go b/constants.go index efac4e3..6350bba 100644 --- a/constants.go +++ b/constants.go @@ -54,6 +54,13 @@ const ( ipvsCmdAttrTimeoutUDP ) +// Attributes used to describe an info +const ( + ipvsCmdAttrInfoUnspec int = iota + ipvsCmdAttrInfoVersion + ipvsCmdAttrInfoConnTableSize +) + // Attributes used to describe a service. Used inside nested attribute // ipvsCmdAttrService const ( diff --git a/ipvs.go b/ipvs.go index 61b6f0a..6b4883a 100644 --- a/ipvs.go +++ b/ipvs.go @@ -74,6 +74,24 @@ type Config struct { TimeoutUDP time.Duration } +// Info defines IPVS info +type Info struct { + Version *Version + ConnTableSize uint32 +} + +// Version defines IPVS version +type Version struct { + Major uint + Minor uint + Patch uint +} + +// String returns a string of IPVS version +func (v *Version) String() string { + return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) +} + // Handle provides a namespace specific ipvs handle to program ipvs // rules. type Handle struct { @@ -204,3 +222,21 @@ func (i *Handle) GetConfig() (*Config, error) { func (i *Handle) SetConfig(c *Config) error { return i.doSetConfigCmd(c) } + +// GetInfo returns info details from IPVS +func (i *Handle) GetInfo() (*Info, error) { + res, err := i.doGetInfoCmd() + if err != nil { + return nil, err + } + + ver := uint(res.version) + return &Info{ + Version: &Version{ + Major: (ver >> 16) & 0xff, + Minor: (ver >> 8) & 0xff, + Patch: ver & 0xff, + }, + ConnTableSize: res.connTableSize, + }, nil +} diff --git a/ipvs_test.go b/ipvs_test.go index 4054f6d..1ecba4f 100644 --- a/ipvs_test.go +++ b/ipvs_test.go @@ -371,6 +371,19 @@ func TestTimeouts(t *testing.T) { assert.DeepEqual(t, *c3, Config{77 * time.Second, 66 * time.Second, 77 * time.Second}) } +func TestInfo(t *testing.T) { + defer setupTestOSContext(t) + + i, err := New("") + assert.NilError(t, err) + + info, err := i.GetInfo() + assert.NilError(t, err) + assert.Check(t, info.Version != nil) + assert.Assert(t, info.Version.String() != "") + assert.Assert(t, info.ConnTableSize > 0) +} + // setupTestOSContext joins a new network namespace, and returns its associated // teardown function. // diff --git a/netlink.go b/netlink.go index 1a822da..cc65419 100644 --- a/netlink.go +++ b/netlink.go @@ -38,6 +38,11 @@ type ipvsFlags struct { mask uint32 } +type ipvsInfo struct { + version uint32 + connTableSize uint32 +} + func deserializeGenlMsg(b []byte) (hdr *genlMsgHdr) { return (*genlMsgHdr)(unsafe.Pointer(&b[0:unsafe.Sizeof(*hdr)][0])) } @@ -573,6 +578,44 @@ func (i *Handle) doSetConfigCmd(c *Config) error { return err } +// parseInfo given a ipvs netlink response this function will respond with a valid info entry, an error otherwise +func (i *Handle) parseInfo(msg []byte) (*ipvsInfo, error) { + var info ipvsInfo + + 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 ipvsCmdAttrInfoVersion: + info.version = native.Uint32(attr.Value) + case ipvsCmdAttrInfoConnTableSize: + info.connTableSize = native.Uint32(attr.Value) + } + } + + return &info, nil +} + +// doGetInfoCmd a wrapper function to be used by GetInfo +func (i *Handle) doGetInfoCmd() (*ipvsInfo, error) { + msg, err := i.doCmdWithoutAttr(ipvsCmdGetInfo) + if err != nil { + return nil, err + } + + res, err := i.parseInfo(msg[0]) + if err != nil { + return nil, err + } + + return res, nil +} + // IPVS related netlink message format explained /* EACH NETLINK MSG is of the below format, this is what we will receive from execute() api. From c5da3e3403a20759abbed33333c6304135c8ea67 Mon Sep 17 00:00:00 2001 From: kwanhur Date: Fri, 17 Sep 2021 16:50:43 +0800 Subject: [PATCH 2/3] feature add GetVersion api Signed-off-by: kwanhur --- ipvs.go | 25 +++++++++++++++++++------ ipvs_test.go | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ipvs.go b/ipvs.go index 6b4883a..98141c2 100644 --- a/ipvs.go +++ b/ipvs.go @@ -223,6 +223,14 @@ func (i *Handle) SetConfig(c *Config) error { return i.doSetConfigCmd(c) } +func toVersion(v uint) *Version { + return &Version{ + Major: (v >> 16) & 0xff, + Minor: (v >> 8) & 0xff, + Patch: v & 0xff, + } +} + // GetInfo returns info details from IPVS func (i *Handle) GetInfo() (*Info, error) { res, err := i.doGetInfoCmd() @@ -230,13 +238,18 @@ func (i *Handle) GetInfo() (*Info, error) { return nil, err } - ver := uint(res.version) return &Info{ - Version: &Version{ - Major: (ver >> 16) & 0xff, - Minor: (ver >> 8) & 0xff, - Patch: ver & 0xff, - }, + Version: toVersion(uint(res.version)), ConnTableSize: res.connTableSize, }, nil } + +// GetVersion returns version from IPVS +func (i *Handle) GetVersion() (*Version, error) { + res, err := i.doGetInfoCmd() + if err != nil { + return nil, err + } + + return toVersion(uint(res.version)), nil +} diff --git a/ipvs_test.go b/ipvs_test.go index 1ecba4f..25c9f4c 100644 --- a/ipvs_test.go +++ b/ipvs_test.go @@ -4,6 +4,7 @@ package ipvs import ( "net" + "regexp" "runtime" "syscall" "testing" @@ -44,6 +45,8 @@ var ( "Tunnel", "Route", } + + verRegexp = regexp.MustCompile(`^\d\.\d\.\d$`) ) func lookupFwMethod(fwMethod uint32) string { @@ -384,6 +387,17 @@ func TestInfo(t *testing.T) { assert.Assert(t, info.ConnTableSize > 0) } +func TestVersion(t *testing.T) { + defer setupTestOSContext(t) + + i, err := New("") + assert.NilError(t, err) + + ver, err := i.GetVersion() + assert.NilError(t, err) + assert.Assert(t, verRegexp.MatchString(ver.String())) +} + // setupTestOSContext joins a new network namespace, and returns its associated // teardown function. // From 8e3ca47e582f56430cdccdaebdb4484b3f87f1ed Mon Sep 17 00:00:00 2001 From: kwanhur Date: Fri, 17 Sep 2021 16:51:25 +0800 Subject: [PATCH 3/3] feature add GetConnectionTableSize api Signed-off-by: kwanhur --- ipvs.go | 10 ++++++++++ ipvs_test.go | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/ipvs.go b/ipvs.go index 98141c2..9507aa7 100644 --- a/ipvs.go +++ b/ipvs.go @@ -253,3 +253,13 @@ func (i *Handle) GetVersion() (*Version, error) { return toVersion(uint(res.version)), nil } + +// GetConnectionTableSize returns connection table size from IPVS +func (i *Handle) GetConnectionTableSize() (uint32, error) { + res, err := i.doGetInfoCmd() + if err != nil { + return 0, err + } + + return res.connTableSize, nil +} diff --git a/ipvs_test.go b/ipvs_test.go index 25c9f4c..5a3656e 100644 --- a/ipvs_test.go +++ b/ipvs_test.go @@ -398,6 +398,17 @@ func TestVersion(t *testing.T) { assert.Assert(t, verRegexp.MatchString(ver.String())) } +func TestConnTableSize(t *testing.T) { + defer setupTestOSContext(t) + + i, err := New("") + assert.NilError(t, err) + + size, err := i.GetConnectionTableSize() + assert.NilError(t, err) + assert.Assert(t, size > 0) +} + // setupTestOSContext joins a new network namespace, and returns its associated // teardown function. //