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

     1  package collectors
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  	"time"
     8  
     9  	"bosun.org/cmd/scollector/conf"
    10  	"bosun.org/metadata"
    11  	"bosun.org/opentsdb"
    12  	"bosun.org/snmp"
    13  )
    14  
    15  func SNMPCiscoBGP(cfg conf.SNMP) {
    16  	collectors = append(collectors, &IntervalCollector{
    17  		F: func() (opentsdb.MultiDataPoint, error) {
    18  			return c_snmp_ciscobgp(cfg.Community, cfg.Host)
    19  		},
    20  		Interval: time.Second * 30,
    21  		name:     fmt.Sprintf("snmp-ciscobgp-%s", cfg.Host),
    22  	})
    23  }
    24  
    25  func c_snmp_ciscobgp(community, host string) (opentsdb.MultiDataPoint, error) {
    26  	const (
    27  		state               = ".1.3.6.1.4.1.9.9.187.1.2.5.1.3.1.4"
    28  		adminStatus         = ".1.3.6.1.4.1.9.9.187.1.2.5.1.4.1.4"
    29  		localAS             = ".1.3.6.1.4.1.9.9.187.1.2.5.1.8.1.4"
    30  		localIdentifier     = ".1.3.6.1.4.1.9.9.187.1.2.5.1.9.1.4"
    31  		remoteAS            = ".1.3.6.1.4.1.9.9.187.1.2.5.1.11.1.4"
    32  		remoteIdentifier    = ".1.3.6.1.4.1.9.9.187.1.2.5.1.12.1.4"
    33  		inUpdates           = ".1.3.6.1.4.1.9.9.187.1.2.5.1.13.1.4"
    34  		outUpdates          = ".1.3.6.1.4.1.9.9.187.1.2.5.1.14.1.4"
    35  		inTotalMessages     = ".1.3.6.1.4.1.9.9.187.1.2.5.1.15.1.4"
    36  		outTotalMessages    = ".1.3.6.1.4.1.9.9.187.1.2.5.1.16.1.4"
    37  		inUpdateElapsedTime = ".1.3.6.1.4.1.9.9.187.1.2.5.1.27.1.4"
    38  		acceptedPrefixes    = ".1.3.6.1.4.1.9.9.187.1.2.8.1.1.1.4"
    39  		deniedPrefixes      = ".1.3.6.1.4.1.9.9.187.1.2.8.1.2.1.4"
    40  		advertisedPrefixes  = ".1.3.6.1.4.1.9.9.187.1.2.8.1.6.1.4"
    41  		suppressedPrefixes  = ".1.3.6.1.4.1.9.9.187.1.2.8.1.7.1.4"
    42  		withdrawnPrefixes   = ".1.3.6.1.4.1.9.9.187.1.2.8.1.8.1.4"
    43  
    44  		bgpPeerState               = "bgp.peer.state"
    45  		bgpPeerAdminStatus         = "bgp.peer.admin_status"
    46  		bgpPeerInUpdates           = "bgp.peer.updates.in"
    47  		bgpPeerOutUpdates          = "bgp.peer.updates.out"
    48  		bgpPeerInTotalMessages     = "bgp.peer.messages.in"
    49  		bgpPeerOutTotalMessages    = "bgp.peer.messages.out"
    50  		bgpPeerInUpdateElapsedTime = "bgp.peer.update_elapsed.in"
    51  		bgpPeerAcceptedPrefixes    = "bgp.peer.prefixes.accepted"
    52  		bgpPeerDeniedPrefixes      = "bgp.peer.prefixes.denied"
    53  		bgpPeerAdvertisedPrefixes  = "bgp.peer.prefixes.advertised"
    54  		bgpPeerSuppressedPrefixes  = "bgp.peer.prefixes.suppressed"
    55  		bgpPeerWithdrawnPrefixes   = "bgp.peer.prefixes.withdrawn"
    56  
    57  		bgpPeerStateDesc               = "The state of the peer. 1:idle 2:connect 3:active 4:opensent 5:openconfirm 6:established"
    58  		bgpPeerAdminStatusDesc         = "The admin status of the peer connection 1:stop 2:start"
    59  		bgpPeerInUpdatesDesc           = "The number of updates received from the peer in the current session"
    60  		bgpPeerOutUpdatesDesc          = "The number of updates sent to the peer in the current session"
    61  		bgpPeerInTotalMessagesDesc     = "The number of total messages received from the peer in the current session"
    62  		bgpPeerOutTotalMessagesDesc    = "The number of total messages sent to the peer in the current session"
    63  		bgpPeerInUpdateElapsedTimeDesc = "The amount of time since the last update from the peer"
    64  		bgpPeerAcceptedPrefixesDesc    = "The number of prefixes accepted from the peer"
    65  		bgpPeerDeniedPrefixesDesc      = "The number of prefixes from the peer that were denied this session"
    66  		bgpPeerAdvertisedPrefixesDesc  = "The number of prefixes that have been advertised to the peer this session"
    67  		bgpPeerSuppressedPrefixesDesc  = "The number of prefixes that have been suppressed from sending to the peer this session"
    68  		bgpPeerWithdrawnPrefixesDesc   = "The number of prefixes that the local node has withdrawn from the peer this session"
    69  	)
    70  	// Tag: local_as
    71  	localASesRaw, err := snmp_ip_tree(host, community, localAS)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	localASes := make(map[string]string, len(localASesRaw))
    76  	for k, v := range localASesRaw {
    77  		s := fmt.Sprint(v)
    78  		localASes[k] = s
    79  	}
    80  
    81  	// Tag: local_id
    82  	localIdentifiersRaw, err := snmp_ip_tree(host, community, localIdentifier)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	localIdentifiers := make(map[string]string, len(localIdentifiersRaw))
    87  	for k, v := range localIdentifiersRaw {
    88  		if uv, ok := v.([]uint8); ok {
    89  			localIdentifiers[k] = snmp_combine_ip_uint8(uv)
    90  		} else {
    91  			return nil, fmt.Errorf("Bad IP address data in local identifier for peer %q on host %q", k, host)
    92  		}
    93  	}
    94  
    95  	// Tag: remote_as
    96  	remoteASesRaw, err := snmp_ip_tree(host, community, remoteAS)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	remoteASes := make(map[string]string, len(remoteASesRaw))
   101  	for k, v := range remoteASesRaw {
   102  		s := fmt.Sprint(v)
   103  		remoteASes[k] = s
   104  	}
   105  
   106  	// Tag: remote_id
   107  	remoteIdentifiersRaw, err := snmp_ip_tree(host, community, remoteIdentifier)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	remoteIdentifiers := make(map[string]string, len(remoteIdentifiersRaw))
   112  	for k, v := range remoteIdentifiersRaw {
   113  		if uv, ok := v.([]uint8); ok {
   114  			remoteIdentifiers[k] = snmp_combine_ip_uint8(uv)
   115  		} else {
   116  			return nil, fmt.Errorf("Bad IP address data in remote identifier for peer %q on host %q", k, host)
   117  		}
   118  	}
   119  
   120  	var md opentsdb.MultiDataPoint
   121  
   122  	type bgpAdd struct {
   123  		oid    string
   124  		metric string
   125  		rate   metadata.RateType
   126  		unit   metadata.Unit
   127  		desc   string
   128  	}
   129  
   130  	// Function to harvest all metrics with the tag groups above
   131  	add := func(bA bgpAdd) error {
   132  		m, err := snmp_ip_tree(host, community, bA.oid)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		for k, v := range m {
   137  			_, localASok := localASes[k]
   138  			_, localIdentifierok := localIdentifiers[k]
   139  			_, remoteASok := remoteASes[k]
   140  			_, remoteIdentifierok := remoteIdentifiers[k]
   141  			if localASok && localIdentifierok && remoteASok && remoteIdentifierok {
   142  				tags := opentsdb.TagSet{
   143  					"host":      host,
   144  					"peer":      k,
   145  					"local_as":  localASes[k],
   146  					"local_id":  localIdentifiers[k],
   147  					"remote_as": remoteASes[k],
   148  					"remote_id": remoteIdentifiers[k],
   149  				}
   150  				Add(&md, bA.metric, v, tags, bA.rate, bA.unit, bA.desc)
   151  			} else {
   152  				return fmt.Errorf("Missing tag data for peer %q on host %q", k, host)
   153  			}
   154  		}
   155  		return nil
   156  	}
   157  	// oid, metric, rate, unit, description
   158  	oids := []bgpAdd{
   159  		{state, bgpPeerState, metadata.Gauge, metadata.StatusCode, bgpPeerStateDesc},
   160  		{adminStatus, bgpPeerAdminStatus, metadata.Gauge, metadata.StatusCode, bgpPeerAdminStatusDesc},
   161  		{inUpdates, bgpPeerInUpdates, metadata.Counter, metadata.Packet, bgpPeerInUpdatesDesc},
   162  		{outUpdates, bgpPeerOutUpdates, metadata.Counter, metadata.Packet, bgpPeerOutUpdatesDesc},
   163  		{inTotalMessages, bgpPeerInTotalMessages, metadata.Counter, metadata.Packet, bgpPeerInTotalMessagesDesc},
   164  		{outTotalMessages, bgpPeerOutTotalMessages, metadata.Counter, metadata.Packet, bgpPeerOutTotalMessagesDesc},
   165  		{inUpdateElapsedTime, bgpPeerInUpdateElapsedTime, metadata.Gauge, metadata.Second, bgpPeerInUpdateElapsedTimeDesc},
   166  		{acceptedPrefixes, bgpPeerAcceptedPrefixes, metadata.Gauge, metadata.Count, bgpPeerAcceptedPrefixesDesc},
   167  		{deniedPrefixes, bgpPeerDeniedPrefixes, metadata.Counter, metadata.Count, bgpPeerDeniedPrefixesDesc},
   168  		{advertisedPrefixes, bgpPeerAdvertisedPrefixes, metadata.Counter, metadata.Count, bgpPeerAdvertisedPrefixesDesc},
   169  		{suppressedPrefixes, bgpPeerSuppressedPrefixes, metadata.Counter, metadata.Count, bgpPeerSuppressedPrefixesDesc},
   170  		{withdrawnPrefixes, bgpPeerWithdrawnPrefixes, metadata.Counter, metadata.Count, bgpPeerWithdrawnPrefixesDesc},
   171  	}
   172  	for _, bA := range oids {
   173  		if err := add(bA); err != nil {
   174  			return nil, err
   175  		}
   176  	}
   177  	return md, nil
   178  }
   179  
   180  func snmp_ip_tree(host, community, oid string) (map[string]interface{}, error) {
   181  	rows, err := snmp.Walk(host, community, oid)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	m := make(map[string]interface{})
   186  	for rows.Next() {
   187  		key := ""
   188  		var a interface{}
   189  		id, err := rows.Scan(&a)
   190  		if err != nil {
   191  			return nil, err
   192  		}
   193  		switch t := id.(type) {
   194  		case []int:
   195  			key = snmp_combine_ip_int(t)
   196  		default:
   197  			return nil, fmt.Errorf("Got wrong type from OID check")
   198  		}
   199  		m[key] = a
   200  	}
   201  	if err := rows.Err(); err != nil && err != io.EOF {
   202  		return nil, err
   203  	}
   204  	return m, nil
   205  }
   206  
   207  func snmp_combine_ip_uint8(path []uint8) string {
   208  	s := make([]string, len(path))
   209  	for i := range path {
   210  		s[i] = fmt.Sprint(path[i])
   211  	}
   212  	// In some cases there's a .1.1 after the IP (because SNMP is awesome), drop it:
   213  	s = s[:4]
   214  	return strings.Join(s, ".")
   215  }
   216  
   217  func snmp_combine_ip_int(path []int) string {
   218  	s := make([]string, len(path))
   219  	for i := range path {
   220  		s[i] = fmt.Sprint(path[i])
   221  	}
   222  	// In some cases there's a .1.1 after the IP (because SNMP is awesome), drop it:
   223  	s = s[:4]
   224  	return strings.Join(s, ".")
   225  }