leoribg/esp-snmp

1.0.0

Latest
uploaded 6 days ago
Read-only SNMPv1 and SNMPv2c agent with extensible OIDs for ESP-IDF

Readme

# ESP32 SNMP Agent Component

Read-only SNMPv1 and SNMPv2c agent for ESP-IDF, with standard system OIDs and an API for proprietary OIDs.

- GET and GETNEXT in v1/v2c; GETBULK in v2c.
- Compatible with numeric `snmpget`, `snmpwalk`, and `snmpbulkwalk` requests.
- Seven standard `system` scalars, including `sysDescr.0` (`1.3.6.1.2.1.1.1.0`).
- Static values, dynamic getters, and explicitly indexed table instances.
- Pure C protocol core, plus an ESP-IDF IPv4/UDP and FreeRTOS wrapper.
- No allocation in the protocol core while processing requests.

Requires ESP-IDF 5.1 or newer. Builds and runtime validation are described in [Testing](docs/testing.md).

## Install

After publishing this version, add it to an existing ESP-IDF project:

```bash
idf.py add-dependency "leoribg/esp-snmp^1.0.0"
idf.py reconfigure
```

Or declare it in `main/idf_component.yml`:

```yaml
dependencies:
  leoribg/esp-snmp: "^1.0.0"
```

Start from the bundled Wi-Fi example:

```bash
idf.py create-project-from-example "leoribg/esp-snmp^1.0.0:wifi_agent"
```

The Component Manager downloads the published package into `managed_components/` and adds it to the build. Wi-Fi or Ethernet initialization remains the responsibility of the application. See [Integration](docs/integration.md) for local and Git dependencies before publication.

## Quick start

Call this after the application has initialized `esp_netif` and obtained an IPv4 address:

```c
#include "esp_err.h"
#include "snmp_agent.h"

static snmp_agent_handle_t agent;

void start_snmp(void)
{
    snmp_agent_config_t config = SNMP_AGENT_CONFIG_DEFAULT();
    config.community = "public";
    config.sys_descr = "ESP32 environmental monitor";
    config.sys_name = "monitor-01";
    config.sys_location = "Laboratory";

    ESP_ERROR_CHECK(snmp_agent_create(&config, &agent));
    ESP_ERROR_CHECK(snmp_agent_start(agent));
}

void stop_snmp(void)
{
    ESP_ERROR_CHECK(snmp_agent_destroy(agent));
    agent = NULL;
}
```

`destroy()` stops the service before releasing its resources. To pause and resume an existing agent, call `snmp_agent_stop()` and then `snmp_agent_start()`. Register proprietary OIDs before the first start, or while stopped.

## Proprietary OIDs

A static INTEGER and a dynamic Gauge32 getter:

```c
#include "esp_err.h"
#include "esp_system.h"
#include "snmp_agent.h"

static int read_free_heap(void *context, snmp_value_t *value)
{
    (void)context;
    *value = (snmp_value_t) {
        .type = SNMP_TYPE_GAUGE32,
        .data.unsigned32 = esp_get_free_heap_size(),
    };
    return 0;
}

void register_product_oids(snmp_agent_handle_t agent)
{
    const snmp_value_t product_status = {
        .type = SNMP_TYPE_INTEGER,
        .data.integer = 1,
    };

    ESP_ERROR_CHECK(snmp_agent_register(
        agent, "1.3.6.1.4.1.32473.10.1.0", &product_status, NULL, NULL));
    ESP_ERROR_CHECK(snmp_agent_register(
        agent, "1.3.6.1.4.1.32473.10.2.0", NULL, read_free_heap, NULL));
}
```

Call `register_product_oids(agent)` between `create()` and `start()`. Supply exactly one of `value` or `getter`. Static values are copied; the getter context remains application-owned. Getters run in the agent task, return zero on success, and must be quick. Synchronize data shared with other tasks and keep borrowed string/OID buffers valid until the getter's next call.

Scalar instances end in `.0`. The PEN `32473` is reserved for documentation; replace it with your organization's PEN in production. See [OIDs](docs/oids.md) for strings, Counter64, compound table indexes, and the bundled [SMIv2 MIB](mibs/NOUVENN-SNMP-EXAMPLE-MIB.txt).

## Standard OIDs

| OID | Name | Type | Configuration |
| --- | --- | --- | --- |
| `1.3.6.1.2.1.1.1.0` | `sysDescr.0` | OCTET STRING | `sys_descr` |
| `1.3.6.1.2.1.1.2.0` | `sysObjectID.0` | OBJECT IDENTIFIER | `sys_object_id` |
| `1.3.6.1.2.1.1.3.0` | `sysUpTime.0` | TimeTicks | Updated automatically |
| `1.3.6.1.2.1.1.4.0` | `sysContact.0` | OCTET STRING | `sys_contact` |
| `1.3.6.1.2.1.1.5.0` | `sysName.0` | OCTET STRING | `sys_name` |
| `1.3.6.1.2.1.1.6.0` | `sysLocation.0` | OCTET STRING | `sys_location` |
| `1.3.6.1.2.1.1.7.0` | `sysServices.0` | INTEGER | `sys_services` |

`sysUpTime` measures hundredths of a second since the latest successful agent start. All objects are read-only, including the standard objects that permit writes in other agents. The other MIB-II groups are not automatically implemented.

## Query and walk

Replace the IP address with the address reported by your application:

```bash
snmpget -v1 -c public -On udp:192.168.1.123:161 1.3.6.1.2.1.1.1.0
snmpget -v2c -c public -On udp:192.168.1.123:161 1.3.6.1.2.1.1.1.0
snmpwalk -v1 -c public -On udp:192.168.1.123:161 1.3.6.1
snmpwalk -v2c -c public -On udp:192.168.1.123:161 1.3.6.1
snmpbulkwalk -v2c -c public -Cr10 -On udp:192.168.1.123:161 1.3.6.1
```

Numeric OIDs work without installing a MIB on the monitoring computer. Walks return registered OIDs in numeric lexicographic order regardless of registration order.

## API

| Function | Purpose |
| --- | --- |
| `snmp_agent_create()` | Allocate an agent and register the seven system scalars |
| `snmp_agent_register()` | Register a static value or a getter |
| `snmp_agent_register_instance()` | Register an instance with an explicit object prefix for compound indexes |
| `snmp_agent_start()` | Bind the UDP socket and start the worker task |
| `snmp_agent_stop()` | Stop the worker synchronously; safe to repeat on a live handle |
| `snmp_agent_destroy()` | Stop the worker and release the handle |

See [API and limits](docs/api.md) and the public headers [snmp_agent.h](include/snmp_agent.h) and [snmp_core.h](include/snmp_core.h). Calls on a live agent are serialized internally. The application must prevent concurrent calls during or after destruction. Getters must not call lifecycle or registration APIs.

## Configuration

`menuconfig` → **Component config** → **SNMP** sets defaults used by `SNMP_AGENT_CONFIG_DEFAULT()`:

| Symbol | Default | Effect |
| --- | --- | --- |
| `CONFIG_SNMP_DEFAULT_COMMUNITY` | `"public"` | Default read community; 1 through 64 bytes are accepted by the API |
| `CONFIG_SNMP_DEFAULT_PORT` | `161` | UDP port, 1 through 65535 |
| `CONFIG_SNMP_DEFAULT_TASK_STACK_SIZE` | `8192` | Task stack size in bytes, 8192 through 65536 |
| `CONFIG_SNMP_DEFAULT_TASK_PRIORITY` | `5` | Task priority, 0 through 24; must also be below `configMAX_PRIORITIES` |

These are defaults. Fields assigned explicitly in `snmp_agent_config_t` take precedence. Pin project defaults in `sdkconfig.defaults` instead of editing generated `sdkconfig` manually.

The other defaults in `SNMP_AGENT_CONFIG_DEFAULT()` are:

| Field | Default | Effect |
| --- | --- | --- |
| `bind_address` | `"0.0.0.0"` | Numeric IPv4 address; all interfaces by default |
| `sys_descr` | `"ESP32 SNMP v1/v2c agent"` | Device description |
| `sys_object_id` | `"1.3.6.1.4.1.32473.1"` | Device type OID |
| `sys_contact` | `""` | Contact string |
| `sys_name` | `"esp32"` | Device name |
| `sys_location` | `""` | Physical location |
| `sys_services` | `72` | Services bitmask, 0 through 127 |

Configuration strings are copied at creation. To change them, destroy the agent and create another. Wi-Fi credentials belong to the example application's **Wi-Fi SNMP example** menu; the library does not own or configure the network interface. The examples explicitly set community and port from their own application menus.

## Limits and behavior

- Up to 64 registered instances, including the seven standard objects: 57 are available for application objects.
- Up to 128 OID arcs, 32 request/GETBULK bindings, 1400-byte packets, and 1024-byte OCTET STRING/Opaque values.
- Counter64 is available in v2c and hidden from the v1 view.
- GETBULK may return fewer bindings to fit the packet and binding limits. Clients continue from the last returned OID.
- SET returns `readOnly` in v1 and `notWritable` in v2c. SNMPv3, traps, and informs are not implemented.
- Invalid communities and malformed or unsupported requests are dropped.
- SNMPv1/v2c communities are sent without encryption. Use an appropriately restricted management network.

## Repository layout and tested targets

This component lives at `components/esp-snmp` inside the development project. Its own `CMakeLists.txt` registers `src/snmp_core.c` and `src/snmp_agent.c`, exposing `include/`. The bundled [`examples/wifi_agent`](examples/wifi_agent/README.md) is an independent ESP-IDF project. Everything needed to build a consuming application is contained in this component directory.

ESP32 and ESP32-C6 builds have been exercised with ESP-IDF 6.0.2, with physical ESP32-C6 validation. The declared ESP-IDF 5.1 minimum and other targets have not all been runtime-tested. See [Testing](docs/testing.md) for commands, evidence, and transport limitations, and [manual publishing](docs/publishing.md) for publishing this directory.

## License

MIT. See [LICENSE](LICENSE) and [CHANGELOG.md](CHANGELOG.md).

Links

Supports all targets

To add this component to your project, run:

idf.py add-dependency "leoribg/esp-snmp^1.0.0"

download archive

Stats

  • Archive size
    Archive size ~ 43.61 KB
  • Downloaded in total
    Downloaded in total 1 time
  • Weekly Downloads Weekly Downloads (All Versions)
  • Downloaded this version
    This version: 1 time

Badge

leoribg/esp-snmp version: 1.0.0
|