bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/snmp_ifaces.go (about)

     1  package collectors
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"bosun.org/cmd/scollector/conf"
     9  	"bosun.org/metadata"
    10  	"bosun.org/opentsdb"
    11  )
    12  
    13  const (
    14  	ifAlias              = ".1.3.6.1.2.1.31.1.1.1.18"
    15  	ifDescr              = ".1.3.6.1.2.1.2.2.1.2"
    16  	ifType               = ".1.3.6.1.2.1.2.2.1.3"
    17  	ifMTU                = ".1.3.6.1.2.1.2.2.1.4"
    18  	ifPhysAddress        = ".1.3.6.1.2.1.2.2.1.6"
    19  	ifHighSpeed          = ".1.3.6.1.2.1.31.1.1.1.15"
    20  	ifAdminStatus        = ".1.3.6.1.2.1.2.2.1.7"
    21  	ifOperStatus         = ".1.3.6.1.2.1.2.2.1.8"
    22  	ifHCInBroadcastPkts  = ".1.3.6.1.2.1.31.1.1.1.9"
    23  	ifHCInMulticastPkts  = ".1.3.6.1.2.1.31.1.1.1.8"
    24  	ifHCInUcastPkts      = ".1.3.6.1.2.1.31.1.1.1.7"
    25  	ifHCOutBroadcastPkts = ".1.3.6.1.2.1.31.1.1.1.13"
    26  	ifHCOutMulticastPkts = ".1.3.6.1.2.1.31.1.1.1.12"
    27  	ifHCOutOctets        = ".1.3.6.1.2.1.31.1.1.1.10"
    28  	ifHCOutUcastPkts     = ".1.3.6.1.2.1.31.1.1.1.11"
    29  	ifHCinOctets         = ".1.3.6.1.2.1.31.1.1.1.6"
    30  	ifInDiscards         = ".1.3.6.1.2.1.2.2.1.13"
    31  	ifInErrors           = ".1.3.6.1.2.1.2.2.1.14"
    32  	ifInPauseFrames      = ".1.3.6.1.2.1.10.7.10.1.3"
    33  	ifName               = ".1.3.6.1.2.1.31.1.1.1.1"
    34  	ifOutDiscards        = ".1.3.6.1.2.1.2.2.1.19"
    35  	ifOutErrors          = ".1.3.6.1.2.1.2.2.1.20"
    36  	ifOutPauseFrames     = ".1.3.6.1.2.1.10.7.10.1.4"
    37  )
    38  
    39  // SNMPIfaces registers a SNMP Interfaces collector for the given community and host.
    40  func SNMPIfaces(cfg conf.SNMP) {
    41  	collectors = append(collectors, &IntervalCollector{
    42  		F: func() (opentsdb.MultiDataPoint, error) {
    43  			return c_snmp_ifaces(cfg.Community, cfg.Host)
    44  		},
    45  		Interval: time.Second * 30,
    46  		name:     fmt.Sprintf("snmp-ifaces-%s", cfg.Host),
    47  	})
    48  }
    49  
    50  const osNet = "os.net"
    51  
    52  func switchInterfaceMetric(metric string, iname string, ifType int64) string {
    53  	switch ifType {
    54  	case 6:
    55  		return metric
    56  	case 53, 161:
    57  		return osNet + ".bond" + strings.TrimPrefix(metric, osNet)
    58  	case 135:
    59  		return osNet + ".virtual" + strings.TrimPrefix(metric, osNet)
    60  	case 131:
    61  		return osNet + ".tunnel" + strings.TrimPrefix(metric, osNet)
    62  	default:
    63  		//Cisco ASAs don't mark port channels correctly
    64  		if strings.Contains(iname, "port-channel") {
    65  			return osNet + ".bond" + strings.TrimPrefix(metric, osNet)
    66  		}
    67  		return osNet + ".other" + strings.TrimPrefix(metric, osNet)
    68  	}
    69  }
    70  
    71  func c_snmp_ifaces(community, host string) (opentsdb.MultiDataPoint, error) {
    72  	ifNamesRaw, err := snmp_subtree(host, community, ifName)
    73  	if err != nil || len(ifNamesRaw) == 0 {
    74  		ifNamesRaw, err = snmp_subtree(host, community, ifDescr)
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  	}
    79  	ifAliasesRaw, err := snmp_subtree(host, community, ifAlias)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	ifTypesRaw, err := snmp_subtree(host, community, ifType)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	ifPhysAddressRaw, err := snmp_subtree(host, community, ifPhysAddress)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	ifNames := make(map[interface{}]string, len(ifNamesRaw))
    92  	ifAliases := make(map[interface{}]string, len(ifAliasesRaw))
    93  	ifTypes := make(map[interface{}]int64, len(ifTypesRaw))
    94  	ifPhysAddresses := make(map[interface{}]string, len(ifPhysAddressRaw))
    95  	for k, v := range ifNamesRaw {
    96  		ifNames[k] = fmt.Sprintf("%s", v)
    97  	}
    98  	for k, v := range ifTypesRaw {
    99  		val, ok := v.(int64)
   100  		if !ok {
   101  			return nil, fmt.Errorf("unexpected type from from MIB::ifType")
   102  		}
   103  		ifTypes[k] = val
   104  	}
   105  	for k, v := range ifAliasesRaw {
   106  		// In case clean would come up empty, prevent the point from being removed
   107  		// by setting our own empty case.
   108  		ifAliases[k], _ = opentsdb.Clean(fmt.Sprintf("%s", v))
   109  		if ifAliases[k] == "" {
   110  			ifAliases[k] = "NA"
   111  		}
   112  	}
   113  	for k, v := range ifPhysAddressRaw {
   114  		ifPhysAddresses[k] = fmt.Sprintf("%X", v)
   115  	}
   116  	var md opentsdb.MultiDataPoint
   117  	add := func(sA snmpAdd) error {
   118  		m, err := snmp_subtree(host, community, sA.oid)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		var sum int64
   123  		for k, v := range m {
   124  			tags := opentsdb.TagSet{
   125  				"host":  host,
   126  				"iface": fmt.Sprintf("%s", k),
   127  				"iname": ifNames[k],
   128  			}
   129  			if sA.dir != "" {
   130  				tags["direction"] = sA.dir
   131  			}
   132  			if iVal, ok := v.(int64); ok && ifTypes[k] == 6 {
   133  				sum += iVal
   134  			}
   135  			Add(&md, switchInterfaceMetric(sA.metric, ifNames[k], ifTypes[k]), v, tags, sA.rate, sA.unit, sA.desc)
   136  			metadata.AddMeta("", tags, "alias", ifAliases[k], false)
   137  			metadata.AddMeta("", tags, "mac", ifPhysAddresses[k], false)
   138  		}
   139  		if sA.metric == osNetBytes {
   140  			tags := opentsdb.TagSet{"host": host, "direction": sA.dir}
   141  			Add(&md, osNetBytes+".total", sum, tags, metadata.Counter, metadata.Bytes, "The total number of bytes transfered through the network device.")
   142  		}
   143  		return nil
   144  	}
   145  	oids := []snmpAdd{
   146  		{ifHCInBroadcastPkts, osNetBroadcast, "in", metadata.Counter, metadata.Packet, osNetBroadcastDesc},
   147  		{ifHCInMulticastPkts, osNetMulticast, "in", metadata.Counter, metadata.Packet, osNetMulticastDesc},
   148  		{ifHCInUcastPkts, osNetUnicast, "in", metadata.Counter, metadata.Packet, osNetUnicastDesc},
   149  		{ifHCOutBroadcastPkts, osNetBroadcast, "out", metadata.Counter, metadata.Packet, osNetBroadcastDesc},
   150  		{ifHCOutMulticastPkts, osNetMulticast, "out", metadata.Counter, metadata.Packet, osNetMulticastDesc},
   151  		{ifHCOutOctets, osNetBytes, "out", metadata.Counter, metadata.Bytes, osNetBytesDesc},
   152  		{ifHCOutUcastPkts, osNetUnicast, "out", metadata.Counter, metadata.Packet, osNetUnicastDesc},
   153  		{ifHCinOctets, osNetBytes, "in", metadata.Counter, metadata.Bytes, osNetBytesDesc},
   154  		{ifInDiscards, osNetDropped, "in", metadata.Counter, metadata.Packet, osNetDroppedDesc},
   155  		{ifInErrors, osNetErrors, "in", metadata.Counter, metadata.Error, osNetErrorsDesc},
   156  		{ifOutDiscards, osNetDropped, "out", metadata.Counter, metadata.Packet, osNetDroppedDesc},
   157  		{ifOutErrors, osNetErrors, "out", metadata.Counter, metadata.Error, osNetErrorsDesc},
   158  		{ifInPauseFrames, osNetPauseFrames, "in", metadata.Counter, metadata.Frame, osNetPauseFrameDesc},
   159  		{ifOutPauseFrames, osNetPauseFrames, "out", metadata.Counter, metadata.Frame, osNetPauseFrameDesc},
   160  		{ifMTU, osNetMTU, "", metadata.Gauge, metadata.Bytes, osNetMTUDesc},
   161  		{ifHighSpeed, osNetIfSpeed, "", metadata.Gauge, metadata.Megabit, osNetIfSpeedDesc},
   162  		{ifAdminStatus, osNetAdminStatus, "", metadata.Gauge, metadata.StatusCode, osNetAdminStatusDesc},
   163  		{ifOperStatus, osNetOperStatus, "", metadata.Gauge, metadata.StatusCode, osNetOperStatusDesc},
   164  	}
   165  	for _, sA := range oids {
   166  		if err := add(sA); err != nil {
   167  			return nil, err
   168  		}
   169  	}
   170  	return md, nil
   171  }
   172  
   173  type snmpAdd struct {
   174  	oid    string
   175  	metric string
   176  	dir    string
   177  	rate   metadata.RateType
   178  	unit   metadata.Unit
   179  	desc   string
   180  }