Search documentation of snmpkit

# SnmpKit.SnmpLib.Manager (snmpkit v1.2.0)

High-level SNMP management operations providing a simplified interface for common SNMP tasks.

This module builds on the core SnmpLib functionality to provide production-ready SNMP management capabilities including GET, GETBULK, SET operations with intelligent error handling, connection reuse, and performance optimizations.

## Features

- Simple API: High-level functions for common SNMP operations
- Connection Reuse: Efficient socket management for multiple operations
- Error Handling: Comprehensive error handling with meaningful messages
- Performance: Optimized for bulk operations and large-scale polling
- Timeout Management: Configurable timeouts with sensible defaults
- Community Support: Support for different community strings per device

## Quick Start

    # Simple GET operation
    {:ok, {type, value}} = SnmpKit.SnmpLib.Manager.get("192.168.1.1", [1, 3, 6, 1, 2, 1, 1, 1, 0])

    # GET with custom community and timeout
    {:ok, {type, value}} = SnmpKit.SnmpLib.Manager.get("192.168.1.1", "1.3.6.1.2.1.1.1.0",
                                       community: "private", timeout: 10_000)

    # Bulk operations for efficiency
    {:ok, results} = SnmpKit.SnmpLib.Manager.get_bulk("192.168.1.1", [1, 3, 6, 1, 2, 1, 2, 2],
                                               max_repetitions: 20)

    # SET operation
    {:ok, :success} = SnmpKit.SnmpLib.Manager.set("192.168.1.1", [1, 3, 6, 1, 2, 1, 1, 5, 0],
                                          {:string, "New System Name"})

## Configuration Options

- `community`: SNMP community string (default: "public")
- `version`: SNMP version (:v1, :v2c) (default: :v2c)
- `timeout`: Operation timeout in milliseconds (default: 5000)
- `retries`: Number of retry attempts (default: 3)
- `port`: SNMP port (default: 161)
- `local_port`: Local source port (default: 0 for random)

# Summary

## Types

bulk_opts()
bulk_result()
community()
host()
manager_opts()
oid()
operation_result()
snmp_value()
varbind()
version()

## Functions

get(host, oid, opts \\ [])

Performs an SNMP GET operation to retrieve a single value.

get_bulk(host, base_oid, opts \\ [])

Performs an SNMP GETBULK operation for efficient bulk data retrieval.

get_multi(host, oids, opts \\ [])

Performs multiple GET operations efficiently with connection reuse.

get_next(host, oid, opts \\ [])

Performs an SNMP GETNEXT operation to retrieve the next value in the MIB tree.

interpret_error(error, arg2, version)

Interprets SNMP errors with enhanced semantics for common cases.

ping(host, opts \\ [])

Checks if a host is reachable via SNMP by performing a basic GET operation.

set(host, oid, arg, opts \\ [])

Performs an SNMP SET operation to modify a value on the target device.

# Types

# bulk_opts()

    @type bulk_opts() :: [
      community: community(),
      version: version(),
      timeout: pos_integer(),
      retries: non_neg_integer(),
      port: pos_integer(),
      local_port: non_neg_integer(),
      max_repetitions: pos_integer(),
      non_repeaters: non_neg_integer()
    ]

# bulk_result()

    @type bulk_result() :: {:ok, [varbind()]} | {:error, atom() | {atom(), any()}}

# community()

    @type community() :: binary()

# host()

    @type host() :: binary() | :inet.ip_address()

# manager_opts()

    @type manager_opts() :: [
      community: community(),
      version: version(),
      timeout: pos_integer(),
      retries: non_neg_integer(),
      port: pos_integer(),
      local_port: non_neg_integer()
    ]

# oid()

    @type oid() :: [non_neg_integer()] | binary()

# operation_result()

    @type operation_result() :: {:ok, snmp_value()} | {:error, atom() | {atom(), any()}}

# snmp_value()

    @type snmp_value() :: any()

# varbind()

    @type varbind() :: {oid(), snmp_value()}

# version()

    @type version() :: :v1 | :v2c

# Functions

# get(host, oid, opts \\ [])

    @spec get(host(), oid(), manager_opts()) ::
      {:ok, {atom(), any()}}
      | {:error, atom() | {:network_error, atom()} | {:socket_error, atom()}}

Performs an SNMP GET operation to retrieve a single value.

## Parameters

- `host`: Target device IP address or hostname
- `oid`: Object identifier as list or string (e.g., [1,3,6,1,2,1,1,1,0] or "1.3.6.1.2.1.1.1.0")
- `opts`: Configuration options (see module docs for available options)

## Returns

- `{:ok, {type, value}}`: Successfully retrieved the value with its SNMP type
- `{:error, reason}`: Operation failed with reason

## Examples

    # Basic GET operation (would succeed with real device)
    # SnmpKit.SnmpLib.Manager.get("192.168.1.1", [1, 3, 6, 1, 2, 1, 1, 1, 0])
    # {:ok, {:octet_string, "Cisco IOS Software"}}

    # GET with custom community and timeout (would succeed with real device)
    # SnmpKit.SnmpLib.Manager.get("192.168.1.1", "1.3.6.1.2.1.1.1.0", community: "private", timeout: 10_000)
    # {:ok, {:octet_string, "Private System Description"}}

    # Test that function exists and handles invalid input properly
    iex> match?({:error, _}, SnmpKit.SnmpLib.Manager.get("invalid.host", [1, 3, 6, 1, 2, 1, 1, 3, 0], timeout: 100))
    true

# get_bulk(host, base_oid, opts \\ [])

    @spec get_bulk(host(), oid(), bulk_opts()) :: bulk_result()

Performs an SNMP GETBULK operation for efficient bulk data retrieval.

GETBULK is more efficient than multiple GET operations when retrieving multiple consecutive values, especially for table walking operations.

## Parameters

- `host`: Target device IP address or hostname
- `base_oid`: Base OID to start the bulk operation
- `opts`: Configuration options including bulk-specific options

## Bulk-Specific Options

- `max_repetitions`: Maximum number of repetitions (default: 10)
- `non_repeaters`: Number of non-repeating variables (default: 0)

## Returns

- `{:ok, varbinds}`: List of {oid, type, value} tuples
- `{:error, reason}`: Operation failed with reason

## Examples

    # Test that get_bulk function exists and handles invalid input properly
    iex> match?({:error, _}, SnmpKit.SnmpLib.Manager.get_bulk("invalid.host", [1, 3, 6, 1, 2, 1, 2, 2], timeout: 100))
    true

    # High-repetition bulk for large tables
    # SnmpKit.SnmpLib.Manager.get_bulk("192.168.1.1", "1.3.6.1.2.1.2.2", max_repetitions: 50)
    # {:ok, [...]} Returns up to 50 interface entries

# get_multi(host, oids, opts \\ [])

    @spec get_multi(host(), [oid()], manager_opts()) ::
      {:ok, [{oid(), atom(), any() | {:error, any()}}]} | {:error, any()}

Performs multiple GET operations efficiently with connection reuse.

More efficient than individual get/3 calls when retrieving multiple values from the same device by reusing the same socket connection.

## Parameters

- `host`: Target device IP address or hostname
- `oids`: List of OIDs to retrieve
- `opts`: Configuration options

## Returns

- `{:ok, results}`: List of {oid, type, value} or {oid, {:error, reason}} tuples
- `{:error, reason}`: Connection or overall operation failed

## Examples

    # Test that get_multi function exists and handles invalid input properly
    iex> oids = ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0", "1.3.6.1.2.1.1.5.0"]
    iex> match?({:error, _}, SnmpKit.SnmpLib.Manager.get_multi("invalid.host", oids, timeout: 100))
    true

# get_next(host, oid, opts \\ [])

    @spec get_next(host(), oid(), manager_opts()) ::
      {:ok, {oid(), atom(), any()}} | {:error, atom() | {atom(), any()}}

Performs an SNMP GETNEXT operation to retrieve the next value in the MIB tree.

GETNEXT is used to traverse the MIB tree by retrieving the next available object after the specified OID. This is essential for MIB walking operations and discovering available objects on SNMP devices.

## Parameters

- `host`: Target device IP address or hostname
- `oid`: Object identifier to get the next value after
- `opts`: Configuration options

## Implementation Details

- SNMP v1: Uses proper GETNEXT PDU for compatibility
- SNMP v2c+: Uses optimized GETBULK with max_repetitions=1

## Returns

- `{:ok, {next_oid, type, value}}`: Next OID and its value as a tuple
- `{:error, reason}`: Operation failed with reason

## Examples

    # Get next OID after system description
    {:ok, {next_oid, type, value}} = SnmpKit.SnmpLib.Manager.get_next("192.168.1.1", "1.3.6.1.2.1.1.1.0")

    # SNMP v1 compatibility
    {:ok, {next_oid, type, value}} = SnmpKit.SnmpLib.Manager.get_next("192.168.1.1", "1.3.6.1.2.1.1.1.0", version: :v1)

    # With custom community
    {:ok, {next_oid, type, value}} = SnmpKit.SnmpLib.Manager.get_next("192.168.1.1", "1.3.6.1.2.1.1.1.0",
                                                         community: "private", timeout: 10_000)

# interpret_error(error, arg2, version)

    @spec interpret_error(atom(), atom(), atom()) :: atom()

Interprets SNMP errors with enhanced semantics for common cases.

Provides more specific error interpretation when generic errors like `:gen_err` are returned by devices that should return more specific SNMP error codes.

## Parameters

- `error`: The original error returned by SNMP operations
- `operation`: The SNMP operation type (`:get`, `:set`, `:get_bulk`)
- `version`: SNMP version (`:v1`, `:v2c`, `:v3`)

## Returns

More specific error atom when possible, otherwise the original error.

## Examples

    # Interpret genErr for GET operations
    iex> SnmpKit.SnmpLib.Manager.interpret_error(:gen_err, :get, :v2c)
    :no_such_object

    iex> SnmpKit.SnmpLib.Manager.interpret_error(:gen_err, :get, :v1)
    :no_such_name

    iex> SnmpKit.SnmpLib.Manager.interpret_error(:too_big, :get, :v2c)
    :too_big

# ping(host, opts \\ [])

    @spec ping(host(), manager_opts()) :: {:ok, :reachable} | {:error, any()}

Checks if a host is reachable via SNMP by performing a basic GET operation.

Useful for device discovery and health checking. Attempts to retrieve sysUpTime (1.3.6.1.2.1.1.3.0) which should be available on all SNMP devices.

## Parameters

- `host`: Target device IP address or hostname
- `opts`: Configuration options (typically just community and timeout)

## Returns

- `{:ok, :reachable}`: Device responded to SNMP request
- `{:error, reason}`: Device not reachable or SNMP not available

## Examples

    # Test that ping function exists and handles invalid input properly
    iex> match?({:error, _}, SnmpKit.SnmpLib.Manager.ping("invalid.host", timeout: 100))
    true

# set(host, oid, arg, opts \\ [])

    @spec set(host(), oid(), {atom(), any()}, manager_opts()) ::
      {:ok, :success} | {:error, any()}

Performs an SNMP SET operation to modify a value on the target device.

## Parameters

- `host`: Target device IP address or hostname
- `oid`: Object identifier to modify
- `value`: New value as {type, data} tuple (e.g., {:string, "new name"})
- `opts`: Configuration options

## Supported Value Types

- `{:string, binary()}`: OCTET STRING
- `{:integer, integer()}`: INTEGER
- `{:counter32, non_neg_integer()}`: Counter32
- `{:gauge32, non_neg_integer()}`: Gauge32
- `{:timeticks, non_neg_integer()}`: TimeTicks
- `{:ip_address, binary()}`: IpAddress (4 bytes)

## Returns

- `{:ok, :success}`: SET operation completed successfully
- `{:error, reason}`: Operation failed with reason

## Examples

    # Test that SET function exists and handles invalid input properly
    iex> match?({:error, _}, SnmpKit.SnmpLib.Manager.set("invalid.host", [1, 3, 6, 1, 2, 1, 1, 5, 0], {:string, "test"}, timeout: 100))
    true