🔌 Diagnostic réseau OT/IT · au shell Linux

Chapitre 10
SNMP & le switch managé

Objectifs du chapitre

1. SNMP en bref

Jusqu'ici on a observé le réseau de l'extérieur : capture sur le fil, LLDP local, sondes DCP. Le switch managé, lui, voit tous ses ports d'un coup. SNMP (Simple Network Management Protocol) est le protocole standard pour lui poser des questions. Il tourne en UDP sur le port 161 (les alertes spontanées, les traps, partent vers l'UDP 162, mais on ne s'en servira pas ici).

Un agent SNMP expose ses données sous forme d'un arbre d'OID (Object Identifier), des chaînes de nombres comme 1.3.6.1.2.1.2.2.1.8. Le dictionnaire qui donne un nom lisible à chaque OID s'appelle une MIB (Management Information Base). On distingue deux opérations de lecture : get (une valeur précise) et walk (parcourir toute une branche). L'écriture (set) existe mais reste l'exception — et un vrai sujet de prudence.

Côté sécurité et versions :

La communauté public laissée active est un classique du durcissement OT : quiconque atteint le switch peut lire toute sa configuration. Pire, si la communauté d'écriture (set) est restée par défaut, on peut reconfigurer le switch — désactiver un port, changer un VLAN. Règle de conduite du diagnostic : on reste en lecture seule, jamais de snmpset sur une installation qu'on ne maîtrise pas. Signaler une communauté par défaut fait partie du diagnostic.

2. Premiers pas : lire l'identité du switch

La branche system est le point d'entrée universel : tout agent SNMP la renseigne. On la parcourt avec snmpwalk. Sur notre Scalance manager 192.168.0.240 :

snmpwalk -v2c -c public 192.168.0.240 system
$ snmpwalk -v2c -c public 192.168.0.240 system
SNMPv2-MIB::sysDescr.0 = STRING: Siemens, SIMATIC NET, SCALANCE XC208, 6GK5208-0BA00-2AC2, HW: 4, FW: V6.5
SNMPv2-MIB::sysObjectID.0 = OID: SNMPv2-SMI::enterprises.4329.6.1.2.2.2.7
SNMPv2-MIB::sysUpTime.0 = Timeticks: (184527300) 21 days, 8:34:33.00
SNMPv2-MIB::sysContact.0 = STRING: maintenance@usine.local
SNMPv2-MIB::sysName.0 = STRING: SW-A-MRM
SNMPv2-MIB::sysLocation.0 = STRING: Armoire A1 - cellule assemblage
SNMPv2-MIB::sysServices.0 = INTEGER: 2

En trois lignes on a l'essentiel : le modèle et le firmware (sysDescr — ici un XC208 en firmware V6.5), le nom logique (sysName = SW-A-MRM, qui confirme qu'on parle bien au manager d'anneau) et depuis combien de temps il tourne (sysUpTime). Un sysUpTime qui vient de retomber à zéro trahit un redémarrage — souvent la première piste après un incident.

Pour une seule valeur, snmpget suffit. Attention au suffixe .0 : les objets scalaires (non indexés) portent l'instance 0.

$ snmpget -v2c -c public 192.168.0.240 sysUpTime.0
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (184527300) 21 days, 8:34:33.00

C'est tout l'intérêt du switch comme point d'observation : il a une vue d'ensemble. Une capture tcpdump ne voit que le trafic qui passe par ton port ; le switch, lui, connaît l'état de chacun de ses ports simultanément. Là où la capture dit « je ne reçois plus rien de tel device », le switch dit « le port 3 est down » — une information plus directe.

3. Obtenir des noms lisibles : les MIB

Par défaut, Debian n'installe pas les fichiers MIB (pour des raisons de licence). Résultat : au lieu de IF-MIB::ifOperStatus.3, tu vois l'OID numérique brut 1.3.6.1.2.1.2.2.1.8.3 — exact, mais illisible. On corrige une fois pour toutes :

# Télécharge le jeu de MIB standard (déjà listé au chapitre 1)
sudo apt install -y snmp-mibs-downloader

Le paquet télécharge les MIB, mais le client snmp les ignore encore : le fichier /etc/snmp/snmp.conf contient une ligne mibs : qui désactive tout chargement. Il faut la commenter :

# Dans /etc/snmp/snmp.conf, transformer :
#   mibs :
# en (commenté) :
#   # mibs :
sudo sed -i 's/^mibs :/# mibs :/' /etc/snmp/snmp.conf

La ligne mibs : (deux-points, valeur vide) veut dire « ne charge aucune MIB ». La commenter rend le comportement par défaut : charger toutes les MIB trouvées dans /usr/share/snmp/mibs. Sans MIB, rien n'est cassé — les OID numériques fonctionnent toujours. Les noms symboliques ne sont qu'un confort de lecture, mais un confort décisif quand on débogue sous pression.

Pour charger en plus une MIB constructeur (par ex. la MIB privée Siemens Scalance), on la dépose dans /usr/share/snmp/mibs/ et on la nomme explicitement avec l'option -m :

snmpwalk -v2c -c public -m +SCALANCE-MSPS-MIB 192.168.0.240 ifDescr

4. L'état des ports (IF-MIB) — le cœur du diagnostic

La MIB la plus utile est IF-MIB : la table des interfaces (les ports du switch). Chaque port porte un index (ifIndex), et toutes les colonnes de la table sont indexées par ce numéro. Commence par la liste des ports :

$ snmpwalk -v2c -c public 192.168.0.240 ifDescr
IF-MIB::ifDescr.1 = STRING: P1 - vers CPU S7-1500
IF-MIB::ifDescr.2 = STRING: P2 - anneau vers SW-B
IF-MIB::ifDescr.3 = STRING: P3 - vers ET200SP .20
IF-MIB::ifDescr.4 = STRING: P4 - anneau vers SW-C
IF-MIB::ifDescr.5 = STRING: P5 - libre
IF-MIB::ifDescr.6 = STRING: P6 - poste diag .71

Puis l'état opérationnel de chacun, ifOperStatus (1 = up, 2 = down) :

$ snmpwalk -v2c -c public 192.168.0.240 ifOperStatus
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: down(2)
IF-MIB::ifOperStatus.4 = INTEGER: up(1)
IF-MIB::ifOperStatus.5 = INTEGER: down(2)
IF-MIB::ifOperStatus.6 = INTEGER: up(1)

Le port P3 — celui de l'ET 200SP .20 — est down. (Le P5 est down aussi, mais ifDescr nous a dit qu'il est libre : normal.) On tient déjà une piste forte. Les OID à connaître :

Nom (IF-MIB)OID numériqueCe qu'on lit
ifDescr1.3.6.1.2.1.2.2.1.2Nom / libellé du port
ifOperStatus1.3.6.1.2.1.2.2.1.8État réel : up(1) / down(2)
ifAdminStatus1.3.6.1.2.1.2.2.1.7État voulu (config) : up / down
ifSpeed1.3.6.1.2.1.2.2.1.5Débit négocié (bit/s)
ifInErrors1.3.6.1.2.1.2.2.1.14Trames reçues en erreur (cumul)
ifOutErrors1.3.6.1.2.1.2.2.1.20Trames émises en erreur (cumul)
ifInOctets1.3.6.1.2.1.2.2.1.10Octets reçus (cumul)

Le compteur d'erreurs en réception est souvent plus parlant qu'un port down : un port qui reste up mais dont ifInErrors grimpe signale un câble abîmé, un connecteur mal serti ou une perturbation électromagnétique (EMI) — exactement les symptômes physiques vus au chapitre 2.

$ snmpwalk -v2c -c public 192.168.0.240 ifInErrors
IF-MIB::ifInErrors.1 = Counter32: 0
IF-MIB::ifInErrors.2 = Counter32: 0
IF-MIB::ifInErrors.4 = Counter32: 14802
IF-MIB::ifInErrors.6 = Counter32: 0

Les compteurs SNMP sont cumulatifs depuis le dernier redémarrage du switch. Une valeur absolue élevée (14802 erreurs) n'est pas en soi un défaut : elle peut dater d'un incident vieux de trois semaines, sur un switch qui n'a pas rebooté. Ce qui prouve un problème en cours, c'est la dérive : le compteur qui augmente entre deux relevés. Toujours mesurer un delta avant de conclure.

Mesurer une dérive : deux relevés espacés

On lit le compteur du port suspect, on attend, on relit, et on fait la différence. À la main :

$ snmpget -v2c -c public 192.168.0.240 ifInErrors.4
IF-MIB::ifInErrors.4 = Counter32: 14802
# ... on attend 60 secondes ...
$ snmpget -v2c -c public 192.168.0.240 ifInErrors.4
IF-MIB::ifInErrors.4 = Counter32: 14971

169 erreurs en 60 secondes, soit près de 3 par seconde : le défaut est actif. Sur le port 2, le même relevé donnerait deux fois la même valeur — compteur figé, câble sain.

On automatise la surveillance de la dérive avec une petite boucle de polling qui affiche l'horodatage et la valeur toutes les 5 secondes :

$ while true; do \
    printf '%s  ' "$(date +%H:%M:%S)"; \
    snmpget -v2c -c public -Ovq 192.168.0.240 ifInErrors.4; \
    sleep 5; \
  done
14:02:03  14802
14:02:08  14815
14:02:13  14831
14:02:18  14848   # +46 en 15 s : ça dérive franchement

L'option -Ovq (output: value, quiet) n'affiche que la valeur brute, sans le nom d'OID — idéal pour une colonne propre ou un calcul de delta.

5. La topologie vue du switch (LLDP-MIB)

Au chapitre 3, on lisait LLDP localement, avec lldpctl : « qui est mon voisin ? ». Le switch, lui, connaît le voisin LLDP de chacun de ses ports. La LLDP-MIB l'expose. lldpRemSysName donne le nom système du voisin distant, lldpRemPortId le port par lequel il est branché :

$ snmpwalk -v2c -c public 192.168.0.240 lldpRemSysName
LLDP-MIB::lldpRemSysName.0.1.1 = STRING: plc-s71500
LLDP-MIB::lldpRemSysName.0.2.2 = STRING: SW-B-MRC
LLDP-MIB::lldpRemSysName.0.4.3 = STRING: SW-C-MRC
LLDP-MIB::lldpRemSysName.0.6.4 = STRING: poste-diag-71

On lit ici, depuis le switch central, la carte du câblage : P1 → le CPU, P2 → SW-B, P4 → SW-C, P6 → le poste de diag. Aucune entrée pour le port 3 : cohérent avec son état down du §4 — le voisin (l'ET 200SP) a disparu. Cette vue recoupe et confirme le LLDP local du chapitre 3, mais depuis le point d'observation le plus riche du réseau.

L'index d'une entrée LLDP distante se lit lldpRemTimeMark.lldpRemLocalPortNum.lldpRemIndex. Le nombre du milieu est le port local du switch : c'est lui qui te dit « ce voisin est branché sur mon port N ». Ne le confonds pas avec lldpRemPortId, qui est l'identifiant du port en face, côté voisin.

6. L'état de l'anneau (MRP-MIB)

Le chapitre 8 a montré comment soupçonner un anneau ouvert à la capture (rafales de trames MRP_Test, TopologyChange). SNMP permet de le confirmer sans ambiguïté : le manager d'anneau connaît l'état exact de la redondance. Deux MIB possibles selon le firmware — la MRP-MIB standard (IEC 62439-2) et la MIB privée Siemens. L'objet clé est l'état de l'anneau, mrpRingState : closed(2) = redondance saine, open(1) = un maillon est rompu.

Sur le manager SW-A-MRM, anneau sain :

$ snmpwalk -v2c -c public 192.168.0.240 mrpRingState
MRP-MIB::mrpRingState.1 = INTEGER: closed(2)
$ snmpwalk -v2c -c public 192.168.0.240 mrpDomainRingPort1State
MRP-MIB::mrpDomainRingPort1State.1 = INTEGER: forwarding(4)
MRP-MIB::mrpDomainRingPort2State.1 = INTEGER: blocked(2)

closed = l'anneau est bouclé et le manager bloque volontairement un de ses deux ports d'anneau (blocked) pour éviter la boucle : c'est le fonctionnement normal de MRP. Si un câble d'anneau casse, le manager débloque ce port pour rétablir le chemin, et l'état bascule :

$ snmpwalk -v2c -c public 192.168.0.240 mrpRingState
MRP-MIB::mrpRingState.1 = INTEGER: open(1)

Un anneau open veut dire : la redondance est consommée. Le réseau tient encore (le manager a rebasculé), mais il n'y a plus de secours — la prochaine coupure fait tomber des devices. C'est une alarme à traiter vite, même si « tout marche » en apparence.

ObjetValeur saineInterprétation
mrpRingStateclosed(2)Anneau bouclé, redondance disponible
mrpRingStateopen(1)Maillon rompu, redondance consommée — alarme
rôle (MRM/MRC)MRM sur un seul switchUn seul manager par anneau ; les autres sont clients

Ces mêmes états sont visibles dans l'interface web du Scalance (page « Media Redundancy ») et dans TIA Portal (diagnostic du switch). SNMP n'invente rien de plus — il rend simplement l'information scriptable : tu peux la relever sur les trois switches d'un anneau en une boucle, la journaliser, la comparer d'un jour à l'autre. Là où le web te fait cliquer, le shell te fait snmpwalk.

7. Corréler les deux vues

Tout l'intérêt du chapitre est là : faire converger la vue switch (SNMP) et la vue fil (captures des chapitres 2, 7, 8). Reprenons l'incident du port 3 :

Les deux récits pointent le même coupable : le lien du port 3 vers l'ET 200SP .20 — câble débranché, coupé ou connecteur défaillant. Ni l'une ni l'autre vue ne suffit seule : la capture dit « quelque chose a bougé », le switch dit « c'est le port 3 ». Ensemble, elles localisent la panne au câble près. C'est la méthode qu'on généralisera au chapitre 11.

Quand deux sources indépendantes — une capture sur le fil et l'état interne d'un équipement — désignent le même point, la conclusion est solide. Une seule source peut mentir (un compteur figé, une trame manquée) ; leur recoupement ne ment presque jamais. Cherche toujours à confirmer une hypothèse par une seconde vue avant d'aller débrancher quoi que ce soit.

Récapitulatif

Exercices

Exercice 1 — Dresser le tableau port → état → erreurs

Sur le Scalance 192.168.0.240, relève l'identité (branche system) puis, pour chaque port, son libellé, son état et ses erreurs en réception. Présente le résultat sous forme d'un tableau port → état → erreurs et identifie le(s) port(s) suspect(s).

Voir la solution
$ snmpget -v2c -c public 192.168.0.240 sysName.0 sysDescr.0
SNMPv2-MIB::sysName.0 = STRING: SW-A-MRM
SNMPv2-MIB::sysDescr.0 = STRING: Siemens ... SCALANCE XC208 ... FW: V6.5
$ snmpwalk -v2c -c public 192.168.0.240 ifDescr
$ snmpwalk -v2c -c public 192.168.0.240 ifOperStatus
$ snmpwalk -v2c -c public 192.168.0.240 ifInErrors

En croisant les trois walk par ifIndex :

Port  Libellé              État   ifInErrors
 1    vers CPU S7-1500      up         0
 2    anneau vers SW-B      up         0
 3    vers ET200SP .20     down         -
 4    anneau vers SW-C      up     14802
 5    libre                 down       0
 6    poste diag .71        up         0

Deux anomalies : le port 3 est down (device décroché) et le port 4 accumule des erreurs. Le P5 est down mais libellé « libre » : à ignorer. Reste à savoir si les erreurs du P4 sont anciennes ou actives — c'est l'exercice 2.

Exercice 2 — Un port dont les erreurs augmentent (delta)

Le port 4 affiche 14802 erreurs. Est-ce un vieil incident cicatrisé ou un défaut actif ? Relève le compteur deux fois à 30 secondes d'intervalle, calcule le delta et conclus. Bonus : une seule ligne de shell qui fait le calcul.

Voir la solution
$ a=$(snmpget -v2c -c public -Ovq 192.168.0.240 ifInErrors.4); \
  sleep 30; \
  b=$(snmpget -v2c -c public -Ovq 192.168.0.240 ifInErrors.4); \
  echo "delta = $((b - a)) erreurs en 30 s"
delta = 83 erreurs en 30 s

Le compteur a bougé de 83 en 30 secondes : le défaut est actif, ce n'est pas un résidu. On soupçonne un câble d'anneau abîmé ou une source d'EMI sur le lien P4 (vers SW-C). Si le delta avait été 0, la grande valeur absolue aurait été un simple héritage d'un incident passé — rien à traiter. La leçon : toujours mesurer la dérive. Le -Ovq renvoie la valeur nue, ce qui permet l'arithmétique $((b - a)).

Exercice 3 — État de l'anneau via la MRP-MIB

Au chapitre 8, la capture laissait soupçonner un anneau ouvert. Confirme-le (ou infirme-le) en lisant mrpRingState sur le manager 192.168.0.240. Interprète la valeur et dis ce que cela implique pour la disponibilité de la cellule.

Voir la solution
$ snmpget -v2c -c public -Ovq 192.168.0.240 mrpRingState.1
open(1)

La MRP-MIB tranche le doute : l'anneau est ouvert. La capture du chapitre 8 avait raison — un maillon est rompu et le manager a rebasculé sur son chemin de secours. Conséquence concrète : le réseau fonctionne encore, mais la redondance est consommée. Il n'y a plus de filet : la prochaine coupure de câble fera décrocher des IO-devices. À traiter en priorité, même sans arrêt de production visible. Pour localiser le maillon rompu, on recoupe avec l'exercice 1 (quel port d'anneau est down ou en erreur) et le LLDP du §5.

Si la réponse avait été closed(2), l'anneau serait sain et redondant, et il aurait fallu chercher la cause de l'incident du chapitre 8 ailleurs (un device, pas l'anneau).