User Tools

Site Tools


doc:appunti:linux:sa:snmp

Monitoraggio SNMP

Introduzione

L'architettura SNMP è di tipo client server. Il server viene interrogato o impostato dal client con i comandi GET, GET-NEXT, GET-RESPONSE e SET. Il server può informare il client con il comando TRAP.

Gli attributi monitorabili sono organizzati in un MIB (Management Information Base) che ha una struttora ad albero. Ogni oggetto ho un identificativo (OID) che indica anche la sua gerarchia (es: “1.1.0”) e pure una label descrittiva (es: “system.sysDescr.0”). Quindi si puo' usare indifferentemente una di queste sintassi per riferirsi ad un attributo:

1.1.0
system.sysDescr.0
1.sysDescr.0

La gerarchia (albero) dei simboli e i loro nomi sono codificati nel RFC1066 MIB. La radice degli oggetti - se non indicata - è per convenzione .iso.org.dod.internet.mgmt.mib. cioè in numeri .1.3.6.1.2.1.. Vedi a proposito man variables(5snmp). Nota che i nomi dei simboli distinguono le maiuscole/minuscole a differenza di quello che dice la man page.

Per convertire i nomi degli attributi dal formato testuale a quello numerico:

# snmptranslate -On IF-MIB::ifName.2
.1.3.6.1.2.1.31.1.1.1.1.2

# snmptranslate -m ALL .1.3.6.1.2.1.31.1.1.1.1.2
IF-MIB::ifName.2

# snmptranslate -Of IF-MIB::ifName.2
.iso.org.dod.internet.mgmt.mib-2.ifMIB.ifMIBObjects.ifXTable.ifXEntry.ifName.2

# snmpget -v1 -c public 127.0.0.1   IF-MIB::ifName.2
IF-MIB::ifName.2 = STRING: eth0

# snmpget -v1 -c public 127.0.0.1   1.3.6.1.2.1.31.1.1.1.1.2
IF-MIB::ifName.2 = STRING: eth0

# snmptranslate -Td IF-MIB::ifName
IF-MIB::ifName
ifName OBJECT-TYPE
  -- FROM       IF-MIB
  -- TEXTUAL CONVENTION DisplayString
  SYNTAX        OCTET STRING (0..255)
  DISPLAY-HINT  "255a"
  MAX-ACCESS    read-only
  STATUS        current
  DESCRIPTION   "The textual name of the interface.  The value of this
            object should be the name of the interface as assigned by
            the local device and should be suitable for use in commands
            entered at the device's `console'.  This might be a text
            ...

Nota che snmptranslate e' in grado anche di cercare espressioni regolari in tutta la gerarchia MIB, cosi' che trovare un certo OID diventa piu' facile:

# snmptranslate -Ib 'sys.*ime'
SNMPv2-MIB::sysORUpTime

SNMP

Sulla macchina da monitorare deve essere installato il demone SNMP, si installa il pacchetto snmpd. Anche se il firewall blocca l'accesso al demone dall'esterno, conviene fare una configurazione un po' più accorta di /etc/snmp/snmpd.conf, vedere man snmpd.conf(5).

La configurazione di default di Debian è già particolarmente paranoica, si deve dare accesso almeno in sola lettura a 127.0.0.1 per fare in modo che MRTG possa fare le sue statistiche: aggiunta la riga:

com2sec readonly 127.0.0.1 public

Impostate anche syslocation e syscontact in modo che diano informazioni sensate.

Per vedere se funziona si installa il pacchetto snmp (tool client) e si prova ad usare uno dei comandi:

snmpwalk    -v 1 -c public 127.0.0.1
snmpget     -v 1 -c public 127.0.0.1 system.sysDescr.0
snmpnetstat -v 1 -c public -o -n 127.0.0.1

L'interrogazione funziona utilizzando la versione 1 o 2c del protocollo (opzione -v), per la versione 3 sarebbe richiesto impostare altre opzioni tipo la securityName, ecc.

Ovviamente si deve conoscere il nome della community (“public” in questo esempio), ed avere i permessi per fare la richiesta. Con snmpwalk si ha l'elenco di tutte le label degli OID interrogabili. Con snmpget si legge il valore dell'attributo. Snmpnetstat presenta alcuni dati relativi alle interfacce di rete in modo più leggibile.

La versione più recente del pacchetto Debian binda il demone solo sull'indirizzo 127.0.0.1, per mettersi in ascolto su tutti gli indirizzi IP bisogna togliere tale indirizzo dalla variabile SNMPDOPTS dal file /etc/default/snmpd.

Controllo del log

L'installazione predefinita di Debian Wheezy genera una riga di log per ogni interrogazione SNMP, se pare eccessiva basta modificare il livello di log agendo sulla variabile SNMPDOPTS del file /etc/default/snmpd:

SNMPDOPTS='-LS0-5d ...

In questo caso S0-5 significa loggare su syslog da LOG_EMERG to LOG_NOTICE, d indica la facility LOG_DAEMON. Vedere snmpcmd(1).

Aggiunta di sensori SNMP

Creato uno script per interfacciare snmpd a varie utility di sistema come i sensori della scheda madre, utility per misurare latenza e pacchetti persi (netmonitor), ecc. Poi si aggiungono in /etc/snmp/snmpd.conf delle righe del tipo:

exec sensors1 /usr/local/sbin/snmpd-helper fan
exec sensors2 /usr/local/sbin/snmpd-helper cpu

A questo punto il sensore è leggibile con:

snmpwalk -v1 -c public 127.0.0.1 UCD-SNMP-MIB::extOutput.1

Come si vede il valore è disponibile sotto un MIB differente, la radice in questo caso è .1.3.6.1.4.1.2021.8.1. (UCD-SNMP-MIB::).

Con la nuova sintassi di snmpd.conf (introdotta con la versione 5.2.x e quindi da preferire ad esempio con snmpd 5.4.3) la direttiva exec viene deprecata, al suo posto si usa extend:

extend sensors_cpu_fan  /usr/local/sbin/snmpd-helper fan
extend sensors_sys_fan  /usr/local/sbin/snmpd-helper fan2

in questo caso l'OID da leggere è:

snmpwalk -v1 -c public 127.0.0.1 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."sensors_cpu_fan"'

Il vantaggio è che l'OID viene indirizzato non con l'indice numerico (che dipende dall'ordine in cui è definito nel file di configurazione), ma da una etichetta.

Notare l'uso degli apici nel comando da shell, in quanto le doppie virgolette fanno parte a tutti gli effetti del nome dell'OID.

Esempi configurazione

Per comodità si può suddividere la configurazione in diversi file ed includerli nel file /etc/mrtg/mrtg.cfg:

#LoadMIBs: /usr/share/snmp/mibs/UCD-SNMP-MIB.txt
LoadMIBs: /usr/share/mibs/netsnmp/UCD-SNMP-MIB
WorkDir: /var/www/mrtg
Include: eth0
Include: cpu1
Include: fan1
Include: free
### Interface eth0
Target[eth0]:   \eth0:public@localhost:
Title[eth0]:    Traffic for interface eth0
PageTop[eth0]:  <H1>Traffic for interface eth0</H1>
Options[eth0]:  growright,bits,noinfo,unknaszero
MaxBytes[eth0]: 13107200
#Unscaled[eth0]: dwm
### CPU Load
Target[cpu1]: ( ssCpuRawUser.0&ssCpuRawUser.0:public@localhost 
    + ssCpuRawSystem.0&ssCpuRawSystem.0:public@localhost
    + ssCpuRawNice.0&ssCpuRawNice.0:public@localhost ) / 2
Title[cpu1]: CPU LOAD
PageTop[cpu1]: <H1>Active CPU Load %</H1>
Colours[cpu1]: ORANGE#ff5c00,BLACK#000000,DARK GREEN#006600,VIOLET#ff00ff
MaxBytes[cpu1]: 100
Unscaled[cpu1]: dwmy
ShortLegend[cpu1]: %
YLegend[cpu1]: CPU Utilization
Legend1[cpu1]: Active CPU in % (Load)
Legend2[cpu1]:
Legend3[cpu1]:
Legend4[cpu1]:
LegendI[cpu1]: Load:&nbsp;
LegendO[cpu1]:
#Options[cpu1]: noo,growright,nopercent,noinfo,unknaszero
Options[cpu1]: growright,nopercent,noinfo,unknaszero

NOTA: Il carico della CPU deve essere diviso per il numero di core presenti (vedere con cat /proc/cpuinfo, 2 nell'esempio sopra). Il contatore SNMP infatti fornisce il numero di ticks di CPU spesi nell'eseguire i processi, ci sono 100 ticks per CPU al secondo.

### CPU Fan
Target[fan1]: .1.3.6.1.4.1.2021.8.1.101.1&.1.3.6.1.4.1.2021.8.1.101.2:public@localhost
Title[fan1]: CPU Fan
PageTop[fan1]: <H1>CPU and System Fans</H1>
Options[fan1]: gauge,growright,nopercent,noinfo,unknaszero,integer
Colours[fan1]: CYAN#92D5FF,BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff
YLegend[fan1]: RPM
ShortLegend[fan1]: rpm
MaxBytes[fan1]: 5000
Unscaled[fan1]: dwmy
kMG[fan1]:
Legend1[fan1]: CPU Fan RPM
Legend2[fan1]: System Fan RPM
Legend3[fan1]:
Legend4[fan1]:
LegendI[fan1]: CPU Fan:&nbsp;
LegendO[fan1]: Sys Fan:&nbsp;
### Free memory
Target[free]:      .1.3.6.1.4.1.2021.4.4.0&.1.3.6.1.4.1.2021.4.6.0:public@localhost
Title[free]:       Free memory
PageTop[free]:     <H1>Free memory</H1>
Options[free]:     gauge,growright,nopercent,noinfo,unknaszero
Colours[free]:     LIGHT GREEN#73d290,GREEN#0c680c,DARK GREEN#006600,VIOLET#ff00ff
MaxBytes1[free]:   1000000
MaxBytes2[free]:   2000000
kMG[free]:         k,M,G,T,P,X
YLegend[free]:     bytes
ShortLegend[free]: bytes
Legend1[free]:     Free swap memory, in bytes
Legend2[free]:     Free memory, not including swap, in bytes
LegendI[free]:     Free swap:&nbsp;
LegendO[free]:     Free memory:&nbsp;

The follogin example is for disk free graph. You need to adjust the MaxBytes to the size of your partition:

Target[df_md0]:      `/usr/local/bin/mrtg-diskfree /dev/md0`
Title[df_md0]:       Disk Usage /dev/md0
Unscaled[df_md0]:    dwym
MaxBytes[df_md0]:    4814824
PageTop[df_md0]:     <H1>Disk Usage /dev/md0</H1>
kmg[df_md0]:         KB,MB,GB
Colours[df_md0]:     BLUE#0000ff,VIOLET#ff00ff,RED#ff0000,DARK BLUE#00007f
LegendI[df_md0]:     Used Disk Space
LegendO[df_md0]:     Total Disk Space
Legend1[df_md0]:     Used Disk Space
Legend2[df_md0]:     Total Disk Space
YLegend[df_md0]:     bytes
ShortLegend[df_md0]: bytes
Options[df_md0]:     gauge, growright, noinfo

you also need the following script mrtg-diskfree:

#!/bin/sh
 
# It assumes that the command output(df -klP) looks like this:
#
# Filesystem           1K-blocks      Used Available Use% Mounted on
# /dev/md0               4814824    781300   3788944  18% /
# tmpfs                  1037648         0   1037648   0% /lib/init/rw
# udev                     10240        64     10176   1% /dev
# tmpfs                  1037648         4   1037644   1% /dev/shm
# /dev/md2             148483184    208412 148274772   1% /home
 
DEV="$1"
if [ ! -b "$DEV" ]; then
    echo "Usage: $(basename $0) <device>"
    exit 1
fi
 
df="$(df -klP | egrep "^${DEV}\b")"
size="$(echo $df | awk '{print $2}')"
used="$(echo $df | awk '{print $3}')"
 
echo $used
echo $size

This graph displays the packet loss percentage with a remote host. It requires the mrtg-ping-probe script, available also as a Debian package:

### Packet loss
Target[loss_192.168.2.2]: `/usr/bin/mrtg-ping-probe -p loss/loss 217.58.146.19`
Title[loss_192.168.2.2]: Packet loss 192.168.2.2
PageTop[loss_192.168.2.2]: <H1>Packet loss 192.168.2.2</H1>
Options[loss_192.168.2.2]: noo,gauge,growright,nopercent,noinfo,unknaszero,withzeroes
Colours[loss_192.168.2.2]: RED#d60000,BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff
MaxBytes[loss_192.168.2.2]: 100
Unscaled[loss_192.168.2.2]: dwmy
YLegend[loss_192.168.2.2]: Packet loss %
ShortLegend[loss_192.168.2.2]: %
Legend1[loss_192.168.2.2]: Packet loss in %
Legend2[loss_192.168.2.2]:
LegendI[loss_192.168.2.2]: loss&nbsp;
LegendO[loss_192.168.2.2]:

This graph displays the packet max/min round-trip time (ping) with a remote host. It requires the mrtg-ping-probe script, available also as a Debian package:

### Ping
Target[ping_88.149.128.3]: `/usr/bin/mrtg-ping-probe -p avg/max 88.149.128.3`
Title[ping_88.149.128.3]: Ping 88.149.128.3 (ping.ngi.it)
PageTop[ping_88.149.128.3]: <H1>Ping 88.149.128.3 (ping.ngi.it)</H1>
Options[ping_88.149.128.3]: gauge,growright,nopercent,noinfo
Colours[ping_88.149.128.3]: YELLOW#d37d00,RED#910000,YELLOW#d37d00,RED#910000
MaxBytes[ping_88.149.128.3]: 3000
YLegend[ping_88.149.128.3]: Ping time (ms)
ShortLegend[ping_88.149.128.3]: ms
Legend1[ping_88.149.128.3]: Average Round Trip Time in ms
Legend2[ping_88.149.128.3]: Maximum Round Trip Time in ms
LegendI[ping_88.149.128.3]: &nbsp;Avg:
LegendO[ping_88.149.128.3]: &nbsp;Max:

Temperature graph using lmsensors. Verify that the version of Net-SNMP on the target system was compiled with the lmSensors extension by running snmpd -Dmib_init and looking through the output for the lmSensors string. Then you need to discover the MIB of your sensor:

snmpwalk -v2c -c public localhost 1.3.6.1.4.1.2021.13.16

In my case the temperature is multiplied by 1000:

### Sensor temp1
Target[temp1]:      iso.3.6.1.4.1.2021.13.16.2.1.3.1&iso.3.6.1.4.1.2021.13.16.2.1.3.1:public@localhost
Factor[temp1]:      0.001
YTicsFactor[temp1]: 0.001
Title[temp1]:       Temperature temp1
PageTop[temp1]:     <H1>Temperature temp1</H1>
Options[temp1]:     noo,gauge,growright,nopercent,noinfo,unknaszero,withzeroes
Colours[temp1]:     RED#d60000,BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff
MaxBytes[temp1]:    150000
Unscaled[temp1]:    dwmy
YLegend[temp1]:     Temp C°
ShortLegend[temp1]: C&deg;
Legend1[temp1]:     Temperature in C&deg;
Legend2[temp1]:
LegendI[temp1]:     Temp C&deg;&nbsp;
LegendO[temp1]:

It seems that MRTG does not support UTF-8 (even version 2.17.4), so the configuration file should be encoded in ISO_8859-1. Special characters used in HTML output should be encoded properly.

See this article: lmSensors/Net-SNMP Sensor Readings .

MIBs e Debian (Squeeze e successive)

Vedere il wiki Debian.

Tradizionalmente i file contenenti i MIBs di IETF e di IANA venivano distribuiti con il pacchetto libsnmp-base, per problemi di licenza questo non è più possibile (dalla versione net-snmp 5.4.2.1~dfsg-1).

Tuttavia installando il pacchetto non-free snmp-mibs-downloader è possibile scaricare i file in questione, che verranno salvati nella directory /var/lib/mibs/.

Per utilizzare i file scaricati bisogna commentare una riga nel file /etc/snmp/snmp.conf:

# If you added the MIBs you can reenable
# loaging them by commenting out the following line.
#mibs :

Stessa cosa bisogna farla per il demone snmpd, aggiungendo una riga in /etc/default/snmpd:

export MIBS=UCD-SNMP-MIB

Utilizzare almeno la versione 1.1 del pacchetto snmp-mibs-downloader, con versioni precedenti alcuni MIBs non vengono scaricati e si incappa in errori del tipo:

snmptranslate -O n UCD-SNMP-MIB::extOutput.2
No log handling enabled - turning on stderr logging       
Cannot find module (IANAifType-MIB): At line 13 in /usr/share/mibs/ietf/IF-MIB
Did not find 'IANAifType' in module #-1 (/usr/share/mibs/ietf/IF-MIB)         
Cannot find module (IANA-RTPROTO-MIB): At line 12 in /usr/share/mibs/ietf/IP-FORWARD-MIB
Did not find 'IANAipRouteProtocol' in module #-1 (/usr/share/mibs/ietf/IP-FORWARD-MIB)  
.1.3.6.1.4.1.2021.8.1.101.2                                                             

Nuova sintassi per snmpd.conf

Con Debian Squeeze la configurazione di snmpd utilizza per default un nuovo formato che comprende regole di ACL, ecc.

Come mettere il demone in ascolto su tutte le interfacce di rete:

#agentAddress  udp:127.0.0.1:161
agentAddress  udp:161

Come esporre tutte le informazioni disponibili alla community public:

#rocommunity public  default    -V systemonly
 rocommunity public  default

Come aggiungere grandezze da monitorare tramite script esterni:

extend mail_incoming    /usr/bin/sudo /usr/local/sbin/mail-io-stats incoming
extend mail_cmpleted    /usr/bin/sudo /usr/local/sbin/mail-io-stats completed

Per leggere le grandezze aggiuntive si utilizza un OID indicizzato con l'etichetta invece che dalla posizione in cui compare. Notare che le doppie virgolette fanno parte dell'OID:

snmpwalk -v 2c -c public 127.0.0.1 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."mail_incoming"'
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."mail_incoming" = STRING: 14

SNMP su ipv6

Con Debian Wheezy sono necessarie alcune accortezze perché SNMP risponda anche su IPV6, in particolare /etc/snmp/snmpd.conf:

agentAddress  udp::161
agentaddress  udp6:161

rocommunity  public default
rocommunity6 public default

SNMP con systemd su Debian 9 e seguenti

Debian 9 Stretch utilizza il sistema di init systemd invece del vecchio sysvinit. Le personalizzazioni all'avvio non si fanno più in /etc/default/snmpd.

La risoluzione degli OIDs nella loro descrizione testuale richiede sempre l'installazione del pacchetto non-free snmp-mibs-downloader. Invece di impostare la variabile d'ambient MIBS si deve modificare il file /etc/snmp/snmp.conf, commentando (disattivando) la riga:

#mibs :

Eventuali personalizzazioni dei parametri di snmpd non si fanno più con la variabile d'ambiente SNMPDOPTS, bisogna piuttosto creare il file /etc/systemd/system/snmpd.service, prendendo come esempio quello predefinito /lib/systemd/system/snmpd.service. Il file personalizzato prevale su quello di sistema (basta eseguire systemctl daemon-reload). Pare che non sia necessario aggiornare i link simbolici, ad esempio quello contenuto in /etc/systemd/system/multi-user.target.wants/.

Ecco ad esempio come modificare la riga ExecStart per diminuire il logging e sopprimere tutte le righe Connection from UDP che riempiono il syslog (nota: si modifica -Lsd in -LSwd):

ExecStart=/usr/sbin/snmpd -LSwd -Lf /dev/null -u Debian-snmp -g Debian-snmp
    -I -smux,mteTrigger,mteTriggerConf -f -p /run/snmpd.pid

In alternativa a sostituire completamente il file unit (cioè il file /etc/systemd/system/snmpd.service) è possibile creare un file override con solo le modifiche necessarie. Il file override deve stare nella directory /etc/systemd/system/snmpd.service.d/ e può chiamarsi local.conf (è possibile averne più di uno). Fare attenzione al parametro ExecStart che deve essere svuotato prima di essere definito nuovamente:

[Service]
Environment="MIBS="
ExecStart=
ExecStart=/usr/sbin/snmpd -LSwd -Lf /dev/null -u Debian-snmp -g Debian-snmp
    -I -smux,mteTrigger,mteTriggerConf -f -p /run/snmpd.pid
doc/appunti/linux/sa/snmp.txt · Last modified: 2020/04/01 11:40 by niccolo