From 71fa81e220b5dc091ae728ddfcba4b83abf24c94 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 27 Oct 2017 11:58:20 -0700 Subject: [PATCH] Expose xfrm state's current and window statistics - aggregate window stats with packet counter stats Signed-off-by: Alessandro Boch --- xfrm_state.go | 27 ++++++++++++++++++++++++--- xfrm_state_linux.go | 11 +++++++++++ xfrm_state_test.go | 21 +++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/xfrm_state.go b/xfrm_state.go index 368a9b9..d14740d 100644 --- a/xfrm_state.go +++ b/xfrm_state.go @@ -3,6 +3,7 @@ package netlink import ( "fmt" "net" + "time" ) // XfrmStateAlgo represents the algorithm to use for the ipsec encryption. @@ -67,6 +68,19 @@ type XfrmStateLimits struct { TimeUseHard uint64 } +// XfrmStateStats represents the current number of bytes/packets +// processed by this State, the State's installation and first use +// time and the replay window counters. +type XfrmStateStats struct { + ReplayWindow uint32 + Replay uint32 + Failed uint32 + Bytes uint64 + Packets uint64 + AddTime uint64 + UseTime uint64 +} + // XfrmState represents the state of an ipsec policy. It optionally // contains an XfrmStateAlgo for encryption and one for authentication. type XfrmState struct { @@ -78,6 +92,7 @@ type XfrmState struct { Reqid int ReplayWindow int Limits XfrmStateLimits + Statistics XfrmStateStats Mark *XfrmMark Auth *XfrmStateAlgo Crypt *XfrmStateAlgo @@ -94,10 +109,16 @@ func (sa XfrmState) Print(stats bool) string { if !stats { return sa.String() } - - return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d", + at := time.Unix(int64(sa.Statistics.AddTime), 0).Format(time.UnixDate) + ut := "-" + if sa.Statistics.UseTime > 0 { + ut = time.Unix(int64(sa.Statistics.UseTime), 0).Format(time.UnixDate) + } + return fmt.Sprintf("%s, ByteSoft: %s, ByteHard: %s, PacketSoft: %s, PacketHard: %s, TimeSoft: %d, TimeHard: %d, TimeUseSoft: %d, TimeUseHard: %d, Bytes: %d, Packets: %d, "+ + "AddTime: %s, UseTime: %s, ReplayWindow: %d, Replay: %d, Failed: %d", sa.String(), printLimit(sa.Limits.ByteSoft), printLimit(sa.Limits.ByteHard), printLimit(sa.Limits.PacketSoft), printLimit(sa.Limits.PacketHard), - sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard) + sa.Limits.TimeSoft, sa.Limits.TimeHard, sa.Limits.TimeUseSoft, sa.Limits.TimeUseHard, sa.Statistics.Bytes, sa.Statistics.Packets, at, ut, + sa.Statistics.ReplayWindow, sa.Statistics.Replay, sa.Statistics.Failed) } func printLimit(lmt uint64) string { diff --git a/xfrm_state_linux.go b/xfrm_state_linux.go index 08b6be0..7fc9290 100644 --- a/xfrm_state_linux.go +++ b/xfrm_state_linux.go @@ -308,6 +308,7 @@ func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState { state.Reqid = int(msg.Reqid) state.ReplayWindow = int(msg.ReplayWindow) lftToLimits(&msg.Lft, &state.Limits) + curToStats(&msg.Curlft, &msg.Stats, &state.Statistics) return &state } @@ -429,6 +430,16 @@ func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) { *lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft)) } +func curToStats(cur *nl.XfrmLifetimeCur, wstats *nl.XfrmStats, stats *XfrmStateStats) { + stats.Bytes = cur.Bytes + stats.Packets = cur.Packets + stats.AddTime = cur.AddTime + stats.UseTime = cur.UseTime + stats.ReplayWindow = wstats.ReplayWindow + stats.Replay = wstats.Replay + stats.Failed = wstats.IntegrityFailed +} + func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo { msg := &nl.XfrmUsersaInfo{} msg.Family = uint16(nl.GetIPFamily(state.Dst)) diff --git a/xfrm_state_test.go b/xfrm_state_test.go index ec5dfb6..45a58aa 100644 --- a/xfrm_state_test.go +++ b/xfrm_state_test.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "net" "testing" + "time" ) func TestXfrmStateAddGetDel(t *testing.T) { @@ -180,6 +181,26 @@ func TestXfrmStateUpdateLimits(t *testing.T) { } } +func TestXfrmStateStats(t *testing.T) { + setUpNetlinkTest(t)() + + // Program state and record time + state := getBaseState() + now := time.Now() + if err := XfrmStateAdd(state); err != nil { + t.Fatal(err) + } + // Retrieve state + s, err := XfrmStateGet(state) + if err != nil { + t.Fatal(err) + } + // Verify stats: We expect zero counters, same second add time and unset use time + if s.Statistics.Bytes != 0 || s.Statistics.Packets != 0 || s.Statistics.AddTime != uint64(now.Unix()) || s.Statistics.UseTime != 0 { + t.Fatalf("Unexpected statistics (addTime: %s) for state:\n%s", now.Format(time.UnixDate), s.Print(true)) + } +} + func getBaseState() *XfrmState { return &XfrmState{ // Force 4 byte notation for the IPv4 addresses