Le protocole SNMP
09/02/2005
 Christian CALECA 
Liste des cours

MRTG en production

Accueil ] [ Le principe ] [ Le protocole ] [ Install.  SNMP. ] [ La MIB ] [ Managers ] [ MRTG intro ] [ MRTG en production ]


Avertissement

N'oublions pas que l'objet de ce chapitre est SNMP et non MRTG...

Les exemples qui suivent sont destinés à montrer comment utiliser SNMP et pas à montrer toutes les finesses de MRTG. Pour ça, vous avez la documentation fournie avec :)

La passerelle

En l'occurrence, il s'agit d'une machine Mandrake 9.0 sur laquelle MRTG 2.9.21 a été installé, comme vu plus haut.

Cette machine est équipée de deux interfaces Ethernet, l'une pour le LAN et l'autre pour le modem-câble. Par dessus, nous trouvons un lien PPP (PPPoE oblige). Ce qui nous donne ceci :

[root@gw1 root]# ifconfig
eth0 Lien encap:Ethernet HWaddr 00:20:18:2C:0E:E9
inet adr:192.168.0.250 Bcast:192.168.0.255 Masque:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2157836 errors:0 dropped:0 overruns:0 frame:0
TX packets:2075111 errors:1 dropped:0 overruns:0 carrier:1
collisions:1840 lg file transmission:100
RX bytes:189444177 (180.6 Mb) TX bytes:691138390 (659.1 Mb)
Interruption:10 Adresse de base:0xe000

eth1 Lien encap:Ethernet HWaddr 00:60:8C:50:F3:3E
inet adr:192.168.100.250 Bcast:192.168.100.255 Masque:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2788786 errors:0 dropped:0 overruns:0 frame:0
TX packets:2266845 errors:0 dropped:0 overruns:0 carrier:0
collisions:2250 lg file transmission:100
RX bytes:991395133 (945.4 Mb) TX bytes:228369369 (217.7 Mb)
Interruption:3 Adresse de base:0x300

lo Lien encap:Boucle locale
inet adr:127.0.0.1 Masque:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:28457 errors:0 dropped:0 overruns:0 frame:0
TX packets:28457 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 lg file transmission:0
RX bytes:3438607 (3.2 Mb) TX bytes:3438607 (3.2 Mb)

ppp0 Lien encap:Protocole Point-à-Point
inet adr:80.8.146.171 P-t-P:80.8.144.1 Masque:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:401251 errors:0 dropped:0 overruns:0 frame:0
TX packets:523520 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 lg file transmission:3
RX bytes:180973212 (172.5 Mb) TX bytes:41086532 (39.1 Mb)

Nous utilisons, comme d'habitude le script cfgmaker :

[root@gw1 root]# cfgmaker \
> --global 'WorkDir: /var/www/html/mrtg/local' \
> --global 'Language: french' \
> --global 'Options[_]: bits,growright' \
> --ifdesc=descr public@localhost \
> --output /var/www/html/mrtg/local/local.cfg

Seulement voilà, nous rencontrons un problème sur ppp0 :

...
### Interface 4 >> Descr: 'ppp0' | Name: '' | Ip: '80.8.146.171' | Eth: '' ###
### The following interface is commented out because:
### * has a speed of 0 which makes no sense
#
# Target[localhost_4]: 4:public@localhost:
# SetEnv[localhost_4]: MRTG_INT_IP="80.8.146.171" MRTG_INT_DESCR="ppp0"
# MaxBytes[localhost_4]: 0
# Title[localhost_4]: ppp0 -- gw1.maison.mrs
# PageTop[localhost_4]: <H1>ppp0 -- gw1.maison.mrs</H1>
# <TABLE>
# <TR><TD>System:</TD> <TD>gw1.maison.mrs in Le local technique</TD></TR>
# <TR><TD>Maintainer:</TD> <TD>Root &lt;root@localhost&gt; (configure /etc/snmp/snmp.conf)</TD></TR>
# <TR><TD>Description:</TD><TD>ppp0 </TD></TR>
# <TR><TD>ifType:</TD> <TD>ppp (23)</TD></TR>
# <TR><TD>ifName:</TD> <TD></TD></TR>
# <TR><TD>Max Speed:</TD> <TD>0.0 bits/s</TD></TR>
# <TR><TD>Ip:</TD> <TD>80.8.146.171 (ca-marseille-19-171.w80-8.abo.wanadoo.fr)</TD></TR>
# </TABLE>

SNMP ne donne pas la vitesse maxi de ppp0 et MRTG ne sait pas comment calculer les graphes. Nous allons devoir modifier tout ça à la main. Fort heureusement, ce n'est pas trop compliqué.

La vitesse maxi, nous la connaissons, elle dépend de l'abonnement. Ici, 512 kilo bits par seconde. Nous prendrons 640 kilo bits par seconde, soit 80 kilo octets par seconde. Nous modifions comme suit :

# MaxBytes[localhost_4]: 80000
...
# <TR><TD>Max Speed:</TD> <TD>640.0 Kbits/s</TD></TR>

De plus, laisser l'IP telle qu'elle a été trouvée au moment de la construction du fichier n'a aucun sens puisque cette adresse va changer à chaque nouvelle session PPPoE (sauf si vous disposez d'une IP fixe, bien entendu). Nous modifions donc la dernière ligne du tableau :

# <TR><TD>Ip:</TD> <TD>Adresse dynamique</TD></TR>

Ca devrait suffire à obtenir quelque chose de propre. Bien entendu, il ne faudra pas oublier de dé-commenter toutes les lignes nécessaires.

Il ne nous reste plus qu'à construire la page d'index :

[root@gw1 root]# indexmaker --columns=1 --sort=descr \
> --sidebyside /var/www/html/mrtg/local/local.cfg \
> --output=/var/www/html/mrtg/local/index.html

Et voilà le travail...

Il est clair que les graphes représentant ppp0 et eth1 vont être très similaires, puisque ppp0 passe sur eth1. Ce ne sera probablement pas la peine de garder les deux, du moins dans ma configuration simple.

Encore plus...

La charge CPU

Afficher le trafic réseau, c'est bien, mais SNMP donne bien plus d'informations. Ce serait par exemple intéressant de tracer le graphe de la charge CPU.

Pour y arriver, c'est assez simple, il suffit de lire le tutoriel de net-snmp sur http://net-snmp.sourceforge.net/ et d'adapter le modèle à notre configuration :

LoadMIBs: /usr/share/snmp/mibs/UCD-SNMP-MIB.txt
### Attention, les trois lignes qui suivent doivent en fait n'en faire qu'une seule
Target[gw1.cpusum]:ssCpuRawUser.0&ssCpuRawUser.0:public@localhost
   + ssCpuRawSystem.0&ssCpuRawSystem.0:public@localhost
   + ssCpuRawNice.0&ssCpuRawNice.0:public@localhost
RouterUptime[gw1.cpusum]: public@localhost 
MaxBytes[gw1.cpusum]: 100 
Title[gw1.cpusum]: CHARGE CPU
PageTop[gw1.cpusum]: <H1>Charge Active CPU %</H1> 
Unscaled[gw1.cpusum]: ymwd 
ShortLegend[gw1.cpusum]: % 
YLegend[gw1.cpusum]: Utilisation CPU
Legend1[gw1.cpusum]: CPU Actif en % (Charge) 
Legend2[gw1.cpusum]: 
Legend3[gw1.cpusum]: 
Legend4[gw1.cpusum]: 
LegendI[gw1.cpusum]:  Actif 
LegendO[gw1.cpusum]: 
Options[gw1.cpusum]: growright,nopercent

Qu'avons-nous fait ?

Il nous faut aller dans la MIB, chercher les bonnes valeurs. Comme nous utilisons une représentation textuelle des feuilles à lire, il nous faut charger le fichier qui permettra d'interpréter cette représentation. Avec une représentation numérique, ça n'aurait pas été nécessaire.

l'outil snmptranslate va nous servir à repérer la partie de la MIB qui nous intéresse ici. Pour éviter de faire trop long, cherchons tout de suite dans la branche "private" : 

[root@gw1 root]# snmptranslate -Tp -IR private
+--private(4)
   |
   +--enterprises(1)
      |
      +--ucdavis(2021)
         |
         +--prTable(2)
         |  |
         |  +--prEntry(1)
         |     |  Index: prIndex
         |     |
         |     +-- -R-- Integer32 prIndex(1)
         |     |        Range: 0..65535
         |     +-- -R-- String    prNames(2)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- Integer32 prMin(3)
         |     +-- -R-- Integer32 prMax(4)
         |     +-- -R-- Integer32 prCount(5)
         |     +-- -R-- Integer32 prErrorFlag(100)
         |     +-- -R-- String    prErrMessage(101)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -RW- Integer32 prErrFix(102)
         |     +-- -R-- String    prErrFixCmd(103)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--memory(4)
         |  |
         |  +-- -R-- Integer32 memIndex(1)
         |  +-- -R-- String    memErrorName(2)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- Integer32 memTotalSwap(3)
         |  +-- -R-- Integer32 memAvailSwap(4)
         |  +-- -R-- Integer32 memTotalReal(5)
         |  +-- -R-- Integer32 memAvailReal(6)
         |  +-- -R-- Integer32 memTotalSwapTXT(7)
         |  +-- -R-- Integer32 memAvailSwapTXT(8)
         |  +-- -R-- Integer32 memTotalRealTXT(9)
         |  +-- -R-- Integer32 memAvailRealTXT(10)
         |  +-- -R-- Integer32 memTotalFree(11)
         |  +-- -R-- Integer32 memMinimumSwap(12)
         |  +-- -R-- Integer32 memShared(13)
         |  +-- -R-- Integer32 memBuffer(14)
         |  +-- -R-- Integer32 memCached(15)
         |  +-- -R-- Integer32 memSwapError(100)
         |  +-- -R-- String    memSwapErrorMsg(101)
         |           Textual Convention: DisplayString
         |           Size: 0..255
         |
         +--extTable(8)
         |  |
         |  +--extEntry(1)
         |     |  Index: extIndex
         |     |
         |     +-- -R-- Integer32 extIndex(1)
         |     |        Range: 0..65535
         |     +-- -R-- String    extNames(2)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- String    extCommand(3)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- Integer32 extResult(100)
         |     +-- -R-- String    extOutput(101)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -RW- Integer32 extErrFix(102)
         |     +-- -R-- String    extErrFixCmd(103)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--dskTable(9)
         |  |
         |  +--dskEntry(1)
         |     |  Index: dskIndex
         |     |
         |     +-- -R-- Integer32 dskIndex(1)
         |     |        Range: 0..65535
         |     +-- -R-- String    dskPath(2)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- String    dskDevice(3)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- Integer32 dskMinimum(4)
         |     +-- -R-- Integer32 dskMinPercent(5)
         |     +-- -R-- Integer32 dskTotal(6)
         |     +-- -R-- Integer32 dskAvail(7)
         |     +-- -R-- Integer32 dskUsed(8)
         |     +-- -R-- Integer32 dskPercent(9)
         |     +-- -R-- Integer32 dskPercentNode(10)
         |     +-- -R-- Integer32 dskErrorFlag(100)
         |     +-- -R-- String    dskErrorMsg(101)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--laTable(10)
         |  |
         |  +--laEntry(1)
         |     |  Index: laIndex
         |     |
         |     +-- -R-- Integer32 laIndex(1)
         |     |        Range: 0..3
         |     +-- -R-- String    laNames(2)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- String    laLoad(3)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- String    laConfig(4)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- Integer32 laLoadInt(5)
         |     +-- -R-- Opaque    laLoadFloat(6)
         |     |        Textual Convention: Float
         |     |        Size: 7
         |     +-- -R-- Integer32 laErrorFlag(100)
         |     +-- -R-- String    laErrMessage(101)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--systemStats(11)
         |  |
         |  +-- -R-- Integer32 ssIndex(1)
         |  +-- -R-- String    ssErrorName(2)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- Integer32 ssSwapIn(3)
         |  +-- -R-- Integer32 ssSwapOut(4)
         |  +-- -R-- Integer32 ssIOSent(5)
         |  +-- -R-- Integer32 ssIOReceive(6)
         |  +-- -R-- Integer32 ssSysInterrupts(7)
         |  +-- -R-- Integer32 ssSysContext(8)
         |  +-- -R-- Integer32 ssCpuUser(9)
         |  +-- -R-- Integer32 ssCpuSystem(10)
         |  +-- -R-- Integer32 ssCpuIdle(11)
         |  +-- -R-- Counter   ssCpuRawUser(50)
         |  +-- -R-- Counter   ssCpuRawNice(51)
         |  +-- -R-- Counter   ssCpuRawSystem(52)
         |  +-- -R-- Counter   ssCpuRawIdle(53)
         |  +-- -R-- Counter   ssCpuRawWait(54)
         |  +-- -R-- Counter   ssCpuRawKernel(55)
         |  +-- -R-- Counter   ssCpuRawInterrupt(56)
         |  +-- -R-- Counter   ssIORawSent(57)
         |  +-- -R-- Counter   ssIORawReceived(58)
         |  +-- -R-- Counter   ssRawInterrupts(59)
         |  +-- -R-- Counter   ssRawContexts(60)
         |
         +--ucdInternal(12)
         |
         +--ucdExperimental(13)
         |  |
         |  +--ucdDlmodMIB(14)
         |     +-- -R-- Integer32 dlmodNextIndex(1)
         |     |
         |     +--dlmodTable(2)
         |        |
         |        +--dlmodEntry(1)
         |           |  Index: dlmodIndex
         |           |
         |           +-- ---- Integer32 dlmodIndex(1)
         |           |        Range: 1..65535
         |           +-- -RW- String    dlmodName(2)
         |           |        Textual Convention: DisplayString
         |           |        Size: 0..255
         |           +-- -RW- String    dlmodPath(3)
         |           |        Textual Convention: DisplayString
         |           |        Size: 0..255
         |           +-- -R-- String    dlmodError(4)
         |           |        Textual Convention: DisplayString
         |           |        Size: 0..255
         |           +-- -RW- EnumVal   dlmodStatus(5)
         |                    Values: loaded(1), unloaded(2), error(3), load(4), unload(5), create(6), delete(7)
         |
         +--ucdDemoMIB(14)
         |  |
         |  +--ucdDemoMIBObjects(1)
         |     |
         |     +--ucdDemoPublic(1)
         |        |
         |        +-- -RW- Integer32 ucdDemoResetKeys(1)
         |        |        Range: 0..2147483647
         |        +-- -RW- String    ucdDemoPublicString(2)
         |        |        Size: 0..1024
         |        +-- -R-- String    ucdDemoUserList(3)
         |        +-- -R-- String    ucdDemoPassphrase(4)
         |
         +--fileTable(15)
         |  |
         |  +--fileEntry(1)
         |     |  Index: fileIndex
         |     |
         |     +-- -R-- Integer32 fileIndex(1)
         |     |        Range: 0..2147483647
         |     +-- -R-- String    fileName(2)
         |     |        Textual Convention: DisplayString
         |     |        Size: 0..255
         |     +-- -R-- Integer32 fileSize(3)
         |     +-- -R-- Integer32 fileMax(4)
         |     +-- -R-- EnumVal   fileErrorFlag(100)
         |     |        Textual Convention: TruthValue
         |     |        Values: true(1), false(2)
         |     +-- -R-- String    fileErrorMsg(101)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--version(100)
         |  |
         |  +-- -R-- Integer32 versionIndex(1)
         |  +-- -R-- String    versionTag(2)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- String    versionDate(3)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- String    versionCDate(4)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- String    versionIdent(5)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- String    versionConfigureOptions(6)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -RW- Integer32 versionClearCache(10)
         |  +-- -RW- Integer32 versionUpdateConfig(11)
         |  +-- -RW- Integer32 versionRestartAgent(12)
         |  +-- -RW- Integer32 versionDoDebugging(20)
         |
         +--snmperrs(101)
         |  |
         |  +-- -R-- Integer32 snmperrIndex(1)
         |  +-- -R-- String    snmperrNames(2)
         |  |        Textual Convention: DisplayString
         |  |        Size: 0..255
         |  +-- -R-- Integer32 snmperrErrorFlag(100)
         |  +-- -R-- String    snmperrErrMessage(101)
         |           Textual Convention: DisplayString
         |           Size: 0..255
         |
         +--mrTable(102)
         |  |
         |  +--mrEntry(1)
         |     |  Index: mrIndex
         |     |
         |     +-- -R-- ObjID     mrIndex(1)
         |     +-- -R-- String    mrModuleName(2)
         |              Textual Convention: DisplayString
         |              Size: 0..255
         |
         +--ucdSnmpAgent(250)
         |  |
         |  +--hpux9(1)
         |  |
         |  +--sunos4(2)
         |  |
         |  +--solaris(3)
         |  |
         |  +--osf(4)
         |  |
         |  +--ultrix(5)
         |  |
         |  +--hpux10(6)
         |  |
         |  +--netbsd1(7)
         |  |
         |  +--freebsd(8)
         |  |
         |  +--irix(9)
         |  |
         |  +--linux(10)
         |  |
         |  +--bsdi(11)
         |  |
         |  +--openbsd(12)
         |  |
         |  +--unknown(255)
         |
         +--ucdTraps(251)
            |
            +--ucdStart(1)
            +--ucdShutdown(2)

Comme l'indique le tutoriel NET-SNMP, le système fournit trois compteurs :User, System et Nice. Si l'on souhaite, comme c'est le cas ici, afficher la charge totale, il nous faut additionner ces trois valeurs.

De plus, MRTG trace les graphes par deux sur le même diagramme. Nous traçons ici deux fois le même.

Pour le reste, il faudra regarder de plus près dans le tutoriel de MRTG si l'on souhaite comprendre les options qui sont spécifiées.

Quelques jours plus tard, voici ce que l'on peut observer...

Notez la pointe d'activité autour des 4h du matin, due à l'activitée générée par logrotate.

La mémoire disponible

Là encore SNMP peut nous informer, mais voyons d'abord un peu avec la commande top.

Ici, sur la passerelle, équipée de 128 Mo de RAM :

10:06am up 11 days, 22:04, 4 users, load average: 0,40, 0,24, 0,14
81 processes: 80 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 64,9% user, 0,8% system, 0,0% nice, 34,1% idle
Mem: 127360K av, 117440K used, 9920K free, 0K shrd, 13752K buff
Swap: 401584K av, 27408K used, 374176K free 24072K cached

Linux a tendance à prendre ses aises dans la RAM disponible (il n'est pas le seul système à le faire). Deux informations sont ici utiles :

Voyons ce que sait nous dire SNMP :

[root@gw1 root]# snmpwalk -v 1 localhost -c public private.enterprises.ucdavis.memory
enterprises.ucdavis.memory.memIndex.0 = 0
enterprises.ucdavis.memory.memErrorName.0 = swap
enterprises.ucdavis.memory.memTotalSwap.0 = 401584
enterprises.ucdavis.memory.memAvailSwap.0 = 374176
enterprises.ucdavis.memory.memTotalReal.0 = 127360
enterprises.ucdavis.memory.memAvailReal.0 = 8872
enterprises.ucdavis.memory.memTotalFree.0 = 383048
enterprises.ucdavis.memory.memMinimumSwap.0 = 16000
enterprises.ucdavis.memory.memShared.0 = 0
enterprises.ucdavis.memory.memBuffer.0 = 15356
enterprises.ucdavis.memory.memCached.0 = 27312
enterprises.ucdavis.memory.memSwapError.0 = 0
enterprises.ucdavis.memory.memSwapErrorMsg.0 =

Nous pourrions par exemple afficher le swap total et le swap disponible, la mémoire réelle (RAM) totale et la mémoire réelle disponible. Nous allons le faire pour le swap.

LoadMIBs: /usr/share/snmp/mibs/UCD-SNMP-MIB.txt
Target[gw1.swap]: memAvailSwap.0&memTotalSwap.0:public@gw1.maison.mrs
Options[gw1.swap]: nopercent,growright,gauge,noinfo
Title[gw1.swap]: Swap
PageTop[gw1.swap]: <H1>Swap.</H1>
MaxBytes[gw1.swap]: 1000000000
kMG[gw1.swap]: k,M,G,T,P,X
Ylegend[gw1.swap]: Octets
ShortLegend[gw1.swap]: octets
LegendI[gw1.swap]: Swap dispo
LegendO[gw1.swap]: Swap total
Legend1[gw1.swap]: Swap disponible
Legend2[gw1.swap]: Swap total

Là encore, je vous laisse regarder dans la documentation de MRTG pour les détails de la configuration.

Quelques temps après, nous obtenons ceci (ce qui n'a ici, rien de passionnant, il faut bien le dire).

Conclusions

Juste un mot pour dire que MRTG, non seulement sait exploiter SNMP, mais qu'il peut aussi afficher des informations issues de scripts, ce qui en augmente encore la portée. Bien entendu, nous ne verrons pas comment faire ici.

Faites un "top" et observez les ressources consommées lorsque MRTG se met au travail... C'est une constante de la mesure : tout instrument de mesure perturbe le milieu dans lequel il opère. Aussi je vous conseille, si vous voulez observer quelque chose de relativement fiable d'installer MRTG sur une machine indépendante de celles dont vous voulez auditer les ressources, surtout en termes de CPU et de mémoire.

Dans le cadre d'un petit réseau domestique, SNMP/MRTG pour visualiser le trafic sur la passerelle, c'est déjà le grand luxe.


Précédente ] [ Accueil ]