Skip to content

Commit

Permalink
Merge pull request #753 from kongfei605/snmp_up
Browse files Browse the repository at this point in the history
load mibs with gosmi
  • Loading branch information
kongfei605 authored Dec 31, 2023
2 parents f5bfd18 + 732e0cc commit ce0ec30
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 221 deletions.
1 change: 1 addition & 0 deletions conf/input.snmp/snmp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ agents = [
## Used by the gosmi translator.
## To add paths when translating with netsnmp, use the MIBDIRS environment variable
# path = ["/usr/share/snmp/mibs"]
# translator = "gosmi"

## SNMP community string.
# community = "public"
Expand Down
141 changes: 141 additions & 0 deletions inputs/snmp/gosmi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package snmp

import (
"fmt"
"sync"

"flashcat.cloud/categraf/pkg/snmp"
"github.com/sleepinggenius2/gosmi"
"github.com/sleepinggenius2/gosmi/models"
)

type gosmiTranslator struct {
}

func NewGosmiTranslator(paths []string) (*gosmiTranslator, error) {
err := snmp.LoadMibsFromPath(paths, &snmp.GosmiMibLoader{})
if err == nil {
return &gosmiTranslator{}, nil
}
return nil, err
}

type gosmiSnmpTranslateCache struct {
mibName string
oidNum string
oidText string
conversion string
node gosmi.SmiNode
err error
}

var gosmiSnmpTranslateCachesLock sync.Mutex
var gosmiSnmpTranslateCaches map[string]gosmiSnmpTranslateCache

//nolint:revive //function-result-limit conditionally 5 return results allowed
func (g *gosmiTranslator) SnmpTranslate(oid string) (mibName string, oidNum string, oidText string, conversion string, err error) {
mibName, oidNum, oidText, conversion, _, err = g.SnmpTranslateFull(oid)
return mibName, oidNum, oidText, conversion, err
}

//nolint:revive //function-result-limit conditionally 6 return results allowed
func (g *gosmiTranslator) SnmpTranslateFull(oid string) (
mibName string, oidNum string, oidText string,
conversion string,
node gosmi.SmiNode,
err error) {
gosmiSnmpTranslateCachesLock.Lock()
if gosmiSnmpTranslateCaches == nil {
gosmiSnmpTranslateCaches = map[string]gosmiSnmpTranslateCache{}
}

var stc gosmiSnmpTranslateCache
var ok bool
if stc, ok = gosmiSnmpTranslateCaches[oid]; !ok {
// This will result in only one call to snmptranslate running at a time.
// We could speed it up by putting a lock in snmpTranslateCache and then
// returning it immediately, and multiple callers would then release the
// snmpTranslateCachesLock and instead wait on the individual
// snmpTranslation.Lock to release. But I don't know that the extra complexity
// is worth it. Especially when it would slam the system pretty hard if lots
// of lookups are being performed.

stc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.node, stc.err = snmp.SnmpTranslateCall(oid)
gosmiSnmpTranslateCaches[oid] = stc
}

gosmiSnmpTranslateCachesLock.Unlock()

return stc.mibName, stc.oidNum, stc.oidText, stc.conversion, stc.node, stc.err
}

type gosmiSnmpTableCache struct {
mibName string
oidNum string
oidText string
fields []Field
err error
}

var gosmiSnmpTableCaches map[string]gosmiSnmpTableCache
var gosmiSnmpTableCachesLock sync.Mutex

// snmpTable resolves the given OID as a table, providing information about the
// table and fields within.
//
//nolint:revive //Too many return variable but necessary
func (g *gosmiTranslator) SnmpTable(oid string) (
mibName string, oidNum string, oidText string,
fields []Field,
err error) {
gosmiSnmpTableCachesLock.Lock()
if gosmiSnmpTableCaches == nil {
gosmiSnmpTableCaches = map[string]gosmiSnmpTableCache{}
}

var stc gosmiSnmpTableCache
var ok bool
if stc, ok = gosmiSnmpTableCaches[oid]; !ok {
stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err = g.SnmpTableCall(oid)
gosmiSnmpTableCaches[oid] = stc
}

gosmiSnmpTableCachesLock.Unlock()
return stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err
}

//nolint:revive //Too many return variable but necessary
func (g *gosmiTranslator) SnmpTableCall(oid string) (mibName string, oidNum string, oidText string, fields []Field, err error) {
mibName, oidNum, oidText, _, node, err := g.SnmpTranslateFull(oid)
if err != nil {
return "", "", "", nil, fmt.Errorf("translating: %w", err)
}

mibPrefix := mibName + "::"

col, tagOids := snmp.GetIndex(mibPrefix, node)
for _, c := range col {
_, isTag := tagOids[mibPrefix+c]
fields = append(fields, Field{Name: c, Oid: mibPrefix + c, IsTag: isTag})
}

return mibName, oidNum, oidText, fields, nil
}

func (g *gosmiTranslator) SnmpFormatEnum(oid string, value interface{}, full bool) (string, error) {
//nolint:dogsled // only need to get the node
_, _, _, _, node, err := g.SnmpTranslateFull(oid)

if err != nil {
return "", err
}

var v models.Value
if full {
v = node.FormatValue(value, models.FormatEnumName, models.FormatEnumValue)
} else {
v = node.FormatValue(value, models.FormatEnumName)
}

return v.Formatted, nil
}
8 changes: 8 additions & 0 deletions inputs/snmp/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type Instance struct {

connectionCache []snmpConnection

Translator string `toml:"translator"`

translator Translator

Mappings map[string]map[string]string `toml:"mappings"`
Expand All @@ -48,7 +50,13 @@ func (ins *Instance) Init() error {
return types.ErrInstancesEmpty
}

var err error
switch ins.Translator {
case "gosmi":
ins.translator, err = NewGosmiTranslator(ins.Path)
if err != nil {
return err
}
case "", "netsnmp":
ins.translator = NewNetsnmpTranslator()
default:
Expand Down
10 changes: 7 additions & 3 deletions inputs/snmp/netsnmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package snmp
import (
"bufio"
"bytes"
"errors"
"fmt"
"log" //nolint:revive
"log"
"os/exec"
"strings"
"sync"
Expand Down Expand Up @@ -58,7 +59,6 @@ var snmpTableCachesLock sync.Mutex

// snmpTable resolves the given OID as a table, providing information about the
// table and fields within.
//nolint:revive
func (n *netsnmpTranslator) SnmpTable(oid string) (
mibName string, oidNum string, oidText string,
fields []Field,
Expand All @@ -79,7 +79,6 @@ func (n *netsnmpTranslator) SnmpTable(oid string) (
return stc.mibName, stc.oidNum, stc.oidText, stc.fields, stc.err
}

//nolint:revive
func (n *netsnmpTranslator) snmpTableCall(oid string) (
mibName string, oidNum string, oidText string,
fields []Field,
Expand Down Expand Up @@ -154,6 +153,7 @@ var snmpTranslateCachesLock sync.Mutex
var snmpTranslateCaches map[string]snmpTranslateCache

// snmpTranslate resolves the given OID.
//
//nolint:revive
func (n *netsnmpTranslator) SnmpTranslate(oid string) (
mibName string, oidNum string, oidText string,
Expand Down Expand Up @@ -254,3 +254,7 @@ func snmpTranslateCall(oid string) (mibName string, oidNum string, oidText strin

return mibName, oidNum, oidText, conversion, nil
}

func (n *netsnmpTranslator) SnmpFormatEnum(_ string, _ interface{}, _ bool) (string, error) {
return "", errors.New("not implemented in netsnmp translator")
}
5 changes: 5 additions & 0 deletions inputs/snmp/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ type Translator interface {
fields []Field,
err error,
)

SnmpFormatEnum(oid string, value interface{}, full bool) (
formatted string,
err error,
)
}

type ClientConfig struct {
Expand Down
39 changes: 0 additions & 39 deletions pkg/snmp/config.go

This file was deleted.

Loading

0 comments on commit ce0ec30

Please sign in to comment.