SnmpKit.SnmpLib.Manager (snmpkit v0.6.3)

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

Functions

Performs an SNMP GET operation to retrieve a single value.

Performs an SNMP GETBULK operation for efficient bulk data retrieval.

Performs multiple GET operations efficiently with connection reuse.

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

Interprets SNMP errors with enhanced semantics for common cases.

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

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