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 }