Skip to content

Commit

Permalink
Using 64bit counters when talking to the SNMP daemon.
Browse files Browse the repository at this point in the history
Also:
- updating one of the tests according to Go style.
- fixing some typos.
  • Loading branch information
mum4k committed Apr 18, 2018
1 parent ae801ac commit 9d87049
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 103 deletions.
55 changes: 27 additions & 28 deletions lib/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"bufio"
"fmt"
"log/syslog"
"math"
"os"
"sort"
"strconv"
Expand Down Expand Up @@ -207,7 +206,9 @@ type snmpData struct {
// oid is the OID of this SNMP data.
oid string

// objectType is the SNMP object type, one of: integer, gauge, counter, timeticks, ipaddress, objectid, or string
// objectType is the SNMP object type, one of: integer, gauge, counter, timeticks, ipaddress, objectid, or string.
// More object types are now supported, see:
// https://github.com/haad/net-snmp/blob/master/agent/mibgroup/ucd-snmp/pass_persist.c
objectType string

// objectValue is the value stored in this OID.
Expand Down Expand Up @@ -330,52 +331,52 @@ func (s *snmp) addSnmpData(oid, objectType string, objectValue interface{}) {
func (s *snmp) addGenericData(data *parsedData) {
tcIndex, ok := s.nameToIndex[data.name]
if !ok {
// Popullate tcIndexLeaf.
// Populate tcIndexLeaf.
s.tcLastNameIndex += 1
tcIndex = s.tcLastNameIndex
s.nameToIndex[data.name] = tcIndex
// Popullate tcIndexLeaf.
// Populate tcIndexLeaf.
tcIndexOID := fmt.Sprintf("%s.%d.%d", myOID, tcIndexLeaf, tcIndex)
s.addSnmpData(tcIndexOID, "integer", tcIndex)

// Popullate tcNameLeaf.
// Populate tcNameLeaf.
tcNameOID := fmt.Sprintf("%s.%d.%d", myOID, tcNameLeaf, tcIndex)
s.addSnmpData(tcNameOID, "string", data.name)

// Popullate tcNumIndexLeaf.
// Populate tcNumIndexLeaf.
s.addSnmpData(fmt.Sprintf("%s.%d", myOID, tcNumIndexLeaf), "integer", s.tcLastNameIndex)
}

// Popullate sentBytesLeaf.
// Populate sentBytesLeaf.
tcSentBytesOID := fmt.Sprintf("%s.%d.%d", myOID, sentBytesLeaf, tcIndex)
s.addSnmpData(tcSentBytesOID, "counter", data.sentBytes)
s.addSnmpData(tcSentBytesOID, "counter64", data.sentBytes)

// Popullate sentPktLeaf.
// Populate sentPktLeaf.
tcSentPktOID := fmt.Sprintf("%s.%d.%d", myOID, sentPktLeaf, tcIndex)
s.addSnmpData(tcSentPktOID, "counter", data.sentPkt)
s.addSnmpData(tcSentPktOID, "counter64", data.sentPkt)

// Popullate droppedPktLeaf.
// Populate droppedPktLeaf.
tcDroppedPktOID := fmt.Sprintf("%s.%d.%d", myOID, droppedPktLeaf, tcIndex)
s.addSnmpData(tcDroppedPktOID, "counter", data.droppedPkt)
s.addSnmpData(tcDroppedPktOID, "counter64", data.droppedPkt)

// Popullate overLimitPktLeaf.
// Populate overLimitPktLeaf.
tcOverlimitPktOID := fmt.Sprintf("%s.%d.%d", myOID, overLimitPktLeaf, tcIndex)
s.addSnmpData(tcOverlimitPktOID, "counter", data.overLimitPkt)
s.addSnmpData(tcOverlimitPktOID, "counter64", data.overLimitPkt)
}

// addUserData stores the data from parsedData as data for a configured user name.
func (s *snmp) addUserData(data *parsedData) {
// Create new index for this user if we don't have it already.
tcUserIndex, ok := s.userToIndex[data.userClass.name]
if !ok {
// Popullate tcUserIndexLeaf.
// Populate tcUserIndexLeaf.
s.tcLastUserIndex += 1
tcUserIndex = s.tcLastUserIndex
s.userToIndex[data.userClass.name] = s.tcLastUserIndex
tcUserIndexOID := fmt.Sprintf("%s.%d.%d", myOID, tcUserIndexLeaf, tcUserIndex)
s.addSnmpData(tcUserIndexOID, "integer", tcUserIndex)

// Popullate tcUserNameLeaf.
// Populate tcUserNameLeaf.
tcUserNameOID := fmt.Sprintf("%s.%d.%d", myOID, tcUserNameLeaf, tcUserIndex)
s.addSnmpData(tcUserNameOID, "string", data.userClass.name)

Expand All @@ -396,24 +397,24 @@ func (s *snmp) addUserData(data *parsedData) {
tcUserDroppedPktOID = fmt.Sprintf("%s.%d.%d", myOID, tcUserDownDroppedPktLeaf, tcUserIndex)
tcUserOverLimitPktOID = fmt.Sprintf("%s.%d.%d", myOID, tcUserDownOverLimitPktLeaf, tcUserIndex)
}
// Popullate tcUser*BytesLeaf.
// Populate tcUser*BytesLeaf.
if tcUserBytesOID != "" {
s.addSnmpData(tcUserBytesOID, "counter", data.sentBytes)
s.addSnmpData(tcUserBytesOID, "counter64", data.sentBytes)
}

// Popullate tcUser*PktLeaf.
// Populate tcUser*PktLeaf.
if tcUserPktOID != "" {
s.addSnmpData(tcUserPktOID, "counter", data.sentPkt)
s.addSnmpData(tcUserPktOID, "counter64", data.sentPkt)
}

// Popullate tcUser*DroppedPktLeaf.
// Populate tcUser*DroppedPktLeaf.
if tcUserDroppedPktOID != "" {
s.addSnmpData(tcUserDroppedPktOID, "counter", data.droppedPkt)
s.addSnmpData(tcUserDroppedPktOID, "counter64", data.droppedPkt)
}

// Popullate tcUser*OverLimitPktLeaf.
// Populate tcUser*OverLimitPktLeaf.
if tcUserOverLimitPktOID != "" {
s.addSnmpData(tcUserOverLimitPktOID, "counter", data.overLimitPkt)
s.addSnmpData(tcUserOverLimitPktOID, "counter64", data.overLimitPkt)
}
}

Expand Down Expand Up @@ -483,13 +484,11 @@ func (s *snmp) printData(data *snmpData) {
} else {
s.snmpTalker.putLine(value)
}
case "counter":
case "counter64":
if value, ok := data.objectValue.(int64); !ok {
s.snmpTalker.putLine(emptyLine)
} else {
// Unfortunatelly SNMP daemon does not support counter64 for pass_persist scripts yet. Need to rotate this around at math.MaxInt32.
rotated := math.Mod(float64(value), float64(math.MaxInt32))
s.snmpTalker.putLine(strconv.FormatInt(int64(rotated), 10))
s.snmpTalker.putLine(strconv.FormatInt(value, 10))
}
case "integer":
if value, ok := data.objectValue.(int); !ok {
Expand Down
146 changes: 71 additions & 75 deletions lib/snmp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import (
"fmt"
"math"
"reflect"
"strconv"
"testing"

"github.com/kylelemons/godebug/pretty"
)

func TestSnmpLogIfDebug(t *testing.T) {
Expand Down Expand Up @@ -144,10 +147,10 @@ func TestSnmpAddData(t *testing.T) {
".1.3.6.1.4.1.2021.255.1.1": {".1.3.6.1.4.1.2021.255.1.1", "integer", 1},
".1.3.6.1.4.1.2021.255.2": {".1.3.6.1.4.1.2021.255.2", "integer", 1},
".1.3.6.1.4.1.2021.255.3.1": {".1.3.6.1.4.1.2021.255.3.1", "string", "eth0:2:3"},
".1.3.6.1.4.1.2021.255.4.1": {".1.3.6.1.4.1.2021.255.4.1", "counter", int64(1)},
".1.3.6.1.4.1.2021.255.5.1": {".1.3.6.1.4.1.2021.255.5.1", "counter", int64(2)},
".1.3.6.1.4.1.2021.255.6.1": {".1.3.6.1.4.1.2021.255.6.1", "counter", int64(3)},
".1.3.6.1.4.1.2021.255.7.1": {".1.3.6.1.4.1.2021.255.7.1", "counter", int64(4)},
".1.3.6.1.4.1.2021.255.4.1": {".1.3.6.1.4.1.2021.255.4.1", "counter64", int64(1)},
".1.3.6.1.4.1.2021.255.5.1": {".1.3.6.1.4.1.2021.255.5.1", "counter64", int64(2)},
".1.3.6.1.4.1.2021.255.6.1": {".1.3.6.1.4.1.2021.255.6.1", "counter64", int64(3)},
".1.3.6.1.4.1.2021.255.7.1": {".1.3.6.1.4.1.2021.255.7.1", "counter64", int64(4)},
},
[]string{
".1.3.6.1.4.1.2021.255",
Expand Down Expand Up @@ -191,14 +194,14 @@ func TestSnmpAddData(t *testing.T) {
".1.3.6.1.4.1.2021.255.8.1": {".1.3.6.1.4.1.2021.255.8.1", "integer", 1},
".1.3.6.1.4.1.2021.255.9": {".1.3.6.1.4.1.2021.255.9", "integer", 1},
".1.3.6.1.4.1.2021.255.10.1": {".1.3.6.1.4.1.2021.255.10.1", "string", "username"},
".1.3.6.1.4.1.2021.255.11.1": {".1.3.6.1.4.1.2021.255.11.1", "counter", int64(5)},
".1.3.6.1.4.1.2021.255.12.1": {".1.3.6.1.4.1.2021.255.12.1", "counter", int64(6)},
".1.3.6.1.4.1.2021.255.13.1": {".1.3.6.1.4.1.2021.255.13.1", "counter", int64(7)},
".1.3.6.1.4.1.2021.255.14.1": {".1.3.6.1.4.1.2021.255.14.1", "counter", int64(8)},
".1.3.6.1.4.1.2021.255.15.1": {".1.3.6.1.4.1.2021.255.15.1", "counter", int64(1)},
".1.3.6.1.4.1.2021.255.16.1": {".1.3.6.1.4.1.2021.255.16.1", "counter", int64(2)},
".1.3.6.1.4.1.2021.255.17.1": {".1.3.6.1.4.1.2021.255.17.1", "counter", int64(3)},
".1.3.6.1.4.1.2021.255.18.1": {".1.3.6.1.4.1.2021.255.18.1", "counter", int64(4)},
".1.3.6.1.4.1.2021.255.11.1": {".1.3.6.1.4.1.2021.255.11.1", "counter64", int64(5)},
".1.3.6.1.4.1.2021.255.12.1": {".1.3.6.1.4.1.2021.255.12.1", "counter64", int64(6)},
".1.3.6.1.4.1.2021.255.13.1": {".1.3.6.1.4.1.2021.255.13.1", "counter64", int64(7)},
".1.3.6.1.4.1.2021.255.14.1": {".1.3.6.1.4.1.2021.255.14.1", "counter64", int64(8)},
".1.3.6.1.4.1.2021.255.15.1": {".1.3.6.1.4.1.2021.255.15.1", "counter64", int64(1)},
".1.3.6.1.4.1.2021.255.16.1": {".1.3.6.1.4.1.2021.255.16.1", "counter64", int64(2)},
".1.3.6.1.4.1.2021.255.17.1": {".1.3.6.1.4.1.2021.255.17.1", "counter64", int64(3)},
".1.3.6.1.4.1.2021.255.18.1": {".1.3.6.1.4.1.2021.255.18.1", "counter64", int64(4)},
},
[]string{
".1.3.6.1.4.1.2021.255",
Expand Down Expand Up @@ -247,21 +250,21 @@ func TestSnmpAddData(t *testing.T) {
".1.3.6.1.4.1.2021.255.1.1": {".1.3.6.1.4.1.2021.255.1.1", "integer", 1},
".1.3.6.1.4.1.2021.255.2": {".1.3.6.1.4.1.2021.255.2", "integer", 1},
".1.3.6.1.4.1.2021.255.3.1": {".1.3.6.1.4.1.2021.255.3.1", "string", "eth0:1:3"},
".1.3.6.1.4.1.2021.255.4.1": {".1.3.6.1.4.1.2021.255.4.1", "counter", int64(9)},
".1.3.6.1.4.1.2021.255.5.1": {".1.3.6.1.4.1.2021.255.5.1", "counter", int64(10)},
".1.3.6.1.4.1.2021.255.6.1": {".1.3.6.1.4.1.2021.255.6.1", "counter", int64(11)},
".1.3.6.1.4.1.2021.255.7.1": {".1.3.6.1.4.1.2021.255.7.1", "counter", int64(12)},
".1.3.6.1.4.1.2021.255.4.1": {".1.3.6.1.4.1.2021.255.4.1", "counter64", int64(9)},
".1.3.6.1.4.1.2021.255.5.1": {".1.3.6.1.4.1.2021.255.5.1", "counter64", int64(10)},
".1.3.6.1.4.1.2021.255.6.1": {".1.3.6.1.4.1.2021.255.6.1", "counter64", int64(11)},
".1.3.6.1.4.1.2021.255.7.1": {".1.3.6.1.4.1.2021.255.7.1", "counter64", int64(12)},
".1.3.6.1.4.1.2021.255.8.1": {".1.3.6.1.4.1.2021.255.8.1", "integer", 1},
".1.3.6.1.4.1.2021.255.9": {".1.3.6.1.4.1.2021.255.9", "integer", 1},
".1.3.6.1.4.1.2021.255.10.1": {".1.3.6.1.4.1.2021.255.10.1", "string", "username"},
".1.3.6.1.4.1.2021.255.11.1": {".1.3.6.1.4.1.2021.255.11.1", "counter", int64(5)},
".1.3.6.1.4.1.2021.255.12.1": {".1.3.6.1.4.1.2021.255.12.1", "counter", int64(6)},
".1.3.6.1.4.1.2021.255.13.1": {".1.3.6.1.4.1.2021.255.13.1", "counter", int64(7)},
".1.3.6.1.4.1.2021.255.14.1": {".1.3.6.1.4.1.2021.255.14.1", "counter", int64(8)},
".1.3.6.1.4.1.2021.255.15.1": {".1.3.6.1.4.1.2021.255.15.1", "counter", int64(1)},
".1.3.6.1.4.1.2021.255.16.1": {".1.3.6.1.4.1.2021.255.16.1", "counter", int64(2)},
".1.3.6.1.4.1.2021.255.17.1": {".1.3.6.1.4.1.2021.255.17.1", "counter", int64(3)},
".1.3.6.1.4.1.2021.255.18.1": {".1.3.6.1.4.1.2021.255.18.1", "counter", int64(4)},
".1.3.6.1.4.1.2021.255.11.1": {".1.3.6.1.4.1.2021.255.11.1", "counter64", int64(5)},
".1.3.6.1.4.1.2021.255.12.1": {".1.3.6.1.4.1.2021.255.12.1", "counter64", int64(6)},
".1.3.6.1.4.1.2021.255.13.1": {".1.3.6.1.4.1.2021.255.13.1", "counter64", int64(7)},
".1.3.6.1.4.1.2021.255.14.1": {".1.3.6.1.4.1.2021.255.14.1", "counter64", int64(8)},
".1.3.6.1.4.1.2021.255.15.1": {".1.3.6.1.4.1.2021.255.15.1", "counter64", int64(1)},
".1.3.6.1.4.1.2021.255.16.1": {".1.3.6.1.4.1.2021.255.16.1", "counter64", int64(2)},
".1.3.6.1.4.1.2021.255.17.1": {".1.3.6.1.4.1.2021.255.17.1", "counter64", int64(3)},
".1.3.6.1.4.1.2021.255.18.1": {".1.3.6.1.4.1.2021.255.18.1", "counter64", int64(4)},
},
[]string{
".1.3.6.1.4.1.2021.255",
Expand Down Expand Up @@ -400,83 +403,76 @@ func TestSnmpListen(t *testing.T) {
s.unlock()

testData := []struct {
desc string
commands []string
expected []string
want []string
}{

// A test case with simple PING-PONG exchange.
{
[]string{"PING", ""},
[]string{"PONG"},
desc: "simple PING-PONG exchange",
commands: []string{"PING", ""},
want: []string{"PONG"},
},

// A test case with standard SNMP GET for a known OID - a string.
{
[]string{"PING", "get", ".1.3.6.1.4.1.2021.255.3.1", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.3.1", "string", "eth0:1:3"},
desc: "standard SNMP GET for a known OID - a string",
commands: []string{"PING", "get", ".1.3.6.1.4.1.2021.255.3.1", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.3.1", "string", "eth0:1:3"},
},

// A test case with standard SNMP GET for a known OID - an integer.
{
[]string{"PING", "get", ".1.3.6.1.4.1.2021.255.1.1", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.1.1", "integer", "1"},
desc: "standard SNMP GET for a known OID - an integer",
commands: []string{"PING", "get", ".1.3.6.1.4.1.2021.255.1.1", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.1.1", "integer", "1"},
},

// A test case with standard SNMP GET for a known OID - a counter.
{
[]string{"PING", "get", ".1.3.6.1.4.1.2021.255.4.1", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.4.1", "counter", "9"},
desc: "standard SNMP GET for a known OID - a counter64",
commands: []string{"PING", "get", ".1.3.6.1.4.1.2021.255.4.1", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.4.1", "counter64", "9"},
},

// A test case with standard SNMP GET for a known OID - a counter, but the internal value is at the math.MaxInt32.
{
[]string{"PING", "get", ".1.3.6.1.4.1.2021.255.6.1", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.6.1", "counter", "0"},
desc: "standard SNMP GET for a known OID - a counter64, and the value is at the math.MaxInt32",
commands: []string{"PING", "get", ".1.3.6.1.4.1.2021.255.6.1", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.6.1", "counter64", strconv.Itoa(math.MaxInt32)},
},

// A test case with standard SNMP GET for a known OID - a counter, but the internal value is larger than math.MaxInt32.
{
[]string{"PING", "get", ".1.3.6.1.4.1.2021.255.7.1", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.7.1", "counter", "1"},
desc: "standard SNMP GET for a known OID - a counter64, and the value is larger than math.MaxInt32",
commands: []string{"PING", "get", ".1.3.6.1.4.1.2021.255.7.1", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.7.1", "counter64", strconv.Itoa(math.MaxInt32 + 1)},
},

// A test case with standard SNMP GET for unknown OID.
{
[]string{"PING", "get", ".1.3.7", ""},
[]string{"PONG", ""},
desc: "standard SNMP GET for unknown OID",
commands: []string{"PING", "get", ".1.3.7", ""},
want: []string{"PONG", ""},
},

// A test case with standard SNMP GET-NEXT for two known OIDs.
{
[]string{"PING", "getnext", ".1.3.6.1.4.1.2021.255.9", "getnext", ".1.3.6.1.4.1.2021.255.10", ""},
[]string{"PONG", ".1.3.6.1.4.1.2021.255.10", "string", "tcUserNameLeaf", ".1.3.6.1.4.1.2021.255.10.1", "string", "username"},
desc: "standard SNMP GET-NEXT for two known OIDs",
commands: []string{"PING", "getnext", ".1.3.6.1.4.1.2021.255.9", "getnext", ".1.3.6.1.4.1.2021.255.10", ""},
want: []string{"PONG", ".1.3.6.1.4.1.2021.255.10", "string", "tcUserNameLeaf", ".1.3.6.1.4.1.2021.255.10.1", "string", "username"},
},

// A test case with standard SNMP GET-NEXT for the last OID.
{
[]string{"PING", "getnext", ".1.3.6.1.4.1.2021.255.18.1", ""},
[]string{"PONG", ""},
desc: "standard SNMP GET-NEXT for the last OID",
commands: []string{"PING", "getnext", ".1.3.6.1.4.1.2021.255.18.1", ""},
want: []string{"PONG", ""},
},

// A test case with standard SNMP GET-NEXT for unknown OID.
{
[]string{"PING", "getnext", ".1.3.7", ""},
[]string{"PONG", ""},
desc: "standard SNMP GET-NEXT for unknown OID",
commands: []string{"PING", "getnext", ".1.3.7", ""},
want: []string{"PONG", ""},
},

// A test case with unknown command.
{
[]string{"PING", "set", ""},
[]string{"PONG", ""},
desc: "unknown command",
commands: []string{"PING", "set", ""},
want: []string{"PONG", ""},
},
}

for i, params := range testData {
tr.erase()
tr.input = params.commands
s.Listen()
if !reflect.DeepEqual(tr.output, params.expected) {
t.Errorf("TestSnmpListen(testCase %d) \n got: '%v', \nwant: '%v'.", i, tr.output, params.expected)
}
for _, tc := range testData {
t.Run(tc.desc, func(t *testing.T) {
tr.erase()
tr.input = tc.commands
s.Listen()
if diff := pretty.Compare(tc.want, tr.output); diff != "" {
t.Errorf("Listen => unexpected output, diff (-want, +got)\n%s", diff)
}
})
}
}

0 comments on commit 9d87049

Please sign in to comment.