-
Notifications
You must be signed in to change notification settings - Fork 491
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1408 from shanemadden/ciscobgp
Add ciscobgp snmp collector
- Loading branch information
Showing
2 changed files
with
226 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
package collectors | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"strings" | ||
"time" | ||
|
||
"bosun.org/_third_party/github.com/mjibson/snmp" | ||
"bosun.org/cmd/scollector/conf" | ||
"bosun.org/metadata" | ||
"bosun.org/opentsdb" | ||
) | ||
|
||
func SNMPCiscoBGP(cfg conf.SNMP) { | ||
collectors = append(collectors, &IntervalCollector{ | ||
F: func() (opentsdb.MultiDataPoint, error) { | ||
return c_snmp_ciscobgp(cfg.Community, cfg.Host) | ||
}, | ||
Interval: time.Second * 30, | ||
name: fmt.Sprintf("snmp-ciscobgp-%s", cfg.Host), | ||
}) | ||
} | ||
|
||
func c_snmp_ciscobgp(community, host string) (opentsdb.MultiDataPoint, error) { | ||
const ( | ||
state = ".1.3.6.1.4.1.9.9.187.1.2.5.1.3.1.4" | ||
adminStatus = ".1.3.6.1.4.1.9.9.187.1.2.5.1.4.1.4" | ||
localAS = ".1.3.6.1.4.1.9.9.187.1.2.5.1.8.1.4" | ||
localIdentifier = ".1.3.6.1.4.1.9.9.187.1.2.5.1.9.1.4" | ||
remoteAS = ".1.3.6.1.4.1.9.9.187.1.2.5.1.11.1.4" | ||
remoteIdentifier = ".1.3.6.1.4.1.9.9.187.1.2.5.1.12.1.4" | ||
inUpdates = ".1.3.6.1.4.1.9.9.187.1.2.5.1.13.1.4" | ||
outUpdates = ".1.3.6.1.4.1.9.9.187.1.2.5.1.14.1.4" | ||
inTotalMessages = ".1.3.6.1.4.1.9.9.187.1.2.5.1.15.1.4" | ||
outTotalMessages = ".1.3.6.1.4.1.9.9.187.1.2.5.1.16.1.4" | ||
inUpdateElapsedTime = ".1.3.6.1.4.1.9.9.187.1.2.5.1.27.1.4" | ||
acceptedPrefixes = ".1.3.6.1.4.1.9.9.187.1.2.8.1.1.1.4" | ||
deniedPrefixes = ".1.3.6.1.4.1.9.9.187.1.2.8.1.2.1.4" | ||
advertisedPrefixes = ".1.3.6.1.4.1.9.9.187.1.2.8.1.6.1.4" | ||
suppressedPrefixes = ".1.3.6.1.4.1.9.9.187.1.2.8.1.7.1.4" | ||
withdrawnPrefixes = ".1.3.6.1.4.1.9.9.187.1.2.8.1.8.1.4" | ||
|
||
bgpPeerState = "bgp.peer.state" | ||
bgpPeerAdminStatus = "bgp.peer.admin_status" | ||
bgpPeerInUpdates = "bgp.peer.updates.in" | ||
bgpPeerOutUpdates = "bgp.peer.updates.out" | ||
bgpPeerInTotalMessages = "bgp.peer.messages.in" | ||
bgpPeerOutTotalMessages = "bgp.peer.messages.out" | ||
bgpPeerInUpdateElapsedTime = "bgp.peer.update_elapsed.in" | ||
bgpPeerAcceptedPrefixes = "bgp.peer.prefixes.accepted" | ||
bgpPeerDeniedPrefixes = "bgp.peer.prefixes.denied" | ||
bgpPeerAdvertisedPrefixes = "bgp.peer.prefixes.advertised" | ||
bgpPeerSuppressedPrefixes = "bgp.peer.prefixes.suppressed" | ||
bgpPeerWithdrawnPrefixes = "bgp.peer.prefixes.withdrawn" | ||
|
||
bgpPeerStateDesc = "The state of the peer. 1:idle 2:connect 3:active 4:opensent 5:openconfirm 6:established" | ||
bgpPeerAdminStatusDesc = "The admin status of the peer connection 1:stop 2:start" | ||
bgpPeerInUpdatesDesc = "The number of updates received from the peer in the current session" | ||
bgpPeerOutUpdatesDesc = "The number of updates sent to the peer in the current session" | ||
bgpPeerInTotalMessagesDesc = "The number of total messages received from the peer in the current session" | ||
bgpPeerOutTotalMessagesDesc = "The number of total messages sent to the peer in the current session" | ||
bgpPeerInUpdateElapsedTimeDesc = "The amount of time since the last update from the peer" | ||
bgpPeerAcceptedPrefixesDesc = "The number of prefixes accepted from the peer" | ||
bgpPeerDeniedPrefixesDesc = "The number of prefixes from the peer that were denied this session" | ||
bgpPeerAdvertisedPrefixesDesc = "The number of prefixes that have been advertised to the peer this session" | ||
bgpPeerSuppressedPrefixesDesc = "The number of prefixes that have been suppressed from sending to the peer this session" | ||
bgpPeerWithdrawnPrefixesDesc = "The number of prefixes that the local node has withdrawn from the peer this session" | ||
) | ||
// Tag: local_as | ||
localASesRaw, err := snmp_ip_tree(host, community, localAS) | ||
if err != nil { | ||
return nil, err | ||
} | ||
localASes := make(map[string]string, len(localASesRaw)) | ||
for k, v := range localASesRaw { | ||
s := fmt.Sprint(v) | ||
localASes[k] = s | ||
} | ||
|
||
// Tag: local_id | ||
localIdentifiersRaw, err := snmp_ip_tree(host, community, localIdentifier) | ||
if err != nil { | ||
return nil, err | ||
} | ||
localIdentifiers := make(map[string]string, len(localIdentifiersRaw)) | ||
for k, v := range localIdentifiersRaw { | ||
if uv, ok := v.([]uint8); ok { | ||
localIdentifiers[k] = snmp_combine_ip_uint8(uv) | ||
} else { | ||
return nil, fmt.Errorf("Bad IP address data in local identifier for peer %q on host %q", k, host) | ||
} | ||
} | ||
|
||
// Tag: remote_as | ||
remoteASesRaw, err := snmp_ip_tree(host, community, remoteAS) | ||
if err != nil { | ||
return nil, err | ||
} | ||
remoteASes := make(map[string]string, len(remoteASesRaw)) | ||
for k, v := range remoteASesRaw { | ||
s := fmt.Sprint(v) | ||
remoteASes[k] = s | ||
} | ||
|
||
// Tag: remote_id | ||
remoteIdentifiersRaw, err := snmp_ip_tree(host, community, remoteIdentifier) | ||
if err != nil { | ||
return nil, err | ||
} | ||
remoteIdentifiers := make(map[string]string, len(remoteIdentifiersRaw)) | ||
for k, v := range remoteIdentifiersRaw { | ||
if uv, ok := v.([]uint8); ok { | ||
remoteIdentifiers[k] = snmp_combine_ip_uint8(uv) | ||
} else { | ||
return nil, fmt.Errorf("Bad IP address data in remote identifier for peer %q on host %q", k, host) | ||
} | ||
} | ||
|
||
var md opentsdb.MultiDataPoint | ||
|
||
type bgpAdd struct { | ||
oid string | ||
metric string | ||
rate metadata.RateType | ||
unit metadata.Unit | ||
desc string | ||
} | ||
|
||
// Function to harvest all metrics with the tag groups above | ||
add := func(bA bgpAdd) error { | ||
m, err := snmp_ip_tree(host, community, bA.oid) | ||
if err != nil { | ||
return err | ||
} | ||
for k, v := range m { | ||
_, localASok := localASes[k] | ||
_, localIdentifierok := localIdentifiers[k] | ||
_, remoteASok := remoteASes[k] | ||
_, remoteIdentifierok := remoteIdentifiers[k] | ||
if localASok && localIdentifierok && remoteASok && remoteIdentifierok { | ||
tags := opentsdb.TagSet{ | ||
"host": host, | ||
"peer": k, | ||
"local_as": localASes[k], | ||
"local_id": localIdentifiers[k], | ||
"remote_as": remoteASes[k], | ||
"remote_id": remoteIdentifiers[k], | ||
} | ||
Add(&md, bA.metric, v, tags, bA.rate, bA.unit, bA.desc) | ||
} else { | ||
return fmt.Errorf("Missing tag data for peer %q on host %q", k, host) | ||
} | ||
} | ||
return nil | ||
} | ||
// oid, metric, rate, unit, description | ||
oids := []bgpAdd{ | ||
{state, bgpPeerState, metadata.Gauge, metadata.StatusCode, bgpPeerStateDesc}, | ||
{adminStatus, bgpPeerAdminStatus, metadata.Gauge, metadata.StatusCode, bgpPeerAdminStatusDesc}, | ||
{inUpdates, bgpPeerInUpdates, metadata.Counter, metadata.Packet, bgpPeerInUpdatesDesc}, | ||
{outUpdates, bgpPeerOutUpdates, metadata.Counter, metadata.Packet, bgpPeerOutUpdatesDesc}, | ||
{inTotalMessages, bgpPeerInTotalMessages, metadata.Counter, metadata.Packet, bgpPeerInTotalMessagesDesc}, | ||
{outTotalMessages, bgpPeerOutTotalMessages, metadata.Counter, metadata.Packet, bgpPeerOutTotalMessagesDesc}, | ||
{inUpdateElapsedTime, bgpPeerInUpdateElapsedTime, metadata.Gauge, metadata.Second, bgpPeerInUpdateElapsedTimeDesc}, | ||
{acceptedPrefixes, bgpPeerAcceptedPrefixes, metadata.Gauge, metadata.Count, bgpPeerAcceptedPrefixesDesc}, | ||
{deniedPrefixes, bgpPeerDeniedPrefixes, metadata.Counter, metadata.Count, bgpPeerDeniedPrefixesDesc}, | ||
{advertisedPrefixes, bgpPeerAdvertisedPrefixes, metadata.Counter, metadata.Count, bgpPeerAdvertisedPrefixesDesc}, | ||
{suppressedPrefixes, bgpPeerSuppressedPrefixes, metadata.Counter, metadata.Count, bgpPeerSuppressedPrefixesDesc}, | ||
{withdrawnPrefixes, bgpPeerWithdrawnPrefixes, metadata.Counter, metadata.Count, bgpPeerWithdrawnPrefixesDesc}, | ||
} | ||
for _, bA := range oids { | ||
if err := add(bA); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return md, nil | ||
} | ||
|
||
func snmp_ip_tree(host, community, oid string) (map[string]interface{}, error) { | ||
rows, err := snmp.Walk(host, community, oid) | ||
if err != nil { | ||
return nil, err | ||
} | ||
m := make(map[string]interface{}) | ||
for rows.Next() { | ||
key := "" | ||
var a interface{} | ||
id, err := rows.Scan(&a) | ||
if err != nil { | ||
return nil, err | ||
} | ||
switch t := id.(type) { | ||
case []int: | ||
key = snmp_combine_ip_int(t) | ||
default: | ||
return nil, fmt.Errorf("Got wrong type from OID check") | ||
} | ||
m[key] = a | ||
} | ||
if err := rows.Err(); err != nil && err != io.EOF { | ||
return nil, err | ||
} | ||
return m, nil | ||
} | ||
|
||
func snmp_combine_ip_uint8(path []uint8) string { | ||
s := make([]string, len(path)) | ||
for i := range path { | ||
s[i] = fmt.Sprint(path[i]) | ||
} | ||
// In some cases there's a .1.1 after the IP (because SNMP is awesome), drop it: | ||
s = s[:4] | ||
return strings.Join(s, ".") | ||
} | ||
|
||
func snmp_combine_ip_int(path []int) string { | ||
s := make([]string, len(path)) | ||
for i := range path { | ||
s[i] = fmt.Sprint(path[i]) | ||
} | ||
// In some cases there's a .1.1 after the IP (because SNMP is awesome), drop it: | ||
s = s[:4] | ||
return strings.Join(s, ".") | ||
} |