SnmpKit.SnmpLib.Types (snmpkit v2.0.1)

SNMP data type validation, formatting, and coercion utilities.

Provides comprehensive support for all SNMP data types including validation, formatting for display, and type coercion between different representations. Includes full support for SNMPv2c exception values.

Supported SNMP Types

  • Basic Types: INTEGER, OCTET STRING, NULL, OBJECT IDENTIFIER
  • Application Types: Counter32, Gauge32, TimeTicks, Counter64, IpAddress, Opaque
  • SNMPv2c Exception Types: NoSuchObject, NoSuchInstance, EndOfMibView
  • Constructed Types: SEQUENCE (for complex structures)

SNMPv2c Exception Values

These special values are used in SNMPv2c responses to indicate specific conditions:

  • :no_such_object (0x80): The requested object does not exist in the MIB
  • :no_such_instance (0x81): The object exists but the specific instance does not
  • :end_of_mib_view (0x82): End of MIB tree reached during GETBULK/walk operations

Features

  • Type validation with detailed error reporting
  • Human-readable formatting for logging and display
  • Type coercion and normalization
  • Range checking and constraint validation
  • Performance-optimized operations
  • RFC-compliant exception value handling

Examples

# Basic type validation
iex> SnmpKit.SnmpLib.Types.validate_counter32(42)
:ok
iex> SnmpKit.SnmpLib.Types.validate_counter32(-1)
{:error, :out_of_range}

# Formatting for display
iex> SnmpKit.SnmpLib.Types.format_timeticks_uptime(4200)
"42 seconds"
iex> SnmpKit.SnmpLib.Types.format_ip_address(<<192, 168, 1, 1>>)
"192.168.1.1"

# Type coercion
iex> SnmpKit.SnmpLib.Types.coerce_value(:counter32, 42)
{:ok, {:counter32, 42}}
iex> SnmpKit.SnmpLib.Types.coerce_value(:string, "test")
{:ok, {:string, "test"}}

# SNMPv2c exception values
iex> SnmpKit.SnmpLib.Types.coerce_value(:no_such_object, nil)
{:ok, {:no_such_object, nil}}
iex> SnmpKit.SnmpLib.Types.coerce_value(:end_of_mib_view, nil)
{:ok, {:end_of_mib_view, nil}}

Summary

Functions

Coerces a value to the specified SNMP type.

Decodes an SNMP typed value back to a native Elixir value.

Encodes a value with automatic type inference or explicit type specification.

True for a varbind that ends a walk: one carrying an SNMPv2 exception (noSuchObject, noSuchInstance, endOfMibView) in its type or value slot.

Formats Counter64 value with appropriate units.

True when oid (list or dotted string) lies under root.

Automatically infers the SNMP type from an Elixir value.

Checks if a type is a binary SNMP type.

Checks if a type is an exception SNMP type.

Checks if a type is a numeric SNMP type.

Returns the maximum value for a numeric SNMP type.

Returns the minimum value for a numeric SNMP type.

Normalizes a type identifier to a consistent format.

Splits a GETNEXT/GETBULK response into the leading varbinds a walk keeps and whether the walk is finished.

Validates a Counter32 value.

Validates a Counter64 value.

Validates a Gauge32 value.

Validates an Unsigned32 value.

Types

snmp_type()

@type snmp_type() ::
  :integer
  | :string
  | :null
  | :oid
  | :counter32
  | :gauge32
  | :timeticks
  | :counter64
  | :ip_address
  | :opaque
  | :no_such_object
  | :no_such_instance
  | :end_of_mib_view
  | :unsigned32
  | :octet_string
  | :object_identifier
  | :boolean

snmp_value()

@type snmp_value() ::
  integer()
  | binary()
  | :null
  | [non_neg_integer()]
  | {:counter32, non_neg_integer()}
  | {:gauge32, non_neg_integer()}
  | {:timeticks, non_neg_integer()}
  | {:counter64, non_neg_integer()}
  | {:ip_address, binary()}
  | {:opaque, binary()}
  | {:unsigned32, non_neg_integer()}
  | {:no_such_object, nil}
  | {:no_such_instance, nil}
  | {:end_of_mib_view, nil}
  | {:string, binary()}
  | {:octet_string, binary()}
  | {:object_identifier, [non_neg_integer()]}
  | {:boolean, boolean()}

Functions

coerce_value(arg1, value)

@spec coerce_value(snmp_type(), term()) :: {:ok, snmp_value()} | {:error, atom()}

Coerces a value to the specified SNMP type.

Parameters

  • type: Target SNMP type
  • raw_value: Value to coerce

Returns

  • {:ok, typed_value} on success
  • {:error, reason} on failure

Examples

{:ok, {:counter32, 42}} = SnmpKit.SnmpLib.Types.coerce_value(:counter32, 42)
{:ok, {:string, "test"}} = SnmpKit.SnmpLib.Types.coerce_value(:string, "test")
{:ok, {:ip_address, <<192, 168, 1, 1>>}} = SnmpKit.SnmpLib.Types.coerce_value(:ip_address, {192, 168, 1, 1})

decode_value(value)

@spec decode_value({snmp_type(), term()} | term()) :: term()

Decodes an SNMP typed value back to a native Elixir value.

Converts SNMP-encoded values back to their most natural Elixir representation, with consistent handling of strings (always returns binaries, not charlists).

Parameters

  • typed_value: A tuple of {type, value} or just a value

Returns

The decoded Elixir value in its most natural form

Examples

"hello" = SnmpKit.SnmpLib.Types.decode_value({:string, "hello"})
"192.168.1.1" = SnmpKit.SnmpLib.Types.decode_value({:ip_address, {192, 168, 1, 1}})
42 = SnmpKit.SnmpLib.Types.decode_value({:counter32, 42})
[1, 3, 6, 1] = SnmpKit.SnmpLib.Types.decode_value({:object_identifier, [1, 3, 6, 1]})

encode_value(value, opts \\ [])

@spec encode_value(
  term(),
  keyword()
) :: {:ok, {snmp_type(), term()}} | {:error, atom()}

Encodes a value with automatic type inference or explicit type specification.

This is the main entry point for encoding values into SNMP types. It supports both automatic type inference based on the value and explicit type specification.

Parameters

  • value: The value to encode
  • opts: Options including:
    • :type - Explicit type specification (overrides inference)
    • :validate - Whether to validate the encoded value (default: true)

Returns

  • {:ok, {type, encoded_value}} on success
  • {:error, reason} on failure

Examples

# Automatic type inference
{:ok, {:string, "hello"}} = SnmpKit.SnmpLib.Types.encode_value("hello")
{:ok, {:integer, 42}} = SnmpKit.SnmpLib.Types.encode_value(42)

# Explicit type specification
{:ok, {:ip_address, {192, 168, 1, 1}}} = SnmpKit.SnmpLib.Types.encode_value("192.168.1.1", type: :ip_address)
{:ok, {:counter32, 100}} = SnmpKit.SnmpLib.Types.encode_value(100, type: :counter32)

end_of_mib?(arg1)

@spec end_of_mib?(term()) :: boolean()

True for a varbind that ends a walk: one carrying an SNMPv2 exception (noSuchObject, noSuchInstance, endOfMibView) in its type or value slot.

The decoder emits exceptions as {oid, :end_of_mib_view, nil}; the value forms :end_of_mib_view and {:end_of_mib_view, nil} are accepted too.

Examples

true = SnmpKit.SnmpLib.Types.end_of_mib?({[1, 3, 6], :end_of_mib_view, nil})
true = SnmpKit.SnmpLib.Types.end_of_mib?({[1, 3, 6], :no_such_instance, nil})
false = SnmpKit.SnmpLib.Types.end_of_mib?({[1, 3, 6], :integer, 1})

format_bytes(a1)

See SnmpKit.SnmpLib.Types.Format.format_bytes/1.

format_counter64(value)

@spec format_counter64(non_neg_integer()) :: binary()

Formats Counter64 value with appropriate units.

Examples

"42" = SnmpKit.SnmpLib.Types.format_counter64(42)
"18,446,744,073,709,551,615" = SnmpKit.SnmpLib.Types.format_counter64(18446744073709551615)

format_hex(a1)

See SnmpKit.SnmpLib.Types.Format.format_hex/1.

format_ip_address(a1)

See SnmpKit.SnmpLib.Types.Format.format_ip_address/1.

format_rate(a1, a2)

See SnmpKit.SnmpLib.Types.Format.format_rate/2.

format_timeticks_uptime(a1)

See SnmpKit.SnmpLib.Types.Format.format_timeticks_uptime/1.

in_scope?(oid, root)

@spec in_scope?(term(), [non_neg_integer()]) :: boolean()

True when oid (list or dotted string) lies under root.

Examples

true = SnmpKit.SnmpLib.Types.in_scope?([1, 3, 6, 1, 2, 1, 1, 1, 0], [1, 3, 6, 1, 2, 1, 1])
true = SnmpKit.SnmpLib.Types.in_scope?("1.3.6.1.2.1.1.1.0", [1, 3, 6, 1, 2, 1, 1])
false = SnmpKit.SnmpLib.Types.in_scope?([1, 3, 6, 1, 2, 1, 2], [1, 3, 6, 1, 2, 1, 1])

infer_type(value)

@spec infer_type(term()) :: snmp_type()

Automatically infers the SNMP type from an Elixir value.

Uses intelligent heuristics to determine the most appropriate SNMP type for a given Elixir value.

Examples

:string = SnmpKit.SnmpLib.Types.infer_type("hello")
:integer = SnmpKit.SnmpLib.Types.infer_type(42)
:ip_address = SnmpKit.SnmpLib.Types.infer_type("192.168.1.1")
:object_identifier = SnmpKit.SnmpLib.Types.infer_type([1, 3, 6, 1, 2, 1])
:boolean = SnmpKit.SnmpLib.Types.infer_type(true)

is_binary_type?(type)

@spec is_binary_type?(snmp_type()) :: boolean()

Checks if a type is a binary SNMP type.

Examples

true = SnmpKit.SnmpLib.Types.is_binary_type?(:string)
true = SnmpKit.SnmpLib.Types.is_binary_type?(:opaque)
false = SnmpKit.SnmpLib.Types.is_binary_type?(:integer)

is_exception_type?(type)

@spec is_exception_type?(snmp_type()) :: boolean()

Checks if a type is an exception SNMP type.

Examples

true = SnmpKit.SnmpLib.Types.is_exception_type?(:no_such_object)
false = SnmpKit.SnmpLib.Types.is_exception_type?(:integer)

is_numeric_type?(type)

@spec is_numeric_type?(snmp_type()) :: boolean()

Checks if a type is a numeric SNMP type.

Examples

true = SnmpKit.SnmpLib.Types.is_numeric_type?(:counter32)
true = SnmpKit.SnmpLib.Types.is_numeric_type?(:integer)
false = SnmpKit.SnmpLib.Types.is_numeric_type?(:string)

max_value(arg1)

@spec max_value(snmp_type()) :: non_neg_integer() | nil

Returns the maximum value for a numeric SNMP type.

Examples

4294967295 = SnmpKit.SnmpLib.Types.max_value(:counter32)
2147483647 = SnmpKit.SnmpLib.Types.max_value(:integer)

min_value(type)

@spec min_value(snmp_type()) :: integer() | nil

Returns the minimum value for a numeric SNMP type.

Examples

-2147483648 = SnmpKit.SnmpLib.Types.min_value(:integer)
0 = SnmpKit.SnmpLib.Types.min_value(:counter32)

normalize_type(type)

@spec normalize_type(term()) :: snmp_type() | :unknown

Normalizes a type identifier to a consistent format.

Examples

:counter32 = SnmpKit.SnmpLib.Types.normalize_type("counter32")
:integer = SnmpKit.SnmpLib.Types.normalize_type(:integer)
:string = SnmpKit.SnmpLib.Types.normalize_type("octet_string")

parse_hex_string(a1)

See SnmpKit.SnmpLib.Types.Format.parse_hex_string/1.

parse_ip_address(a1)

See SnmpKit.SnmpLib.Types.Format.parse_ip_address/1.

take_in_scope(varbinds, root)

@spec take_in_scope([term()], [non_neg_integer()]) :: {[tuple()], boolean()}

Splits a GETNEXT/GETBULK response into the leading varbinds a walk keeps and whether the walk is finished.

Keeps {oid, type, value} varbinds up to the first exception (end_of_mib?/1) or the first OID outside root; everything from that point on is dropped. done? is true when something was cut, so the caller knows not to ask for more. Every walk stack (SnmpKit.SnmpLib.Walker, SnmpKit.SnmpMgr.V2Walk, SnmpKit.SnmpMgr.Bulk, SnmpKit.SnmpMgr.AdaptiveWalk) terminates on this one rule.

Examples

{[{[1, 3, 6, 1, 1], :integer, 1}], true} =
  SnmpKit.SnmpLib.Types.take_in_scope(
    [{[1, 3, 6, 1, 1], :integer, 1}, {[1, 3, 6, 1, 2], :end_of_mib_view, nil}],
    [1, 3, 6, 1]
  )

truncate_string(a1, a2)

See SnmpKit.SnmpLib.Types.Format.truncate_string/2.

validate_counter32(value)

@spec validate_counter32(term()) :: :ok | {:error, atom()}

Validates a Counter32 value.

Counter32 is a 32-bit unsigned integer that wraps around when it reaches its maximum value.

Parameters

  • value: Value to validate

Returns

  • :ok if valid
  • {:error, reason} if invalid

Examples

:ok = SnmpKit.SnmpLib.Types.validate_counter32(42)
:ok = SnmpKit.SnmpLib.Types.validate_counter32(4294967295)
{:error, :out_of_range} = SnmpKit.SnmpLib.Types.validate_counter32(-1)
{:error, :not_integer} = SnmpKit.SnmpLib.Types.validate_counter32("42")

validate_counter64(value)

@spec validate_counter64(term()) :: :ok | {:error, atom()}

Validates a Counter64 value.

Counter64 is a 64-bit unsigned integer for high-speed interfaces.

validate_gauge32(value)

@spec validate_gauge32(term()) :: :ok | {:error, atom()}

Validates a Gauge32 value.

Gauge32 is a 32-bit unsigned integer that represents a non-negative integer value. Unlike Counter32, it does not wrap around.

validate_integer(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_integer/1.

validate_ip_address(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_ip_address/1.

validate_octet_string(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_octet_string/1.

validate_oid(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_oid/1.

validate_opaque(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_opaque/1.

validate_timeticks(a1)

See SnmpKit.SnmpLib.Types.Validation.validate_timeticks/1.

validate_unsigned32(value)

@spec validate_unsigned32(term()) :: :ok | {:error, atom()}

Validates an Unsigned32 value.

Unsigned32 is a 32-bit unsigned integer.