MIB Guide - SnmpKit
This guide covers working with Management Information Bases (MIBs) in SnmpKit, including OID resolution, MIB compilation, and custom MIB integration.
Table of Contents
- Overview
- Basic MIB Operations
- OID Resolution
- MIB Compilation
- Standard MIBs
- Custom MIBs
- Tree Navigation
- Advanced Features
- Troubleshooting
Overview
Management Information Bases (MIBs) define the structure of manageable objects in SNMP. SnmpKit provides comprehensive MIB support through the SnmpKit.MIB
module, allowing you to:
- Resolve OID names to numeric identifiers
- Perform reverse lookups from OIDs to names
- Compile and load custom MIBs
- Navigate the MIB tree structure
- Query object definitions and metadata
Basic MIB Operations
OID Name Resolution
Convert human-readable names to numeric OIDs:
# Simple name resolution
{:ok, oid} = SnmpKit.MIB.resolve("sysDescr.0")
# Returns: [1, 3, 6, 1, 2, 1, 1, 1, 0]
# Multiple resolutions
names = ["sysDescr.0", "sysUpTime.0", "sysName.0"]
{:ok, oids} = SnmpKit.MIB.resolve_many(names)
# Partial name resolution
{:ok, oid} = SnmpKit.MIB.resolve("system.sysDescr.0")
{:ok, oid} = SnmpKit.MIB.resolve("1.3.6.1.2.1.1.1.0")
Reverse OID Lookup
Convert numeric OIDs back to readable names:
# Basic reverse lookup
{:ok, name} = SnmpKit.MIB.reverse_lookup([1, 3, 6, 1, 2, 1, 1, 1, 0])
# Returns: "sysDescr.0"
# Multiple reverse lookups
oids = [[1, 3, 6, 1, 2, 1, 1, 1, 0], [1, 3, 6, 1, 2, 1, 1, 3, 0]]
{:ok, names} = SnmpKit.MIB.reverse_lookup_many(oids)
# Get the longest matching name
{:ok, partial_name} = SnmpKit.MIB.reverse_lookup([1, 3, 6, 1, 2, 1, 1, 1, 5])
# Returns closest match even if exact OID doesn't exist
OID Resolution
Working with Different OID Formats
SnmpKit supports multiple OID input formats:
# String format
{:ok, oid} = SnmpKit.MIB.resolve("sysDescr.0")
# Dotted decimal string
{:ok, oid} = SnmpKit.MIB.resolve("1.3.6.1.2.1.1.1.0")
# Mixed format
{:ok, oid} = SnmpKit.MIB.resolve("iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0")
# List format (already resolved)
{:ok, oid} = SnmpKit.MIB.resolve([1, 3, 6, 1, 2, 1, 1, 1, 0])
Common System OIDs
# System group OIDs
system_oids = %{
"sysDescr.0" => [1, 3, 6, 1, 2, 1, 1, 1, 0],
"sysObjectID.0" => [1, 3, 6, 1, 2, 1, 1, 2, 0],
"sysUpTime.0" => [1, 3, 6, 1, 2, 1, 1, 3, 0],
"sysContact.0" => [1, 3, 6, 1, 2, 1, 1, 4, 0],
"sysName.0" => [1, 3, 6, 1, 2, 1, 1, 5, 0],
"sysLocation.0" => [1, 3, 6, 1, 2, 1, 1, 6, 0],
"sysServices.0" => [1, 3, 6, 1, 2, 1, 1, 7, 0]
}
# Verify all resolve correctly
for {name, expected_oid} <- system_oids do
{:ok, ^expected_oid} = SnmpKit.MIB.resolve(name)
end
MIB Compilation
Loading Standard MIBs
SnmpKit comes with standard MIBs pre-compiled:
# Standard MIBs are loaded automatically
{:ok, oid} = SnmpKit.MIB.resolve("sysDescr.0") # Works immediately
# Check what MIBs are loaded
{:ok, loaded_mibs} = SnmpKit.MIB.list_loaded()
IO.inspect(loaded_mibs)
# Reload standard MIBs if needed
{:ok, _} = SnmpKit.MIB.reload_standard()
Compiling Custom MIBs
High-Level Compilation
For most use cases, use the high-level compilation API:
# Compile a single MIB file
{:ok, compiled} = SnmpKit.MIB.compile("path/to/MY-CUSTOM-MIB.mib")
{:ok, _} = SnmpKit.MIB.load(compiled)
# Compile multiple MIBs with dependencies
mib_files = [
"CISCO-SMI.mib",
"CISCO-TC.mib",
"CISCO-CABLE-MODEM-MIB.mib"
]
{:ok, compiled_mibs} = SnmpKit.MIB.compile_many(mib_files)
{:ok, _} = SnmpKit.MIB.load_many(compiled_mibs)
Low-Level Compilation
For advanced control over the compilation process:
# Use the low-level compiler directly
alias SnmpKit.MibCompiler
# Configure compilation options
options = [
output_dir: "priv/compiled_mibs",
include_dirs: ["priv/mibs", "/usr/share/snmp/mibs"],
warnings_as_errors: false,
verbose: true
]
# Compile with options
{:ok, result} = MibCompiler.compile_file("MY-MIB.mib", options)
# Handle compilation errors
case MibCompiler.compile_file("BROKEN-MIB.mib", options) do
{:ok, result} ->
IO.puts("Compilation successful")
{:error, {:compilation_failed, errors}} ->
IO.puts("Compilation failed:")
for error <- errors, do: IO.puts(" #{error}")
end
Standard MIBs
Commonly Used Standard MIBs
# RFC1213-MIB (MIB-II) - Basic system information
{:ok, _} = SnmpKit.MIB.resolve("sysDescr.0")
{:ok, _} = SnmpKit.MIB.resolve("ifTable")
{:ok, _} = SnmpKit.MIB.resolve("ipAddrTable")
# IF-MIB - Interface information
{:ok, _} = SnmpKit.MIB.resolve("ifXTable")
{:ok, _} = SnmpKit.MIB.resolve("ifHCInOctets.1")
# HOST-RESOURCES-MIB - System resources
{:ok, _} = SnmpKit.MIB.resolve("hrSystemUptime.0")
{:ok, _} = SnmpKit.MIB.resolve("hrMemorySize.0")
# SNMPv2-MIB - SNMP statistics
{:ok, _} = SnmpKit.MIB.resolve("snmpInPkts.0")
{:ok, _} = SnmpKit.MIB.resolve("snmpOutPkts.0")
Loading Additional Standard MIBs
# Load specific standard MIBs
standard_mibs = [
"BRIDGE-MIB",
"ENTITY-MIB",
"DISMAN-EVENT-MIB",
"NOTIFICATION-LOG-MIB"
]
for mib <- standard_mibs do
case SnmpKit.MIB.load_standard(mib) do
{:ok, _} -> IO.puts("Loaded #{mib}")
{:error, reason} -> IO.puts("Failed to load #{mib}: #{reason}")
end
end
Custom MIBs
Enterprise MIBs
Many vendors provide their own MIBs for device-specific objects:
# Cisco MIBs
cisco_mibs = [
"CISCO-SMI.mib",
"CISCO-TC.mib",
"CISCO-CABLE-MODEM-MIB.mib",
"CISCO-DOCS-EXT-MIB.mib"
]
# Load Cisco MIBs in dependency order
{:ok, _} = SnmpKit.MIB.compile_and_load_many(cisco_mibs)
# Now Cisco-specific OIDs work
{:ok, oid} = SnmpKit.MIB.resolve("cdxCmtsCmStatusValue")
DOCSIS MIBs
For cable modem and CMTS management:
# DOCSIS MIBs
docsis_mibs = [
"DOCS-CABLE-DEVICE-MIB.mib",
"DOCS-IF-MIB.mib",
"DOCS-QOS-MIB.mib",
"DOCS-SUBMGT-MIB.mib"
]
{:ok, _} = SnmpKit.MIB.compile_and_load_many(docsis_mibs)
# DOCSIS-specific operations
{:ok, status} = SnmpKit.SNMP.get("10.1.1.100", "docsIfCmStatusValue.1")
{:ok, signal} = SnmpKit.SNMP.get("10.1.1.100", "docsIfSigQSignalNoise.1")
Creating Custom MIB Definitions
# Define custom objects programmatically
custom_objects = [
%{
name: "myCustomObject",
oid: [1, 3, 6, 1, 4, 1, 12345, 1, 1, 1],
syntax: :integer,
access: :read_only,
description: "My custom SNMP object"
}
]
{:ok, _} = SnmpKit.MIB.define_objects(custom_objects)
# Now the custom object can be resolved
{:ok, oid} = SnmpKit.MIB.resolve("myCustomObject.0")
Tree Navigation
Exploring the MIB Tree
# Get children of a node
{:ok, children} = SnmpKit.MIB.children([1, 3, 6, 1, 2, 1, 1])
# Returns list of child OIDs under system group
# Get parent of a node
{:ok, parent} = SnmpKit.MIB.parent([1, 3, 6, 1, 2, 1, 1, 1, 0])
# Returns: [1, 3, 6, 1, 2, 1, 1, 1]
# Get siblings
{:ok, siblings} = SnmpKit.MIB.siblings([1, 3, 6, 1, 2, 1, 1, 1, 0])
# Walk the tree from a starting point
{:ok, tree} = SnmpKit.MIB.walk_tree([1, 3, 6, 1, 2, 1, 1])
Querying Object Information
# Get detailed object information
{:ok, info} = SnmpKit.MIB.object_info("sysDescr.0")
# Returns: %{name: "sysDescr", oid: [...], syntax: :octet_string, ...}
# Check if an OID exists
true = SnmpKit.MIB.exists?("sysDescr.0")
false = SnmpKit.MIB.exists?("nonExistentObject.0")
# Get object syntax information
{:ok, syntax} = SnmpKit.MIB.get_syntax("sysDescr.0")
# Returns: :octet_string
# Get access level
{:ok, access} = SnmpKit.MIB.get_access("sysDescr.0")
# Returns: :read_only
Advanced Features
MIB Validation
# Validate MIB files before compilation
case SnmpKit.MIB.validate("MY-MIB.mib") do
{:ok, _} -> IO.puts("MIB is valid")
{:error, {:validation_failed, errors}} ->
IO.puts("MIB validation failed:")
for error <- errors, do: IO.puts(" #{error}")
end
# Validate loaded MIB consistency
{:ok, report} = SnmpKit.MIB.validate_loaded()
if report.inconsistencies != [] do
IO.puts "Found inconsistencies:"
for issue <- report.inconsistencies, do: IO.puts(" #{issue}")
end
MIB Caching and Performance
# Enable aggressive caching for better performance
SnmpKit.MIB.configure_cache(
size: 10_000,
ttl: :infinity,
strategy: :lru
)
# Preload commonly used OIDs
common_oids = [
"sysDescr.0", "sysUpTime.0", "sysName.0",
"ifInOctets", "ifOutOctets", "ifOperStatus"
]
{:ok, _} = SnmpKit.MIB.preload(common_oids)
# Get cache statistics
{:ok, stats} = SnmpKit.MIB.cache_stats()
IO.inspect(stats)
Bulk OID Operations
# Resolve many OIDs efficiently
oids_to_resolve = [
"sysDescr.0", "sysUpTime.0", "sysName.0",
"ifInOctets.1", "ifOutOctets.1", "ifOperStatus.1"
]
{:ok, resolved} = SnmpKit.MIB.resolve_many(oids_to_resolve)
# Reverse lookup many OIDs
numeric_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]
]
{:ok, names} = SnmpKit.MIB.reverse_lookup_many(numeric_oids)
Troubleshooting
Common Issues
MIB Compilation Failures
# Debug compilation issues
case SnmpKit.MIB.compile("problematic.mib", debug: true) do
{:error, {:compilation_failed, errors}} ->
IO.puts("Compilation errors:")
for {line, message} <- errors do
IO.puts("Line #{line}: #{message}")
end
{:error, {:missing_dependencies, deps}} ->
IO.puts("Missing dependencies: #{Enum.join(deps, ", ")}")
IO.puts("Load these MIBs first")
end
OID Resolution Problems
# Debug OID resolution
case SnmpKit.MIB.resolve("unknownOid.0") do
{:error, :not_found} ->
# Try partial matches
case SnmpKit.MIB.search("unknownOid") do
{:ok, matches} ->
IO.puts("Did you mean one of these?")
for match <- matches, do: IO.puts(" #{match}")
{:error, :no_matches} ->
IO.puts("No similar OIDs found")
end
end
Performance Issues
# Profile MIB operations
{time, {:ok, result}} = :timer.tc(fn ->
SnmpKit.MIB.resolve("complexOid.withManyParts.0")
end)
IO.puts("Resolution took #{time}μs")
# Enable verbose logging for debugging
Logger.configure(level: :debug)
SnmpKit.MIB.resolve("sysDescr.0") # Will show detailed logs
Best Practices
- Load MIBs in dependency order - Load base MIBs before dependent ones
- Use preloading - Preload commonly used OIDs for better performance
- Cache aggressively - Enable caching for production deployments
- Validate before loading - Always validate MIBs before compilation
- Handle errors gracefully - Always pattern match on MIB operation results
- Use bulk operations - Resolve multiple OIDs at once when possible
Getting Help
# Get help on available MIB functions
h SnmpKit.MIB
# List all loaded MIBs
{:ok, mibs} = SnmpKit.MIB.list_loaded()
IO.inspect(mibs)
# Get detailed system information
{:ok, info} = SnmpKit.MIB.system_info()
IO.inspect(info)
For more examples and advanced usage, see the API documentation.