Device Monitoring & SNMP Polling
Poll devices with SNMPv2c: right-click interface quick-look, 64-bit HC counters, two-sample throughput, hardware resource gauges, and jump-host routing.
Overview
NetStacks polls network devices over SNMPv2c to surface live interface throughput, error and discard counters, link state, and hardware health without leaving the terminal. The SNMP client is built into the Local Agent, so every query runs from the same process that already holds your SSH sessions and credential vault — no external poller, no separate database, no agents on the devices.
The two places you will use SNMP most are:
- The interface Quick-Look — right-click an interface name in a terminal session to see a floating overlay with live in/out throughput and counters for that one port.
- The device detail panel in Network Topology — CPU, memory and temperature gauges plus a full interface table, polled directly over SNMP.
The built-in client speaks SNMPv2c (community-string auth). It uses GETBULK for efficient table walks — a v2c feature — so v1-only devices and v3 (USM auth/priv) are not handled by the native UDP path. Configure your community strings in the credential vault before polling.
All SNMP functions are stateless: each call opens a lightweight UDP exchange to the target on port 161 (configurable) and closes it. There is no persistent session and no background polling loop — queries happen on demand when you open a Quick-Look or a device panel.
How Polling Works
Every SNMP operation targets a host:port pair (default UDP port 161) with a community string, and times out after 5 seconds per round-trip. A single WALK is capped at 10,000 entries as a safety limit. The agent exposes four core operations — GET, WALK, try-communities, and interface-stats — that everything else is built on.
GET, WALK & GETBULK
A GET fetches one or more named OIDs in a single PDU. A WALK retrieves an entire subtree. Internally the WALK uses GETBULK with 25 repetitions per request rather than a GETNEXT loop, so a 200-row interface table is fetched in roughly 8 PDUs instead of 200 — about 25× fewer round-trips. The walk stops as soon as a returned OID falls outside the root subtree, or on endOfMibView.
You can run a raw GET or WALK from the API for any OID you like. For example, fetch sysDescr.0 and sysUpTime.0 in one GET:
curl -s http://127.0.0.1:9000/api/snmp/get \
-H 'Content-Type: application/json' \
-d '{
"host": "192.0.2.10",
"port": 161,
"community": "public",
"oids": ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0"]
}'The response carries a typed value for each varbind:
{
"values": [
{
"oid": "1.3.6.1.2.1.1.1.0",
"value": { "type": "String", "value": "Cisco IOS Software, C3560..." },
"valueType": "OctetString"
},
{
"oid": "1.3.6.1.2.1.1.3.0",
"value": { "type": "TimeTicks", "value": 184529900 },
"valueType": "TimeTicks"
}
]
}A WALK takes a single rootOid and returns every entry beneath it. This walks the standard ifDescr table (one row per interface):
curl -s http://127.0.0.1:9000/api/snmp/walk \
-H 'Content-Type: application/json' \
-d '{
"host": "192.0.2.10",
"community": "public",
"rootOid": "1.3.6.1.2.1.2.2.1.2"
}'Community Strings & Auto-Detect
Rather than hard-coding a community per device, store a list of community strings on a profile in the credential vault. The try-communities operation tries each one in turn with a sysName.0 GET and returns the first that works — along with the device’s system name. Timeouts and rejected communities are skipped silently; only a fully exhausted list returns an auth error.
curl -s http://127.0.0.1:9000/api/snmp/try-communities \
-H 'Content-Type: application/json' \
-d '{
"host": "192.0.2.10",
"profileId": "core-switches"
}'
# => { "community": "ro-public", "sysName": "core-sw-01" }The interface Quick-Look and device panel never ask you to type a community. They call the try-* endpoints, which resolve communities from the session’s profile vault — and if that profile has none configured, fall back to scanning your other profiles for one that has SNMP communities set. See SNMP Communities.
The Interface Quick-Look
When NetStacks detects an interface name in your terminal output (for example after a show ip interface brief or in a log line), right-clicking it surfaces a SNMP Stats: <interface> menu item. Selecting it opens a floating Quick-Look overlay anchored at the cursor — a focused, single-port live view that disappears when you press Esc or click outside it.
The overlay polls that one interface by name. Interface name matching is forgiving: it expands common abbreviations both ways, so right-clicking Gi0/0 matches GigabitEthernet0/0 and vice versa. The same logic covers Fa/Te/Tw/Fo/Hu/Et/Lo/Vl/Po/Tu/Se and management prefixes, with a case-insensitive substring match as a final fallback. To resolve the index, the agent walks ifDescr, ifName, and ifAlias — so an LLDP-style alias like to PE3-CHI can match too.
The header shows the resolved interface description, the device host, oper-status (color-coded up/down/testing), and link speed; the alias (ifAlias) appears as a subtitle when present.
64-bit HC Counters & Fallback
For each interface the agent GETs the full IF-MIB counter set in a single request and prefers the 64-bit High-Capacity (HC) counters from ifXTable — ifHCInOctets / ifHCOutOctets and the HC packet counters. These do not wrap on high-throughput links the way 32-bit counters do (a 32-bit octet counter wraps roughly every 34 seconds at 1 Gbps). If HC counters are unavailable on the device, it falls back to the 32-bit ifInOctets / ifOutOctets counters, and the response flags this with hcCounters: false. The Quick-Look footer then shows a (32-bit) marker so you know wrap correction was in play.
Speed resolution follows the same prefer-then-fallback pattern: it uses ifHighSpeed (in Mbps) when present, otherwise derives Mbps from the 32-bit ifSpeed (bps ÷ 1,000,000).
Two-Sample Throughput
SNMP octet counters are monotonic totals, not rates. To turn them into live throughput the Quick-Look takes two samples five seconds apart and divides the delta by the elapsed time:
bits_per_second = (octets_sample2 - octets_sample1) / seconds_between * 8The overlay walks a small state machine — polling-first → waiting (a 5-second countdown ring) → polling-second → complete — then renders In and Out rate cards (auto-scaled bps/Kbps/Mbps/Gbps) plus the deltas for errors-in, errors-out, and discards over the same window. Non-zero error or discard deltas are highlighted. A Refresh button restarts the two-sample cycle, and a “Polled Ns ago” readout keeps the age visible.
When a sample-2 value is lower than sample-1, the delta is negative. For 32-bit counters the overlay adds 2^32 to correct a single wrap. For 64-bit HC counters — which effectively never wrap in practice — a negative delta (e.g. after a device counter reset) is treated as 0 rather than a spurious huge spike.
The five-second gap is deliberate: it is long enough to average out bursts into a stable rate, short enough to feel live. If you need an exact instantaneous figure, refresh a few times — each press is a fresh, independent measurement.
Hardware Resource Gauges
Open a device in Network Topology and the detail panel polls hardware health alongside the interface table: CPU, memory, and temperature gauges. Resource polling is multi-vendor and best-effort — it probes vendor MIBs in order and falls through to standard HOST-RESOURCES-MIB / ENTITY-SENSOR-MIB, so an unsupported OID on one platform simply moves on to the next probe rather than failing the panel.
CPU tries, in order: Cisco cpmCPUTotal5minRev (IOS / IOS-XR / NX-OS), Juniper jnxOperatingCPU (5-min average), then standard hrProcessorLoad (Arista/Linux/generic), averaged across cores. The agent-side helper additionally pulls Cisco memory-pool used/free in the same first GET.
Memory tries Cisco MEMORY-POOL-MIB (used + free), then Cisco IOS-XR cempMemPoolHCUsed/cempMemPoolHCFree, then Juniper jnxOperatingBuffer (utilization %), then HOST-RESOURCES-MIB hrStorageTable — matching the RAM/physical-memory row by description.
Temperature tries Cisco ENVMON-MIB, Cisco ENTITY-SENSOR-MIB (sensor type 8 = celsius), Juniper jnxOperatingTemp, then standard ENTITY-SENSOR-MIB — reporting the hottest valid sensor reading.
Memory used and total are converted to bytes and rendered as a percentage; CPU is a 0–100% load; temperature is the maximum celsius reading across sensors. Any gauge whose OIDs the device does not answer is simply omitted — the panel never blocks on a probe that times out.
How Jump Routing Applies
SNMP is UDP, but SSH only forwards TCP — so you cannot tunnel UDP/161 through a bastion directly. NetStacks solves this by running the net-snmp CLI tools (snmpget, snmpwalk) over an SSH exec channel on the jump host and parsing their stdout back into the exact same value shape as the native UDP path. As a result every downstream consumer — interface stats, the Quick-Look, resource gauges, neighbor discovery — is destination-agnostic. A query is one of two kinds:
- Direct — the agent opens a UDP socket from its own process to
host:161. This is the default when no jump is involved. - Via jump — the agent SSHes to the bastion and runs net-snmp CLI tools there, aimed at the target’s
host:161over UDP from the jump’s vantage point. The jump host must have net-snmp installed.
The choice is resolved centrally so every caller follows identical rules:
- If the request supplies a session-level jump (the parent terminal session’s jump, passed as
jumpHostIdorjumpSessionId), use it. - Otherwise, if the named profile has a jump configured, use the profile’s jump.
- Otherwise, go direct.
jumpHostId and jumpSessionId are mutually exclusive. Setting both is rejected with a VALIDATION error. The Quick-Look passes through whichever jump the parent terminal session was opened with, so via-jump SNMP “just works” for devices you reached through a bastion.
To force a query through a bastion explicitly, add the jump id to any SNMP request body. Note the via-jump path is slower than direct UDP (it spins up an SSH exec per call), so the frontend uses a tighter 15-second timeout for interface-stats than its default client timeout:
curl -s http://127.0.0.1:9000/api/snmp/interface-stats \
-H 'Content-Type: application/json' \
-d '{
"host": "10.0.0.5",
"community": "public",
"interfaceName": "Te1/0/1",
"jumpHostId": "bastion-dc1"
}'HTTP API Reference
The Local Agent exposes these SNMP endpoints (all POST, JSON bodies). Every request accepts an optional port (default 161) and the optional mutually-exclusive jump fields jumpHostId / jumpSessionId.
| Endpoint | Purpose | Key fields |
|---|---|---|
/api/snmp/get | GET one or more OIDs | host, community, oids[] |
/api/snmp/walk | WALK a subtree (GETBULK) | host, community, rootOid |
/api/snmp/try-communities | Find a working community from vault | host, profileId |
/api/snmp/interface-stats | IF-MIB counters for one named interface | host, community, interfaceName |
/api/snmp/try-interface-stats | Interface stats using vault communities | host, profileId, interfaceName |
The interface-stats response includes both numeric status and text: operStatusText / adminStatusText (up/down/testing), ifTypeText (e.g. ethernetCsmacd), the resolved ifIndex, speedMbps, the full set of in/out octet, packet, error and discard counters, and the hcCounters flag.
{
"ifIndex": 10101,
"ifDescr": "TenGigabitEthernet1/0/1",
"ifAlias": "to PE3-CHI",
"operStatus": 1,
"operStatusText": "up",
"adminStatus": 1,
"adminStatusText": "up",
"ifType": 6,
"ifTypeText": "ethernetCsmacd",
"mtu": 9216,
"physAddress": "00:1a:2b:3c:4d:5e",
"speedMbps": 10000,
"inOctets": 884736102233,
"outOctets": 119238847711,
"inErrors": 0,
"outErrors": 0,
"inDiscards": 12,
"outDiscards": 0,
"hcCounters": true
}Errors map to specific codes and HTTP statuses so clients can react precisely:
| Code | HTTP | Meaning |
|---|---|---|
SNMP_TIMEOUT | 504 | No response within 5s (wrong community or unreachable) |
SNMP_CONNECTION_FAILED | 502 | Could not reach the target |
SNMP_AUTH_ERROR | 401 | Community string rejected / no working community |
INTERFACE_NOT_FOUND | — | Name matched no ifDescr/ifName/ifAlias row |
NOT_FOUND | — | noSuchObject / noSuchInstance for the OID |
VALIDATION | 400 | Bad OID, or both jump fields set |
In Personal Mode the requests above hit the Local Agent directly with host + profileId. In Controller (team/enterprise) mode the frontend sends a deviceId instead and the Controller resolves host and SNMP credentials server-side — you never pass a community over the wire.
OID Reference
The OIDs the interface-stats call fetches per interface index (IF-MIB / ifXTable):
1.3.6.1.2.1.2.2.1.2— ifDescr- Interface description (walked to resolve the index by name).
1.3.6.1.2.1.31.1.1.1.1— ifName- Short name (e.g.
Gi0/0/0), also searched for matching. 1.3.6.1.2.1.31.1.1.1.18— ifAlias- Configured description / LLDP-style label (e.g.
to PE3-CHI). 1.3.6.1.2.1.2.2.1.7/.8— ifAdminStatus / ifOperStatus- 1 = up, 2 = down, 3 = testing.
1.3.6.1.2.1.31.1.1.1.6/.10— ifHCInOctets / ifHCOutOctets- 64-bit byte counters — preferred for throughput.
1.3.6.1.2.1.2.2.1.10/.16— ifInOctets / ifOutOctets- 32-bit fallback byte counters.
1.3.6.1.2.1.2.2.1.14/.20— ifInErrors / ifOutErrors- Error counters shown as deltas in the Quick-Look.
1.3.6.1.2.1.2.2.1.13/.19— ifInDiscards / ifOutDiscards- Discard counters shown as deltas.
1.3.6.1.2.1.31.1.1.1.15— ifHighSpeed- Link speed in Mbps (preferred over the 32-bit
ifSpeedat.5).
System and resource OIDs used elsewhere:
sysDescr.0 1.3.6.1.2.1.1.1.0
sysName.0 1.3.6.1.2.1.1.5.0 (community auto-detect)
sysUpTime.0 1.3.6.1.2.1.1.3.0
cpmCPUTotal5minRev 1.3.6.1.4.1.9.9.109.1.1.1.1.8 (Cisco CPU)
ciscoMemoryPoolUsed 1.3.6.1.4.1.9.9.48.1.1.1.5 (Cisco mem used)
ciscoMemoryPoolFree 1.3.6.1.4.1.9.9.48.1.1.1.6 (Cisco mem free)
hrProcessorLoad 1.3.6.1.2.1.25.3.3.1.2 (generic CPU)Q&A
- Does NetStacks support SNMPv3 or SNMPv1?
- The native UDP client is SNMPv2c only (it relies on GETBULK). v1-only and v3 (USM) are not handled by the built-in path. Use a v2c community string in the vault.
- Why does the throughput take five seconds to appear?
- Throughput is computed from two counter samples spaced five seconds apart, divided by the elapsed time. The first sample shows immediately; the rate cards fill in after the second sample completes the window.
- What does the
(32-bit)marker in the footer mean? - The device did not expose 64-bit HC octet counters, so the agent fell back to 32-bit counters (
hcCounters: false). 32-bit octet counters can wrap quickly on fast links; the overlay corrects a single wrap by adding2^32to a negative delta. - I right-clicked an interface but there is no SNMP option.
- The Quick-Look only appears when the terminal session has both a host and a profile associated with it, and NetStacks recognized the text as an interface name. Make sure you connected via a saved profile and that SNMP communities are configured on it.
- My device is behind a bastion — will SNMP work?
- Yes. Because SSH cannot tunnel UDP, the agent runs net-snmp CLI tools on the jump host and parses their output. The jump must have
snmpget/snmpwalkinstalled. If the parent session used a jump, the Quick-Look reuses it automatically. - Interface name not found — what is matched?
- The agent searches
ifDescr,ifName, andifAlias, expanding abbreviations (e.g.Te1/0/1↔TenGigabitEthernet1/0/1) and falling back to a case-insensitive substring match. If none match you get anINTERFACE_NOT_FOUNDerror. - Does polling store history or run in the background?
- No. SNMP queries are on-demand and stateless — opening a Quick-Look or device panel triggers them, and nothing polls continuously or persists a time series. The product ships with zero device-side telemetry.
Related
- SNMP Communities — configure community strings on a profile.
- Network Topology — device detail panel with resource gauges and interface tables.
- Network Discovery — SNMP-based neighbor and topology discovery.
- SSH Tunnels & Port Forwarding — reaching devices through a bastion.
- Connecting to Devices — profiles, hosts, and jump configuration.
- The Local Agent — the process that runs SNMP queries.