# SNMP Monitoring

> Monitor network devices, Nutanix clusters, and legacy infrastructure by collecting SNMP metrics and sending them to Last9.

Source: https://last9.io/docs/integrations/others/snmp/

SNMP (Simple Network Management Protocol) is the standard protocol for monitoring network devices — switches, routers, firewalls, UPS units, and hypervisors like Nutanix. Last9 collects SNMP metrics via the OpenTelemetry Collector or the Prometheus SNMP Exporter.

## How it works

```
SNMP Device                  Collector                    Last9
(switch, router,  ──GET/WALK──▶  OTel Collector       ──OTLP──▶  Levitate
 Nutanix, UPS)                   or Prometheus                    (metrics)
                                 SNMP Exporter
```

The collector polls SNMP-capable devices at a configurable interval, converts the OID values to metrics, and forwards them to Last9.

## Prerequisites

- OpenTelemetry Collector Contrib v0.90.0 or later (for `snmpreceiver`)
- Or Prometheus SNMP Exporter if you prefer the Prometheus path
- Network access from the collector host to the SNMP device (UDP port 161)
- SNMP community string (v1/v2c) or credentials (v3)
- Last9 OTLP endpoint and authentication credentials

## Approach 1 — OTel snmpreceiver (recommended)

Use this when you want a single OTel Collector to handle SNMP alongside other receivers (hostmetrics, sqlserver, etc.).

### Install OTel Collector Contrib

Download from the [releases page](https://github.com/open-telemetry/opentelemetry-collector-releases/releases) and install as a service. If you already have a collector running for host metrics, add the SNMP receiver to the same config.

### Configuration

```yaml
receivers:
  snmp:
    collection_interval: 60s
    endpoint: "udp://192.168.1.1:161" # Replace with device IP
    version: v2c
    community: "public" # Replace with your community string
    # For SNMPv3:
    # version: v3
    # user: "monitoruser"
    # security_level: auth_priv
    # auth_type: MD5
    # auth_password: "${env:SNMP_AUTH_PASSWORD}"
    # privacy_type: DES
    # privacy_password: "${env:SNMP_PRIV_PASSWORD}"
    resource_attributes:
      device.name:
        scalar_oid: "1.3.6.1.2.1.1.5.0" # sysName — scalar, not a table OID
    attributes:
      interface_name:
        oid: "1.3.6.1.2.1.2.2.1.2" # ifDescr — looked up by the same table index
    metrics:
      # Interface traffic — cumulative counters
      network.interface.in.octets:
        unit: "By"
        sum:
          value_type: int
          aggregation: cumulative
          monotonic: true
        column_oids:
          - oid: "1.3.6.1.2.1.2.2.1.10" # ifInOctets
            attributes:
              - name: interface_name
      network.interface.out.octets:
        unit: "By"
        sum:
          value_type: int
          aggregation: cumulative
          monotonic: true
        column_oids:
          - oid: "1.3.6.1.2.1.2.2.1.16" # ifOutOctets
            attributes:
              - name: interface_name
      # System uptime — gauge (resets on reboot)
      system.uptime:
        unit: "cs"
        gauge:
          value_type: int
        scalar_oids:
          - oid: "1.3.6.1.2.1.1.3.0" # sysUpTime
      # CPU (Cisco IOS example)
      system.cpu.utilization:
        unit: "%"
        gauge:
          value_type: double
        scalar_oids:
          - oid: "1.3.6.1.4.1.9.2.1.57.0"

processors:
  resourcedetection:
    detectors: [env, system]

exporters:
  otlphttp:
    endpoint: "https://<your-last9-otlp-endpoint>"
    headers:
      Authorization: "Basic <your-base64-credentials>"
    compression: gzip

service:
  pipelines:
    metrics:
      receivers: [snmp]
      processors: [resourcedetection]
      exporters: [otlphttp]
```

### Monitor multiple devices

Add one `snmp` receiver per device, each with a unique name:

```yaml
receivers:
  snmp/core-switch:
    endpoint: "udp://10.0.0.1:161"
    community: "public"
    # ... metrics config
  snmp/firewall:
    endpoint: "udp://10.0.0.2:161"
    community: "public"
    # ... metrics config

service:
  pipelines:
    metrics:
      receivers: [snmp/core-switch, snmp/firewall]
      processors: [resourcedetection]
      exporters: [otlphttp]
```

## Approach 2 — Prometheus SNMP Exporter

Use this when you already have a Prometheus SNMP Exporter running, or prefer managing MIB files with the Prometheus toolchain.

### Run the Prometheus SNMP Exporter

```bash
docker run -d \
  --name snmp-exporter \
  -p 9116:9116 \
  -v ./snmp.yml:/etc/snmp_exporter/snmp.yml \
  prom/snmp-exporter:latest
```

Generate `snmp.yml` from MIB files using the [snmp_exporter generator](https://github.com/prometheus/snmp_exporter/tree/main/generator).

### Scrape with OTel Collector

```yaml
receivers:
  prometheus:
    config:
      scrape_configs:
        - job_name: snmp
          static_configs:
            - targets:
                - 192.168.1.1 # Device IP — passed as 'target' param to exporter
          metrics_path: /snmp
          params:
            module: [if_mib]
          relabel_configs:
            - source_labels: [__address__]
              target_label: __param_target
            - source_labels: [__param_target]
              target_label: instance
            - replacement: localhost:9116
              target_label: __address__

exporters:
  otlphttp:
    endpoint: "https://<your-last9-otlp-endpoint>"
    headers:
      Authorization: "Basic <your-base64-credentials>"
    compression: gzip

service:
  pipelines:
    metrics:
      receivers: [prometheus]
      exporters: [otlphttp]
```

## Nutanix cluster monitoring

Nutanix Prism exposes SNMP OIDs for cluster health. Use the snmpreceiver with Nutanix-specific OIDs, or use the [nutanix-exporter](https://github.com/claranet/nutanix-exporter) which queries the Prism REST API and exposes Prometheus metrics.

```yaml
# Nutanix via snmpreceiver
receivers:
  snmp/nutanix:
    endpoint: "udp://<prism-ip>:161"
    version: v2c
    community: "public"
    metrics:
      nutanix.cluster.cpu.usage:
        unit: "%"
        gauge:
          value_type: double
        scalar_oids:
          - oid: "1.3.6.1.4.1.41263.1.1" # clusterCpuUsagePpm — divide by 10000 for %
      nutanix.cluster.memory.usage:
        unit: "%"
        gauge:
          value_type: double
        scalar_oids:
          - oid: "1.3.6.1.4.1.41263.1.2"
      nutanix.cluster.storage.usage:
        unit: "By"
        gauge:
          value_type: int
        scalar_oids:
          - oid: "1.3.6.1.4.1.41263.2.1"
```

:::note
Enable SNMP on Nutanix Prism: Settings → SNMP → Configure SNMP. For Prism REST API monitoring instead of SNMP, use the Prometheus nutanix-exporter (more metrics available).
:::

## Common OIDs reference

| Metric               | OID                    | Notes                    |
| -------------------- | ---------------------- | ------------------------ |
| System name          | `1.3.6.1.2.1.1.5.0`    | sysName                  |
| System uptime        | `1.3.6.1.2.1.1.3.0`    | sysUpTime (centiseconds) |
| Interface in bytes   | `1.3.6.1.2.1.2.2.1.10` | ifInOctets (table)       |
| Interface out bytes  | `1.3.6.1.2.1.2.2.1.16` | ifOutOctets (table)      |
| Interface errors in  | `1.3.6.1.2.1.2.2.1.14` | ifInErrors (table)       |
| Interface errors out | `1.3.6.1.2.1.2.2.1.20` | ifOutErrors (table)      |
| Interface status     | `1.3.6.1.2.1.2.2.1.8`  | ifOperStatus (table)     |

For vendor-specific OIDs (Cisco, Juniper, HP, Nutanix), refer to the device's MIB files.

## Approach comparison

|                  | OTel snmpreceiver        | Prometheus SNMP Exporter              |
| ---------------- | ------------------------ | ------------------------------------- |
| Setup complexity | Low — single config file | Higher — MIB generator step           |
| MIB support      | Manual OID config        | Full MIB file support                 |
| Best for         | Known OIDs, quick setup  | Large MIB libraries, Prometheus users |
| Existing setup   | Works standalone         | Needs Prometheus or OTel scraper      |

## Verify metrics in Last9

After starting the collector, open Last9 → **Metrics** and search for your metric name (e.g., `network.interface.in.octets`). Filter by `device.name` to see per-device data.

Create a dashboard panel with:

```promql
rate(network_interface_in_octets{device_name="core-switch"}[5m]) * 8
```

This gives interface throughput in bits per second.

## Troubleshooting

| Symptom                   | Solution                                                                                                     |
| ------------------------- | ------------------------------------------------------------------------------------------------------------ |
| No metrics in Last9       | Check UDP port 161 is reachable from collector host: `snmpwalk -v2c -c public <device-ip> 1.3.6.1.2.1.1.5.0` |
| Authentication error      | Verify community string or SNMPv3 credentials; check device SNMP ACL allows collector IP                     |
| OID returns no data       | Confirm OID exists on device: `snmpget -v2c -c public <device-ip> <oid>`                                     |
| Metrics have wrong values | Some OIDs are counters — use `rate()` in PromQL instead of raw values                                        |
| High collector memory     | Reduce `collection_interval` frequency or limit number of OIDs polled per device                             |
