这是indexloc提供的服务,不要输入任何密码
Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/scollector/collectors/snmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"bosun.org/opentsdb"
)

var builtInSNMPs = map[string]func(cfg conf.SNMP){"ifaces": SNMPIfaces, "cisco": SNMPCisco, "bridge": SNMPBridge, "ips": SNMPIPAddresses}
var builtInSNMPs = map[string]func(cfg conf.SNMP){"ifaces": SNMPIfaces, "cisco": SNMPCisco, "bridge": SNMPBridge, "ips": SNMPIPAddresses, "ciscobgp": SNMPCiscoBGP}

func SNMP(cfg conf.SNMP, mibs map[string]conf.MIB) error {
if cfg.Host == "" {
Expand Down
225 changes: 225 additions & 0 deletions cmd/scollector/collectors/snmp_ciscobgp.go
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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this return a simple map[string]string if that is what you really expect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, no - the map's values are int64 for some OIDs, []uint8 for others, and uint8 for others. The conversion to string from the .Scan result is just for the IP address embedded in the OID.

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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can declare a as []int instead of interface{} and pass that into Scan. Then you don;t have to do all of the type checking stuff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind me. I'm just confused.

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, ".")
}