Owner request: finding where a host is plugged in from a MAC or IP is a must,
and BGP peer monitoring is wanted.
L2 job (internal/l2): a job of its own, off the 60 s poll path (its sessions
are path "l2"), walks BRIDGE-MIB, Q-BRIDGE-MIB, CISCO-VTP-MIB (a per-VLAN
context walk, enabled by the cisco-ios profile flag l2.per_vlan_context, not by
detection) and the IP-MIB neighbour tables (IPv4 ARP and IPv6 ND, IPv4-only
fallback) every l2.interval, with its own concurrency cap and a per-device
deadline. It yields to the poller like the rollup job, and a device that times
out is skipped for the cycle, counted and named on /poller/health. Migration 14
adds fdb_entries, arp_entries, vlans and l2_walks with first/last-seen history,
batched upserts, daily pruning by last_seen (l2.keep) and backup coverage.
API (additive): /l2/search ranks edge ports first (a port is an uplink above
l2.edge_max_macs MACs, with an LLDP neighbour, or as a LAG), plus the device
fdb/arp/l2/l2-ports tables and /interfaces/{id}/macs; vendor and mac_kind are
computed at query time from the optional registry.
BGP: profiles label peer rows by decoding the table index (index_label.layout),
so each peer, IPv4 or IPv6, is one component whatever MIB feeds it; AS, local
AS, router id and description are component attributes, never labels.
CISCO-BGP4 (cisco-ios, cisco-nxos), Juniper BGP4-V2 and Arista BGP4V2 replace
the optional generic BGP4-MIB metrics, which edgeos, fortigate, pfsense and vyos
switch on. /bgp/peers lists sessions down first. The built-in rule
bgp_peer_down (critical, not established for 2 minutes) fires only where a
policy binds it; its notification names the peer's AS and description.
Fixtures are generated (Q-BRIDGE with IPv4/IPv6 neighbours, BRIDGE-MIB only,
Cisco per-VLAN contexts via a new simagent contexts feature) and checked
against real LibreNMS recordings. DEVIATIONS 50-55 record the departures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T4PdJUPrakM8fHvN8jYv2x
116 lines
7.7 KiB
YAML
116 lines
7.7 KiB
YAML
# Provenance: standard objects (all under mibs/: IF-MIB, SNMPv2-MIB,
|
|
# HOST-RESOURCES-MIB, UCD-SNMP-MIB, ENTITY-MIB, ENTITY-SENSOR-MIB, IP-MIB;
|
|
# every OID verified with snmptranslate). Standard objects from IF-MIB (RFC 2863), SNMPv2-MIB (RFC 3418),
|
|
# HOST-RESOURCES-MIB (RFC 2790), UCD-SNMP-MIB (net-snmp project documentation),
|
|
# ENTITY-MIB (RFC 6933), ENTITY-SENSOR-MIB (RFC 3433) and IP-MIB (RFC 4293).
|
|
# OIDs are the IANA/IETF-registered values; no MIB text is reproduced.
|
|
#
|
|
# Decision: hrStorageUsed/Size/AllocationUnits are labelled with the row's
|
|
# hrStorageDescr value, but the label key is `component` (index_label.as), not
|
|
# `hrStorageDescr`. Build detail "Metric labels" allows no SNMP label besides
|
|
# device and iface/component, and the spec's hrStorageUsed{device, hrStorageDescr}
|
|
# is read as "the descr identifies the row". Dashboards and alert rules select
|
|
# on `component`.
|
|
#
|
|
# Notes: mem* objects are kilobytes (scale 1024 gives bytes). entPhySensorValue
|
|
# is the raw sensor reading; its type, scale and precision live in inventory, so
|
|
# its unit here is `count`. ipIfStats metrics are opt-in: a profile switches them
|
|
# on by restating the metric with `enabled: true`.
|
|
name: generic
|
|
priority: 0
|
|
provenance: IF-MIB, SNMPv2-MIB, HOST-RESOURCES-MIB, UCD-SNMP-MIB, ENTITY-MIB, ENTITY-SENSOR-MIB, IP-MIB (IETF RFCs and net-snmp docs)
|
|
snmp:
|
|
max_repetitions: 25
|
|
concurrency: 1
|
|
interfaces:
|
|
exclude_ifname: ['^lo$', '^lo[0-9]*$', '^Loopback', '^Null0$', '^NULL', '^InLoopBack']
|
|
discovery_tables:
|
|
- ENTITY-MIB::entPhysicalTable
|
|
- HOST-RESOURCES-MIB::hrStorageTable
|
|
- LLDP-MIB::lldpRemTable
|
|
- BGP4-MIB::bgpPeerTable
|
|
# BGP4-MIB (RFC 4273) is IPv4 peers only and optional: router profiles switch it on with enable_metrics, and
|
|
# profiles with a vendor BGP table (CISCO-BGP4, Juniper BGP4-V2, Arista BGP4V2) replace these metrics by name, so a
|
|
# peer is never reported twice. Rows are indexed by the peer address, so the component label is decoded from the index.
|
|
component_attrs:
|
|
- { table: "BGP4-MIB::bgpPeerTable", name: remote_as, oid: 1.3.6.1.2.1.15.3.1.9 } # bgpPeerRemoteAs
|
|
- { table: "BGP4-MIB::bgpPeerTable", name: router_id, oid: 1.3.6.1.2.1.15.3.1.1 } # bgpPeerIdentifier
|
|
metrics:
|
|
- { name: ifHCInOctets, oid: 1.3.6.1.2.1.31.1.1.1.6, type: counter64, unit: octets, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- { name: ifHCOutOctets, oid: 1.3.6.1.2.1.31.1.1.1.10, type: counter64, unit: octets, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- { name: ifInErrors, oid: 1.3.6.1.2.1.2.2.1.14, type: counter32, unit: errors, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- { name: ifOutErrors, oid: 1.3.6.1.2.1.2.2.1.20, type: counter32, unit: errors, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- { name: ifInDiscards, oid: 1.3.6.1.2.1.2.2.1.13, type: counter32, unit: packets, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- { name: ifOutDiscards, oid: 1.3.6.1.2.1.2.2.1.19, type: counter32, unit: packets, interval: 60s, index_label: { column: ifIndex, as: iface } }
|
|
- name: ifOperStatus
|
|
oid: 1.3.6.1.2.1.2.2.1.8
|
|
type: status
|
|
unit: enum
|
|
interval: 60s
|
|
index_label: { column: ifIndex, as: iface }
|
|
enum: { 1: up, 2: down, 3: testing, 4: unknown, 5: dormant, 6: notPresent, 7: lowerLayerDown }
|
|
- name: ifAdminStatus
|
|
oid: 1.3.6.1.2.1.2.2.1.7
|
|
type: status
|
|
unit: enum
|
|
interval: 60s
|
|
index_label: { column: ifIndex, as: iface }
|
|
enum: { 1: up, 2: down, 3: testing }
|
|
- { name: sysUpTime, oid: 1.3.6.1.2.1.1.3.0, type: gauge, unit: seconds, interval: 60s, category: system, label: "Uptime" }
|
|
- { name: hrSystemUptime, oid: 1.3.6.1.2.1.25.1.1.0, type: gauge, unit: seconds, interval: 5m, category: system, label: "System uptime" }
|
|
- { name: hrProcessorLoad, oid: 1.3.6.1.2.1.25.3.3.1.2, type: gauge, unit: percent, interval: 5m, index_label: { column: hrDeviceIndex, as: component }, category: health, label: "CPU load" }
|
|
- { name: hrStorageUsed, oid: 1.3.6.1.2.1.25.2.3.1.6, type: gauge, unit: count, interval: 5m, index_label: { column: hrStorageDescr, as: component }, table: "HOST-RESOURCES-MIB::hrStorageTable", category: health, label: "Storage used", of: hrStorageSize, scale_by: hrStorageAllocationUnits }
|
|
- { name: hrStorageSize, oid: 1.3.6.1.2.1.25.2.3.1.5, type: gauge, unit: count, interval: 5m, index_label: { column: hrStorageDescr, as: component }, table: "HOST-RESOURCES-MIB::hrStorageTable", category: health, label: "Storage size", scale_by: hrStorageAllocationUnits }
|
|
- { name: hrStorageAllocationUnits, oid: 1.3.6.1.2.1.25.2.3.1.4, type: gauge, unit: bytes, interval: 5m, index_label: { column: hrStorageDescr, as: component }, table: "HOST-RESOURCES-MIB::hrStorageTable", category: health, label: "Allocation unit" }
|
|
- { name: memTotalReal, oid: 1.3.6.1.4.1.2021.4.5.0, type: gauge, unit: bytes, scale: 1024, interval: 5m, category: health, label: "Memory total" }
|
|
- { name: memAvailReal, oid: 1.3.6.1.4.1.2021.4.6.0, type: gauge, unit: bytes, scale: 1024, interval: 5m, category: health, label: "Memory available", of: memTotalReal }
|
|
- { name: entPhySensorValue, oid: 1.3.6.1.2.1.99.1.1.1.4, type: gauge, unit: count, interval: 5m, index_label: { column: entPhysicalName, as: component }, table: "ENTITY-MIB::entPhysicalTable", category: environment, label: "Sensor reading (raw)" }
|
|
# Opt-in per-address-family octets from IP-MIB ipIfStatsTable (index ipVersion.ifIndex).
|
|
- { name: ipIfStatsHCInOctetsV4, oid: 1.3.6.1.2.1.4.31.3.1.6, type: counter64, unit: octets, interval: 5m, index_label: { column: ifIndex, as: iface }, index_prefix: "1", optional: true, enabled: false }
|
|
- { name: ipIfStatsHCOutOctetsV4, oid: 1.3.6.1.2.1.4.31.3.1.33, type: counter64, unit: octets, interval: 5m, index_label: { column: ifIndex, as: iface }, index_prefix: "1", optional: true, enabled: false }
|
|
- { name: ipIfStatsHCInOctetsV6, oid: 1.3.6.1.2.1.4.31.3.1.6, type: counter64, unit: octets, interval: 5m, index_label: { column: ifIndex, as: iface }, index_prefix: "2", optional: true, enabled: false }
|
|
- { name: ipIfStatsHCOutOctetsV6, oid: 1.3.6.1.2.1.4.31.3.1.33, type: counter64, unit: octets, interval: 5m, index_label: { column: ifIndex, as: iface }, index_prefix: "2", optional: true, enabled: false }
|
|
# BGP4-MIB bgpPeerTable (1.3.6.1.2.1.15.3.1), verified against mibs/BGP4-MIB. Off unless enable_metrics names them.
|
|
- name: bgp_peer_state
|
|
category: routing
|
|
label: "BGP session state"
|
|
oid: 1.3.6.1.2.1.15.3.1.2 # bgpPeerState
|
|
type: status
|
|
unit: enum
|
|
interval: 5m
|
|
index_label: { as: component, layout: ipv4 }
|
|
table: "BGP4-MIB::bgpPeerTable"
|
|
enum: { 1: idle, 2: connect, 3: active, 4: opensent, 5: openconfirm, 6: established }
|
|
enum_state: { idle: crit, connect: crit, active: crit, opensent: crit, openconfirm: crit, established: ok }
|
|
optional: true
|
|
- name: bgp_peer_uptime
|
|
category: routing
|
|
label: "BGP session uptime"
|
|
oid: 1.3.6.1.2.1.15.3.1.16 # bgpPeerFsmEstablishedTime
|
|
type: gauge
|
|
unit: seconds
|
|
interval: 5m
|
|
index_label: { as: component, layout: ipv4 }
|
|
table: "BGP4-MIB::bgpPeerTable"
|
|
optional: true
|
|
- name: bgp_peer_in_updates
|
|
category: routing
|
|
label: "BGP updates received"
|
|
oid: 1.3.6.1.2.1.15.3.1.10 # bgpPeerInUpdates
|
|
type: counter32
|
|
unit: count
|
|
interval: 5m
|
|
index_label: { as: component, layout: ipv4 }
|
|
table: "BGP4-MIB::bgpPeerTable"
|
|
optional: true
|
|
- name: bgp_peer_out_updates
|
|
category: routing
|
|
label: "BGP updates sent"
|
|
oid: 1.3.6.1.2.1.15.3.1.11 # bgpPeerOutUpdates
|
|
type: counter32
|
|
unit: count
|
|
interval: 5m
|
|
index_label: { as: component, layout: ipv4 }
|
|
table: "BGP4-MIB::bgpPeerTable"
|
|
optional: true
|