Módulo SNMP
O módulo snmp fornece uma interface completa para monitoramento e gerenciamento de dispositivos de rede através do protocolo SNMP (Simple Network Management Protocol). Este módulo é útil para coleta de métricas de roteadores, switches, servidores, impressoras e qualquer dispositivo que suporte SNMP.
- Suporte a SNMP v1, v2c e v3
- Operações GET, GET BULK e WALK
- Autenticação e criptografia SNMP v3
- Configuração flexível de timeout e retentativas
- Retorno seguro com tratamento de erros
Protocolos suportados:
- SNMP v1: Protocolo básico com comunidade pública/privada
- SNMP v2c: Melhorias de performance com operações BULK
- SNMP v3: Segurança avançada com autenticação e criptografia
Configuração SNMP
Todas as funções SNMP requerem um objeto de configuração que define os parâmetros de conexão. A configuração é uma tabela Lua com os seguintes campos:
Campos de Configuração Básicos:
| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
address |
string | obrigatório | Endereço IP ou hostname do dispositivo |
snmpVersion |
número | 1 | Versão SNMP (1=v1, 2=v2c, 3=v3) |
snmpPort |
número | 161 | Porta SNMP |
snmpCommunity |
string | nil | Comunidade SNMP (v1/v2c) |
snmpTimeout |
número | 5 | Timeout em segundos |
snmpRetryCount |
número | 3 | Número de retentativas |
snmpMaxBulkItems |
número | nil | Máximo de itens por operação BULK |
snmpExponentialBackoff |
booleano | false | Habilitar backoff exponencial |
Campos para SNMP v3:
| Campo | Tipo | Descrição |
|---|---|---|
snmpSecurityLevel |
string | Nível de segurança: "NoAuthNoPriv", "AuthNoPriv", "AuthPriv" |
snmpAuthProtocol |
string | Protocolo de autenticação: "MD5", "SHA1" |
snmpAuthUser |
string | Usuário de autenticação |
snmpAuthPassword |
string | Senha de autenticação |
snmpPrivProtocol |
string | Protocolo de criptografia: "DES", "AES" |
snmpPrivPassword |
string | Senha de criptografia |
Configuração via Tabela params:
O ambiente Lua inclui uma tabela predefinida chamada params que contém os detalhes do dispositivo atual. Esta tabela pode ser usada diretamente como configuração SNMP, pois já possui os campos necessários no formato esperado.
Exemplo de uso direto:
-- Usar a tabela device diretamente como configuração
local sys_descr = snmp.getex(device, "1.3.6.1.2.1.1.1.0")
print("Descrição do dispositivo:", sys_descr)
-- Versão que não lança erro
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:
-- Criar configuração baseada em device com ajustes
local config = {
address = device.address,
snmpVersion = device.snmpVersion,
snmpCommunity = device.snmpCommunity,
snmpTimeout = device.snmpTimeout or 5, -- Usar padrão se não definido
snmpRetryCount = 2, -- Sobrescrever valor padrão
snmpMaxBulkItems = 50 -- Adicionar configuração extra
}
-- Usar para operação 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)
Exemplos de Configuração:
-- 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, -- Porta customizada
snmpTimeout = 10 -- Timeout maior para rede lenta
}
Funções Disponíveis
1. snmp.getex(config, oid)
Realiza uma consulta SNMP GET para um OID específico.
Parâmetros:
- config (tabela): Configuração SNMP (ver seção acima)
- oid (string): OID a ser consultado (formato numérico ou nomeado)
Retorno:
- valor: Valor retornado pelo dispositivo SNMP (número, string, etc.)
Erros:
- Lança erro se o OID não existir ou houver falha na comunicação
Exemplo de Uso:
-- Consultar sysDescr (descrição do 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")
-- ou usando OID nomeado
local sys_descr = snmp.getex(config, ".1.3.6.1.2.1.1.1.0")
print("Descrição do sistema:", sys_descr)
-- Exemplo de saída: "Cisco IOS Software, C3750 Software (C3750-IPSERVICESK9-M), Version 12.2(55)SE10, RELEASE SOFTWARE (fc2)"
-- Consultar uptime do 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 nome do host
local sys_name = snmp.getex(config, "1.3.6.1.2.1.1.5.0")
print("Nome do host:", sys_name)
-- Consultar localização
local sys_location = snmp.getex(config, "1.3.6.1.2.1.1.6.0")
print("Localização:", sys_location)
2. snmp.get_safe(config, oid)
Versão segura de getex que não lança exceções, retornando erro como segundo valor.
Parâmetros:
- config (tabela): Configuração SNMP
- oid (string): OID a ser consultado
Retorno:
-
tuple:
(valor, erro)onde:- valor (qualquer tipo ou nil): Valor retornado se bem-sucedido
- erro (string ou nil): Mensagem de erro se falhar, nil se bem-sucedido
Exemplo de Uso:
local config = {
address = "192.168.1.1",
snmpVersion = 2,
snmpCommunity = "public"
}
-- Consulta segura que não quebra o script em caso de erro
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 ação 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
3. snmp.get_bulk(config, oids)
Realiza operação SNMP GET BULK para múltiplos OIDs de uma vez (SNMP v2c/v3).
Parâmetros:
- config (tabela): Configuração SNMP (deve ser v2 ou v3)
- oids (array de strings): Lista de OIDs para consulta
Retorno:
- tabela: Mapa OID → valor para todos os OIDs consultados
Comportamento:
- Mais eficiente que múltiplas chamadas
getexpara muitos OIDs - Suportado apenas em SNMP v2c e v3
- Usa
snmpMaxBulkItemsda configuração para limitar tamanho
Exemplo de Uso:
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 operação
}
-- 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 informações de múltiplas 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
4. snmp.get(oid)
Versão simplificada de snmp.getex que usa automaticamente a configuração do dispositivo atual (params).
Parâmetros:
- oid (string): OID a ser consultado
Retorno:
- valor: Valor retornado pelo dispositivo SNMP
Comportamento:
- Usa
paramscomo configuração - Lança erro se o OID não existir ou houver falha na comunicação
Exemplo de Uso:
-- Consulta simplificada usando a configuração do dispositivo atual
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)
Realiza uma operação SNMP WALK com suporte a cache e ordenação.
Parâmetros:
- oid (string): OID base para o walk
- cache_ttl (número, opcional): Tempo de vida do cache em segundos
- enforce_ordering (booleano, opcional): Forçar ordenação dos resultados (ordem natural)
Comportamento do cache:
- Usa cache quando
cache_ttlé especificado
Exemplo de Uso:
-- Walk com cache 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 com ordenação forçada (sem cache)
local ordered_interfaces = snmp.walk("1.3.6.1.2.1.2.2.1.2", nil, true)
print("Total de interfaces:", #ordered_interfaces)
Comportamento de Ordenação:
O parâmetro enforce_ordering controla como os resultados são estruturados:
-
Quando
false(padrão): Os resultados são retornados como uma tabela Lua onde cada OID é uma chave que mapeia para seu valor. Esta estrutura é eficiente para acesso aleatório, mas perde a ordenação natural dos OIDs, pois as tabelas Lua não preservam a ordem de inserção das chaves. -
Quando
true: Os resultados são retornados como uma lista de pares (tabela de tabelas), onde cada elemento é uma tabela contendo 2 elementos. Esta estrutura preserva a ordem natural dos OIDs conforme retornados pelo 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 = falsequando você só precisa acessar valores por OID específico e a ordem não importa. - Use
enforce_ordering = truequando você precisa processar os resultados na mesma ordem em que foram retornados pelo dispositivo, como para:- Gerar relatórios ordenados
- Processar sequências de índices consecutivos
- Manter correspondência com outras listas ordenadas
Retorno:
- tabela: Mapa OID → valor para todos os OIDs encontrados
6. snmp.walkex(device, oid, cache_ttl)
Função estendida de walk com sistema de cache avançado e prevenção de execuções concorrentes.
Parâmetros:
- device (tabela): Configuração do dispositivo
- oid (string): OID base para o walk
- cache_ttl (número, opcional): Tempo de vida do cache em segundos
Retorno:
- tabela: Mapa OID → valor para todos os OIDs encontrados
Comportamento:
- Implementa cache global compartilhado entre execuções
- Previne execuções concorrentes do mesmo walk
- Usa
registrypara coordenar execuções simultâneas
Exemplo de Uso:
-- Walk estendido com cache 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
7. snmp.count(oid)
Conta o número de itens retornados por um walk.
Parâmetros:
- oid (string): OID base para contar
Retorno:
- número: Quantidade de itens encontrados
Exemplo de Uso:
-- 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 processos
local num_processes = snmp.count("1.3.6.1.2.1.25.4.2.1.2")
print("Número de processos:", num_processes)
8. snmp.diff(typ, lhs, rhs)
Calcula a diferença entre dois valores, tratando rollover de contadores.
Parâmetros:
- typ (número): Tipo do contador (32 ou 64 bits)
- lhs (número): Valor atual
- rhs (número): Valor anterior
Retorno:
- número: Diferença entre os valores
Comportamento:
- Trata rollover de contadores de 32 e 64 bits
- Sinaliza
RepeatPrevValuese a diferença for negativa
Exemplo de Uso:
-- Calcular diferença 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)
9. inst(oid)
Resolve dinamicamente OIDs de instâncias baseado no nome da instância.
Parâmetros:
- oid (string): OID base (sem índice de instância)
Retorno:
- string: OID completo com índice de instância
Comportamento:
- Usa
params.InstanceNameeparams.snmpOIDDescpara resolução - Suporta cache de instâncias
- Lança erro se a instância não for encontrada
Exemplo de Uso:
-- 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)
10. prev(oid)
Obtém o valor anterior de um OID armazenado.
Parâmetros:
- oid (string): OID para obter valor anterior
Retorno:
- qualquer tipo: Valor anterior armazenado, ou 0 se não existir
Comportamento:
- Busca valor em
store.get("snmp.value." .. oid) - Retorna 0 se não encontrar valor armazenado
Exemplo de Uso:
-- Obter valor anterior para cálculo de taxa
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)
11. lapsed(oid)
Obtém o tempo decorrido desde a última leitura de um OID.
Parâmetros:
- oid (string): OID para verificar tempo decorrido
Retorno:
- número: Tempo em segundos desde última leitura, ou 1 se não houver registro
Exemplo de Uso:
-- Calcular taxa 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")
Exemplos Completos
Monitoramento de Interface de Rede:
-- 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
-- Obter informações da interface
local interface_index = snmp.get(if_index_oid)
local interface_name = snmp.get(if_descr_oid)
print("Monitorando interface:", interface_name, "(índice", interface_index, ")")
-- Coletar estatí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 diferenças desde última leitura
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)
Inventário de Interfaces com Walk:
-- Listar todas as interfaces com 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
-- Extrair índice da interface do OID
local index = string.match(oid, "(%d+)$")
-- Obter tipo e status da interface
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:
-- 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