Ir al contenido

Módulo SNMP

El módulo snmp proporciona una interfaz completa para el monitoreo y la gestión de dispositivos de red a través del protocolo SNMP (Simple Network Management Protocol). Este módulo es útil para la recopilación de métricas de routers, switches, servidores, impresoras y cualquier dispositivo que soporte SNMP.

  • Soporte para SNMP v1, v2c y v3

  • Operaciones GET, GET BULK y WALK

  • Autenticación y cifrado SNMP v3

  • Configuración flexible de timeout y reintentos

  • Retorno seguro con manejo de errores

Protocolos soportados:

  • SNMP v1: Protocolo básico con comunidad pública/privada

  • SNMP v2c: Mejoras de rendimiento con operaciones BULK

  • SNMP v3: Seguridad avanzada con autenticación y cifrado

Todas las funciones SNMP requieren un objeto de configuración que define los parámetros de conexión. La configuración es una tabla Lua con los siguientes campos:

CampoTipoPadrãoDescripción
addressstringobrigatórioEndereço IP ou hostname do dispositivo
snmpVersionnúmero1Versão SNMP (1=v1, 2=v2c, 3=v3)
snmpPortnúmero161Porta SNMP
snmpCommunitystringnilComunidade SNMP (v1/v2c)
snmpTimeoutnúmero5Timeout em segundos
snmpRetryCountnúmero3Número de retentativas
snmpMaxBulkItemsnúmeronilMáximo de itens por operação BULK
snmpExponentialBackoffbooleanofalseHabilitar backoff exponencial
CampoTipoDescripción
snmpSecurityLevelstringNível de segurança: “NoAuthNoPriv”, “AuthNoPriv”, “AuthPriv”
snmpAuthProtocolstringProtocolo de autenticação: “MD5”, “SHA1”
snmpAuthUserstringUsuário de autenticação
snmpAuthPasswordstringSenha de autenticação
snmpPrivProtocolstringProtocolo de criptografia: “DES”, “AES”
snmpPrivPasswordstringSenha de criptografia

O ambiente Lua inclui uma tabela predefinida chamada params que contém os detalhes do dispositivo atual. Esta tabela puede ser usada directamente como configuración SNMP, ya que ya posee los campos necesarios en el formato esperado.

Exemplo de uso direto:

-- Usar la tabla device directamente como configuración
local sys_descr = snmp.getex(device, "1.3.6.1.2.1.1.1.0")
print("Descrição do dispositivo:", sys_descr)
-- Versión que no lanza error
local valor, erro = snmp.get_safe(device, "1.3.6.1.2.1.1.3.0")
if not erro then
print("Uptime do dispositivo:", valor)
end

Combinando com configurações adicionais:

-- Crear configuración basada en device con ajustes
local config = {
address = device.address,
snmpVersion = device.snmpVersion,
snmpCommunity = device.snmpCommunity,
snmpTimeout = device.snmpTimeout or 5, -- Usar el valor predeterminado si no está definido
snmpRetryCount = 2, -- Sobrescribir valor predeterminado
snmpMaxBulkItems = 50 -- Agregar configuración adicional
}
-- Usar para operación BULK
local oids = {"1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0"}
local resultados = snmp.get_bulk(config, oids)
-- Configuração básica SNMP v2c
local config_v2c = {
address = "192.168.1.1",
snmpVersion = 2,
snmpCommunity = "public",
snmpTimeout = 3,
snmpRetryCount = 2
}
-- Configuração SNMP v3 com autenticação e criptografia
local config_v3 = {
address = "10.0.0.254",
snmpVersion = 3,
snmpSecurityLevel = "AuthPriv",
snmpAuthProtocol = "SHA1",
snmpAuthUser = "monitor",
snmpAuthPassword = "senha123",
snmpPrivProtocol = "AES",
snmpPrivPassword = "chave456",
snmpTimeout = 5
}
-- Configuração para dispositivo com porta não padrão
local config_custom_port = {
address = "switch.piso1.local",
snmpVersion = 2,
snmpCommunity = "internal",
snmpPort = 8161, -- Puerto personalizado
snmpTimeout = 10 -- Timeout mayor para red lenta
}

Realiza una consulta SNMP GET para un OID específico.

  • config (tabela): Configuração SNMP (ver seção acima)

  • oid (string): OID a ser consultado (formato numérico ou nomeado)

  • valor: Valor retornado pelo dispositivo SNMP (número, string, etc.)
  • Lança erro se o OID não existir ou houver falha na comunicação
-- Consultar sysDescr (descripción del sistema)
local config = {
address = "192.168.1.1",
snmpVersion = 2,
snmpCommunity = "public"
}
local sys_descr = snmp.getex(config, "1.3.6.1.2.1.1.1.0")
-- o usando OID nombrado
local sys_descr = snmp.getex(config, ".1.3.6.1.2.1.1.1.0")
print("Descrição do sistema:", sys_descr)
-- Ejemplo de salida: "Cisco IOS Software, C3750 Software (C3750-IPSERVICESK9-M), Version 12.2(55)SE10, RELEASE SOFTWARE (fc2)"
-- Consultar uptime del sistema
local sys_uptime = snmp.getex(config, "1.3.6.1.2.1.1.3.0")
print("Uptime:", sys_uptime, "centésimos de segundo")
-- Consultar nombre del host
local sys_name = snmp.getex(config, "1.3.6.1.2.1.1.5.0")
print("Nome do host:", sys_name)
-- Consultar ubicación
local sys_location = snmp.getex(config, "1.3.6.1.2.1.1.6.0")
print("Localização:", sys_location)

Versión segura de getex que no lanza excepciones, retornando el error como segundo valor.

  • config (tabela): Configuração SNMP

  • oid (string): OID a ser consultado

  • tuple: (valor, erro) donde:

    • valor (qualquer tipo ou nil): Valor retornado se bem-sucedido

    • erro (string ou nil): Mensagem de error se falhar, nil se bem-sucedido

local config = {
address = "192.168.1.1",
snmpVersion = 2,
snmpCommunity = "public"
}
-- Consulta segura que no rompe el script en caso de error
local valor, erro = snmp.get_safe(config, "1.3.6.1.2.1.1.1.0")
if erro then
log.error("Falha na consulta SNMP:", erro)
-- Tomar acción alternativa
else
print("Valor obtido:", valor)
end
-- Consultar múltiplos OIDs com tratamento de erro individual
local oids = {
"1.3.6.1.2.1.1.1.0", -- sysDescr
"1.3.6.1.2.1.1.3.0", -- sysUpTime
"1.3.6.1.2.1.1.5.0", -- sysName
"1.3.6.1.2.1.1.6.0" -- sysLocation
}
local resultados = {}
for _, oid in ipairs(oids) do
local valor, erro = snmp.get_safe(config, oid)
if erro then
log.warn("Falha no OID", oid, ":", erro)
resultados[oid] = {erro = erro}
else
resultados[oid] = {valor = valor}
end
end

Realiza operación SNMP GET BULK para múltiples OIDs a la vez (SNMP v2c/v3).

  • config (tabela): Configuração SNMP (deve ser v2 ou v3)

  • oids (array de strings): Lista de OIDs para consulta

  • tabela: Mapa OID → valor para todos los OIDs consultados
  • Más eficiente que múltiples llamadas getex para muchos OIDs

  • Soportado solo en SNMP v2c y v3

  • Usa snmpMaxBulkItems de la configuración para limitar tamaño

local config = {
address = "192.168.1.1",
snmpVersion = 2, -- Deve ser v2 ou v3 para GET BULK
snmpCommunity = "public",
snmpMaxBulkItems = 50 -- Limitar a 50 OIDs por operación
}
-- Consultar múltiplas informações do sistema de uma vez
local oids = {
"1.3.6.1.2.1.1.1.0", -- sysDescr
"1.3.6.1.2.1.1.3.0", -- sysUpTime
"1.3.6.1.2.1.1.5.0", -- sysName
"1.3.6.1.2.1.1.6.0", -- sysLocation
"1.3.6.1.2.1.1.7.0" -- sysServices
}
local resultados = snmp.get_bulk(config, oids)
for oid, valor in pairs(resultados) do
print("OID:", oid, "=", valor)
end
-- Consultar información de múltiples interfaces
local function obter_info_interfaces(config, indices)
local oids = {}
for _, idx in ipairs(indices) do
table.insert(oids, "1.3.6.1.2.1.2.2.1.2." .. idx) -- ifDescr
table.insert(oids, "1.3.6.1.2.1.2.2.1.3." .. idx) -- ifType
table.insert(oids, "1.3.6.1.2.1.2.2.1.5." .. idx)
end
return snmp.get_bulk(config, oids)
end

Versión simplificada de snmp.getex que usa automáticamente la configuración del dispositivo actual (params).

  • oid (string): OID a ser consultado
  • valor: Valor retornado pelo dispositivo SNMP
  • Usa params como configuração

  • Lança erro se o OID não existir ou houver falha na comunicação

-- Consulta simplificada usando la configuración del dispositivo actual
local sys_descr = snmp.get("1.3.6.1.2.1.1.1.0")
print("Descrição do sistema:", sys_descr)
-- Consultar múltiplos OIDs
local uptime = snmp.get("1.3.6.1.2.1.1.3.0")
local hostname = snmp.get("1.3.6.1.2.1.1.5.0")
print("Uptime:", uptime, "Hostname:", hostname)

5. snmp.walk(oid, cache_ttl, enforce_ordering)

Sección titulada «5. snmp.walk(oid, cache_ttl, enforce_ordering)»

Realiza una operación SNMP WALK con soporte de caché y ordenamiento.

  • oid (string): OID base para el walk

  • cache_ttl (número, opcional): Tiempo de vida del caché en segundos

  • enforce_ordering (booleano, opcional): Forzar ordenación de los resultados (orden natural)

  • Usa caché cuando cache_ttl es especificado
-- Walk con caché de 30 segundos
local interfaces = snmp.walk("1.3.6.1.2.1.2.2.1.2", 30)
for oid, ifname in pairs(interfaces) do
print("Interface", oid, ":", ifname)
end
-- Walk con ordenación forzada (sin caché)
local ordered_interfaces = snmp.walk("1.3.6.1.2.1.2.2.1.2", nil, true)
print("Total de interfaces:", #ordered_interfaces)

El parámetro enforce_ordering controla cómo se estructuran los resultados:

  • Cuando false (padrão): Los resultados se retornan como una tabla Lua donde cada OID es una clave que mapea a su valor. Esta estructura es eficiente para acceso aleatorio, pero pierde la ordenación natural de los OIDs, ya que las tablas Lua no preservan el orden de inserción de las claves.

  • Cuando true: Los resultados se retornan como una lista de pares (tabla de tablas), donde cada elemento es una tabla conteniendo 2 elementos. Esta estructura preserva el orden natural de los OIDs tal como son retornados por el dispositivo SNMP.

Exemplo de diferença:

-- Com enforce_ordering = false (padrão)
local resultado_tabela = snmp.walk("1.3.6.1.2.1.2.2.1.2", nil, false)
-- Estrutura: { ["1.3.6.1.2.1.2.2.1.2.1"] = "eth0", ["1.3.6.1.2.1.2.2.1.2.2"] = "eth1" }
-- A ordem das chaves não é garantida
-- Com enforce_ordering = true
local resultado_lista = snmp.walk("1.3.6.1.2.1.2.2.1.2", nil, true)
-- Estrutura: { {"1.3.6.1.2.1.2.2.1.2.1", "eth0"},
-- {"1.3.6.1.2.1.2.2.1.2.2", "eth1"} }
-- A ordem dos elementos é preservada

Quando usar cada modo:

  • Use enforce_ordering = false cuando solo necesita acceder valores por OID específico y el orden no importa.

  • Use enforce_ordering = true cuando necesita procesar los resultados en el mismo orden en que fueron retornados por el dispositivo, como para:

    • Generar reportes ordenados

    • Procesar secuencias de índices consecutivos

    • Mantener correspondencia con otras listas ordenadas

  • tabela: Mapa OID → valor para todos os OIDs encontrados

Función extendida de walk con sistema de caché avanzado y prevención de ejecuciones concurrentes.

  • device (tabela): Configuração do dispositivo

  • oid (string): OID base para el walk

  • cache_ttl (número, opcional): Tiempo de vida del caché en segundos

  • tabela: Mapa OID → valor para todos los OIDs encontrados
  • Implementa caché global compartido entre ejecuciones

  • Previene ejecuciones concurrentes del mismo walk

  • Usa registry para coordinar ejecuciones simultáneas

-- Walk extendido con caché de 60 segundos
local device_config = {
address = "192.168.1.1",
snmpVersion = 2,
snmpCommunity = "public"
}
local sys_oids = snmp.walkex(device_config, "1.3.6.1.2.1.1", 60)
for oid, value in pairs(sys_oids) do
print("OID:", oid, "Valor:", value)
end

Cuenta el número de ítems retornados por un walk.

  • oid (string): OID base para contar
  • número: Cantidad de ítems encontrados
-- Contar número de interfaces
local num_interfaces = snmp.count("1.3.6.1.2.1.2.2.1.2")
print("Número de interfaces:", num_interfaces)
-- Contar número de procesos
local num_processes = snmp.count("1.3.6.1.2.1.25.4.2.1.2")
print("Número de processos:", num_processes)

Calcula la diferencia entre dos valores, manejando rollover de contadores.

  • typ (número): Tipo do contador (32 ou 64 bits)

  • lhs (número): Valor atual

  • rhs (número): Valor anterior

  • número: Diferença entre os valores
  • Trata rollover de contadores de 32 y 64 bits

  • Señala RepeatPrevValue si la diferencia es negativa

-- Calcular diferencia para contador de 32 bits
local current_bytes = snmp.get("1.3.6.1.2.1.2.2.1.10.1") -- ifInOctets.1
local prev_bytes = prev("1.3.6.1.2.1.2.2.1.10.1")
local bytes_diff = snmp.diff(32, current_bytes, prev_bytes)
print("Bytes recebidos desde última leitura:", bytes_diff)

Resuelve dinámicamente OIDs de instancias basado en el nombre de la instancia.

  • oid (string): OID base (sin índice de instancia)
  • string: OID completo con índice de instancia
  • Usa params.InstanceName e params.snmpOIDDesc para resolución

  • Soporta caché de instancias

  • Lança erro se a instância não for encontrada

-- Resolver OID para instância específica
-- params.InstanceName = "eth0"
-- params.snmpOIDDesc = "1.3.6.1.2.1.2.2.1.2" -- ifDescr
local if_in_octets_oid = inst("1.3.6.1.2.1.2.2.1.10") -- ifInOctets
print("OID resolvido:", if_in_octets_oid)
-- Saída: "1.3.6.1.2.1.2.2.1.10.1" (se eth0 for índice 1)
-- Consultar usando OID resolvido
local bytes_in = snmp.get(if_in_octets_oid)
print("Bytes recebidos na interface eth0:", bytes_in)

Obtiene el valor anterior de un OID almacenado.

  • oid (string): OID para obtener valor anterior
  • qualquer tipo: Valor anterior almacenado, o 0 se no existir
  • Busca valor en store.get("snmp.value." .. oid)

  • Retorna 0 si no encuentra valor almacenado

-- Obtener valor anterior para cálculo de tasa
local current_value = snmp.get("1.3.6.1.2.1.2.2.1.16.1") -- ifOutOctets.1
local previous_value = prev("1.3.6.1.2.1.2.2.1.16.1")
local bytes_out_diff = current_value - previous_value
print("Bytes enviados desde última leitura:", bytes_out_diff)

Obtiene el tiempo transcurrido desde la última lectura de un OID.

  • oid (string): OID para verificar tiempo transcurrido
  • número: Tiempo en segundos desde la última lectura, o 1 si no hay registro
-- Calcular tasa por segundo
local current_counter = snmp.get("1.3.6.1.2.1.2.2.1.10.1") -- ifInOctets.1
local previous_counter = prev("1.3.6.1.2.1.2.2.1.10.1")
local time_elapsed = lapsed("1.3.6.1.2.1.2.2.1.10.1")
local bytes_per_second = (current_counter - previous_counter) / time_elapsed
print("Taxa de recebimento:", bytes_per_second, "bytes/segundo")
-- Resolver OID da interface eth0
local if_index_oid = inst("1.3.6.1.2.1.2.2.1.1") -- ifIndex
local if_descr_oid = inst("1.3.6.1.2.1.2.2.1.2") -- ifDescr
-- Obtener información de la interfaz
local interface_index = snmp.get(if_index_oid)
local interface_name = snmp.get(if_descr_oid)
print("Monitorando interface:", interface_name, "(índice", interface_index, ")")
-- Recopilar estadísticas
local in_octets = snmp.get(inst("1.3.6.1.2.1.2.2.1.10")) -- ifInOctets
local out_octets = snmp.get(inst("1.3.6.1.2.1.2.2.1.16")) -- ifOutOctets
local in_errors = snmp.get(inst("1.3.6.1.2.1.2.2.1.14")) -- ifInErrors
local out_errors = snmp.get(inst("1.3.6.1.2.1.2.2.1.20")) -- ifOutErrors
-- Calcular diferencias desde la última lectura
local time_elapsed = lapsed(inst("1.3.6.1.2.1.2.2.1.10"))
local prev_in = prev(inst("1.3.6.1.2.1.2.2.1.10"))
local prev_out = prev(inst("1.3.6.1.2.1.2.2.1.16"))
local in_rate = (in_octets - prev_in) / time_elapsed
local out_rate = (out_octets - prev_out) / time_elapsed
print("Taxa de entrada:", in_rate, "bytes/seg")
print("Taxa de saída:", out_rate, "bytes/seg")
print("Erros de entrada:", in_errors)
print("Erros de saída:", out_errors)
-- Listar todas las interfaces con walk
local interfaces = snmp.walk("1.3.6.1.2.1.2.2.1.2", 300) -- ifDescr com cache de 5 minutos
print("=== Inventário de Interfaces ===")
for oid, ifname in pairs(interfaces) do
-- Extraer índice de la interfaz del OID
local index = string.match(oid, "(%d+)$")
-- Obtener tipo y estado de la interfaz
local iftype = snmp.get("1.3.6.1.2.1.2.2.1.3." .. index) -- ifType
local ifstatus = snmp.get("1.3.6.1.2.1.2.2.1.8." .. index) -- ifOperStatus
local status_text = "DOWN"
if ifstatus == 1 then status_text = "UP" end
print(string.format("Interface %s: %s (Tipo: %d, Status: %s)",
index, ifname, iftype, status_text))
end
print("Total de interfaces:", snmp.count("1.3.6.1.2.1.2.2.1.2"))

Monitoramento de Uso de CPU com Múltiplas Instâncias:

Sección titulada «Monitoramento de Uso de CPU com Múltiplas Instâncias:»
-- Usar walk para obter todas as CPUs
local cpu_oids = snmp.walk("1.3.6.1.2.1.25.3.3.1.2", 30) -- hrProcessorLoad
local total_load = 0
local cpu_count = 0
for oid, load in pairs(cpu_oids) do
cpu_count = cpu_count + 1
total_load = total_load + load
local cpu_index = string.match(oid, "(%d+)$")
print(string.format("CPU %d: %d%%", cpu_index, load))
end
if cpu_count > 0 then
local avg_load = total_load / cpu_count
print(string.format("Média de uso de CPU: %.1f%%", avg_load))
end