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

Chapitre 11
Méthodologie de diagnostic

Objectifs du chapitre

1. Deux stratégies : ascendante et descendante

Tout ce qui précède — la couche physique du chapitre 2, la découverte L2 du chapitre 3, l'IP du chapitre 4, les ports du chapitre 5, le Profinet des chapitres 6-7, le MRP du chapitre 8, l'OPC-UA du chapitre 9 et la supervision du chapitre 10 — n'est utile que si l'on sait dans quel ordre l'employer. Il existe deux manières d'ordonner ces outils, et elles répondent à des situations différentes.

Ascendante (bottom-up) : partir du fil et monter

On commence par la couche physique et on remonte le modèle en couches, une à la fois :

  1. L1 — lien & erreurs (ch. 2) : le port est-il up ? bon débit, bon duplex ? les compteurs d'erreurs montent-ils ?
  2. L2 — découverte (ch. 3) : le voisin est-il vu en LLDP ? répond-il en DCP ? porte-t-il le bon nom de station ?
  3. L3 — IP (ch. 4) : joignable en ping ? pas de doublon d'adresse ?
  4. L4 — ports (ch. 5) : les services attendus sont-ils ouverts ?
  5. Protocole (ch. 6-9) : le cyclique Profinet tourne-t-il ? l'anneau MRP est-il fermé ? la session OPC-UA s'établit-elle ?
  6. Supervision (ch. 10) : que dit le switch de son côté ?

Cette stratégie est fiable quand on ne sait rien : on ne présume d'aucune cause, on valide chaque couche avant de croire à la suivante. Elle est un peu plus longue, mais elle ne saute jamais l'étape qui, précisément, cachait le problème.

Descendante (top-down) : partir du symptôme et redescendre

On part de la plainte applicative — « la station décroche », « le SCADA perd la valeur », « l'axe vibre » — et on redescend vers les couches basses jusqu'à trouver l'endroit qui ne tient pas. Plus rapide quand on a déjà une hypothèse ou un historique (« ça arrive toujours sur ce variateur », « depuis qu'on a rebranché le câble du port 3 »).

Le réflexe le plus coûteux, c'est de sauter les couches basses parce que le symptôme est applicatif. On veut ouvrir Wireshark et décoder du Profinet alors que le vrai problème est un câble ou un duplex mal négocié (ch. 2). Sur le terrain, une large part des « pannes Profinet » signalées sont en réalité des défauts de couche 1 : connecteur RJ45 abîmé, verrou cassé, câble écrasé, auto-négociation partie en half-duplex. En cas de doute, redescends d'un cran.

Les deux stratégies convergent vers le même diagnostic ; elles diffèrent seulement par le point de départ. En pratique on fait souvent un mélange : on démarre descendant (on a un symptôme), mais dès qu'une couche est douteuse on bascule en ascendant à partir d'elle pour ne rien présumer.

2. Établir une base de référence (baseline)

On ne diagnostique bien que ce qu'on connaît sain. La plupart des indicateurs du cours ne veulent rien dire dans l'absolu — ils prennent leur sens par comparaison avec l'état normal. Un compteur ethtool -S à 4 200 erreurs est-il grave ? Impossible de répondre si l'on ne sait pas s'il était à 4 198 hier. Un temps de cycle de 2 ms est-il bon ? Seulement si la machine a été configurée pour 2 ms.

La parade est de relever l'état quand tout va bien, une fois la mise en service terminée, et de l'archiver. C'est cinq minutes de travail qui font gagner des heures le jour de la panne :

# Baseline « installation saine » — à ranger avec la doc de la machine
mkdir -p ~/baseline && cd ~/baseline

# L1 : état des liens et compteurs d'erreurs (attendus à 0 ou stables)
ethtool eth0            > link.txt
ethtool -S eth0         > l1-counters.txt

# L2 : topologie LLDP — qui est le voisin de chaque port
lldpctl                 > topologie.txt

# L3 : inventaire des équipements présents sur le segment
sudo arp-scan --interface=eth0 192.168.0.0/24 > inventaire.txt

# Protocole : endpoints OPC-UA publiés par le serveur
python3 -c "import asyncio,asyncua; ..."       > opcua-endpoints.txt

# Switch : compteurs et état d'anneau via SNMP
snmpwalk -v2c -c public 192.168.0.240 IF-MIB::ifOperStatus > switch-ports.txt

Ta meilleure référence de comparaison, c'est toi-même, hier. Garde une baseline saine par machine — temps de cycle, compteurs d'erreurs à 0, topologie LLDP, endpoints OPC-UA, anneau fermé. Le jour de la panne, un simple diff entre la baseline et la mesure du moment pointe souvent la couche fautive en quelques secondes.

La baseline shell complète la vue TIA Portal, elle ne la remplace pas. TIA te donne la configuration attendue (topologie planifiée, temps de cycle paramétré, noms de station) ; le shell te donne la réalité mesurée sur le fil. Le diagnostic naît du croisement des deux : quand l'attendu et le réel divergent, tu tiens un bout du problème.

3. Cas complet de bout en bout

Mettons la démarche ascendante à l'épreuve d'un cas réaliste.

Symptôme. La station et200sp-2 (192.168.0.21) ne répond plus. Le CPU cpu1500 (192.168.0.1) signale une défaillance de station ; les E/S décentralisées de cette station sont figées.

On ne présume rien. On part du fil et on monte, couche par couche, en notant à chaque étape la commande et son interprétation.

Étape L1 — le lien physique (ch. 2)

Le port de l'edge (ou du switch) qui mène vers la station est-il up ? au bon débit ? les compteurs montent-ils ?

$ ethtool eth0
        Speed: Unknown!
        Duplex: Unknown!
        # ...
        Link detected: no

Verdict immédiat : lien down. Le débit et le duplex sont Unknown, aucune porteuse. Inutile de monter plus haut avant d'avoir compris pourquoi — mais on continue le tour pour corroborer, car un edge peut être branché ailleurs que sur le port fautif.

$ ethtool -S eth0 | grep -Ei 'err|crc|carrier'
     rx_crc_errors: 1832
     rx_errors: 1832
     carrier_changes: 47

Des CRC par milliers et des carrier changes qui grimpent : la couche 1 est malade — câble, connecteur ou duplex. Signature classique d'un lien qui « bat » (up/down répété).

Étape L2 — découverte (ch. 3)

Le voisin est-il encore vu en LLDP ? répond-il à un DCP Identify ?

$ lldpctl | grep -A2 et200sp-2
# ... aucune sortie : le voisin a disparu de la table LLDP

$ sudo python3 -m pnio_dcp identify-all -i eth0
# cpu1500        192.168.0.1
# et200sp-3      192.168.0.22
# (et200sp-2 : pas de réponse)

La station ne répond ni en LLDP ni en DCP — deux mécanismes de couche 2, donc indépendants de l'IP. Cela confirme que le device est coupé en dessous de la couche réseau, et non à cause d'un problème d'adressage. Les autres stations, elles, répondent : le segment vit toujours.

Étape L3 — IP (ch. 4)

$ ping -c3 192.168.0.21
3 packets transmitted, 0 received, 100% packet loss

$ sudo arping -c3 -I eth0 192.168.0.21
# 0 réponses — l'adresse MAC ne répond plus à l'ARP

Injoignable en IP et en ARP. Le arping est ici précieux : s'il avait vu deux MAC différentes répondre, on aurait un doublon d'IP (autre panne classique). Ici, zéro réponse — cohérent avec un device physiquement déconnecté, pas un conflit d'adresse.

Étape L4 — ports (ch. 5)

$ nmap -Pn -p 102,4840 192.168.0.21
Host is down (ou tous les ports filtered)

Sans surprise après L3, mais on le note : le port 102 (S7/Profinet contexte) et 4840 (OPC-UA) sont inaccessibles. Cohérent avec un hôte absent.

Étape Profinet — la capture (ch. 6-7)

$ sudo tshark -i eth0 -f 'ether host 00:1c:06:xx:xx:xx' -a duration:5
# ... plus aucune trame RT vers/depuis la station : cyclique arrêté

Le trafic cyclique vers et200sp-2 est tombé : plus de trames RT, le CycleCounter ne progresse plus et le CPU a levé une alarme de retrait. Le DataStatus des autres stations reste bon (bit Provider State = Run) — la panne est bien localisée à cette station.

Étape MRP — l'anneau (ch. 8)

$ sudo tshark -i eth0 -Y 'mrp' -a duration:3
  0.000  MRP_Test  Ring state: OPEN
  0.020  MRP_TopologyChange
# le manager a détecté une coupure et rerouté

L'anneau est passé OPEN : le Media Redundancy Manager a vu une rupture et a ouvert son port de secours pour rerouter. La redondance a fait son travail (la ligne n'est pas tombée), mais elle nous signale qu'un lien physique a lâché — exactement là où ethtool voyait le lien down.

Étape Switch — SNMP (ch. 10)

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

$ snmpget -v2c -c public 192.168.0.240 IF-MIB::ifInErrors.3
IF-MIB::ifInErrors.3 = Counter32: 1832

Le switch scalance (192.168.0.240) le confirme depuis son point de vue : le port 3 est ifOperStatus down, avec exactement le même compte d'erreurs d'entrée que côté edge. Toutes les mesures pointent le même endroit.

Diagnostic. Le câble du port 3 du switch (celui qui dessert et200sp-2) est défectueux. Faisceau de preuves convergent : ethtool montre le lien down + CRC ; DCP/ARP ne voient plus la station ; nmap la donne down ; le cyclique Profinet s'est arrêté ; MRP a rerouté (anneau OPEN) ; et le switch rapporte ifOperStatus down sur le port 3 avec les mêmes erreurs. Correction : remplacer le cordon du port 3 (ou re-sertir le connecteur). Après échange, on revérifie de bas en haut : lien up, DCP répond, cyclique repart, anneau se referme (CLOSED).

4. L'arbre de décision

La démarche ascendante se résume à une poignée de questions binaires. Tant qu'on répond « oui », on monte d'une couche ; le premier « non » désigne la couche à investiguer — et donne la panne la plus probable.

L1 · le lien est-il up (débit/duplex OK, 0 erreur) ? ethtool / ethtool -S — ch. 2 ▼ oui L2 · le device répond-il en DCP / est-il vu en LLDP ? pnio-dcp / lldpctl — ch. 3 ▼ oui L3 · joignable en IP, sans doublon d'adresse ? ping / arping — ch. 4 ▼ oui Proto · le cyclique Profinet est-il présent ? tshark / nmap — ch. 5-7 ▼ oui MRP · l'anneau est-il fermé (CLOSED) ? tshark 0x88E3 / SNMP — ch. 8, 10 ▼ oui Réseau sain — le problème est applicatif → OPC-UA / logique CPU — ch. 9 câble / duplex RJ45, SFP, half-duplex device HS / mauvais nom station retirée, DCP nok IP / doublon conflit, mauvais masque appairage / alarme AR non établi, module KO anneau ouvert 1 lien coupé, reroutage non ▶ non ▶ non ▶ non ▶ non ▶
Figure 11.1. L'arbre de décision de la démarche ascendante. Chaque « oui » (vert) fait monter d'une couche ; le premier « non » (rouge) désigne la couche fautive et la panne la plus probable, avec le chapitre et la commande de vérification. Un « oui » jusqu'en bas innocente le réseau : le problème est alors applicatif (OPC-UA, logique CPU, ch. 9).

5. Journaliser proprement

Une panne intermittente ne se laisse pas capturer à la demande : le jour où elle survient, on n'est jamais devant l'écran. La parade est de laisser une capture qui tourne en continu vers des fichiers horodatés et en rotation, pour ne jamais saturer le disque.

# tcpdump : un fichier par heure, on garde les 24 derniers (= 1 journée glissante)
sudo tcpdump -i eth0 -w /var/log/pn-%Y%m%d-%H%M%S.pcap -G 3600 -W 24

Variante avec dumpcap (du paquet Wireshark), qui borne par la taille plutôt que par le temps :

# dumpcap : fichiers de ~100 Mo, on en garde 20 (≈ 2 Go au total)
dumpcap -i eth0 -b filesize:100000 -b files:20 -w /var/log/pn.pcap

Quand la panne survient, on ne garde que la tranche horaire concernée pour l'analyser à froid avec tshark -r — sans jamais avoir eu besoin d'être présent au bon moment.

Sur le terrain, trois règles tiennent tout le reste ensemble. Passif d'abord : capture, LLDP et lecture SNMP avant tout scan ou écriture DCP. Une action à la fois : on ne change qu'une chose, puis on re-mesure — sinon on ne saura jamais laquelle a agi. Tracer ce qu'on fait : noter l'heure et la commande de chaque intervention, pour pouvoir revenir en arrière et pour que le collègue de la prochaine équipe comprenne l'état laissé.

6. La checklist réutilisable

Voici le livrable à emporter. Pour chaque symptôme courant, la couche visée, la commande de vérification et ce qu'on cherche dans sa sortie. C'est la traduction, en une page, de tout le cours.

SymptômeCoucheCommande de vérificationCe qu'on cherche
Pas de lien / port mort L1 (ch. 2) ethtool eth0 Link detected: no, débit/duplex Unknown → câble, connecteur, SFP.
Erreurs qui montent, débit dégradé L1 (ch. 2) ethtool -S eth0 | grep -i err rx_crc_errors/carrier_changes qui grimpent, ou half-duplex non voulu.
Station introuvable / mauvais nom L2 (ch. 3) lldpctl · pnio-dcp identify-all Voisin absent de LLDP, pas de réponse DCP, ou nom de station ≠ celui planifié dans TIA.
Équipement injoignable L3 (ch. 4) ping · arping -I eth0 <ip> 0 réponse ICMP mais éventuellement ARP présent → filtrage/route ; 0 ARP → device absent.
Doublon d'adresse IP L3 (ch. 4) arping -D -I eth0 <ip> Deux adresses MAC différentes qui répondent pour la même IP.
Service applicatif absent L4 (ch. 5) nmap -Pn -p 102,4840 <ip> Port attendu closed/filtered → service arrêté ou pare-feu.
Station qui décroche (défaillance) Profinet (ch. 6-7) tshark -i eth0 -Y pn_io Cyclique arrêté, CycleCounter figé, alarme de retrait, DataStatus mauvais.
Jitter / à-coups sur un axe Profinet (ch. 7) tshark -i eth0 -Y pn_rt -T fields -e frame.time_delta Écarts inter-trames irréguliers (le Δt s'éloigne du temps de cycle) → surcharge, boucle, duplex.
Anneau ouvert / redondance perdue MRP (ch. 8) tshark -i eth0 -Y mrp Trames 0x88E3 annonçant Ring state: OPEN + TopologyChange → un lien coupé.
Session OPC-UA refusée Appli (ch. 9) asyncua / lecture des endpoints BadSecurityPolicyRejected, certificat/hôte non approuvé, endpoint absent.
Doute sur l'état côté switch Supervision (ch. 10) snmpwalk … IF-MIB::ifOperStatus ifOperStatus down sur un port, ifInErrors qui monte, état d'anneau.

Récapitulatif

Exercices

Exercice 1 — Ordonner le diagnostic d'un jitter

On te signale un jitter sur un axe : le mouvement a des à-coups, la boucle de position « broute ». Le symptôme est applicatif. Ordonne les étapes de diagnostic (stratégie de ton choix) et donne la commande de chacune. Justifie ton point de départ.

Voir la solution

Un jitter est d'abord une affaire de régularité temporelle — donc on soupçonne la couche 1 et le cyclique, pas l'IP. On peut partir descendant (mesurer d'abord le jitter là où il se voit) puis basculer ascendant dès qu'une couche est douteuse :

  1. Mesurer le jitter (proto) — confirmer le symptôme sur le fil :
    tshark -i eth0 -Y pn_rt -T fields -e frame.time_delta → le Δt inter-trames doit coller au temps de cycle ; s'il varie, le jitter est réel.
  2. L1 — la cause la plus fréquente : ethtool eth0 (duplex !) puis ethtool -S eth0 | grep -i err → un half-duplex ou des CRC expliquent des retards erratiques.
  3. MRP — un anneau qui flappe reroute et introduit du jitter : tshark -i eth0 -Y mrp → chercher des TopologyChange répétés.
  4. Charge / switch — une tempête ou un port saturé : snmpwalk … ifInErrors / ifInOctets pour repérer une surcharge.

On ne commence pas par ping ou nmap : un axe qui bouge est, par définition, joignable. Attaquer par L3/L4 ferait perdre du temps sur des couches déjà saines.

Exercice 2 — La one-liner de capture horodatée en rotation

Écris la commande tcpdump qui capture en continu sur eth0 vers des fichiers horodatés, un par heure, en gardant les 24 derniers. Explique chaque option.

Voir la solution
sudo tcpdump -i eth0 -w /var/log/pn-%Y%m%d-%H%M%S.pcap -G 3600 -W 24
  • -i eth0 : l'interface à écouter (celle sur le segment machine — attention au piège WSL du ch. 1).
  • -w …%Y%m%d-%H%M%S.pcap : le nom du fichier est construit avec strftime, donc daté et unique.
  • -G 3600 : bascule de fichier toutes les 3600 s = 1 heure.
  • -W 24 : borne à 24 fichiers en anneau (le plus ancien est écrasé) → une journée glissante, disque borné.

Pour borner par la taille plutôt que par le temps : dumpcap -i eth0 -b filesize:100000 -b files:20 -w /var/log/pn.pcap (20 fichiers de ~100 Mo). On analyse ensuite à froid la tranche voulue avec tshark -r /var/log/pn-....pcap.

Exercice 3 — Lire la checklist et justifier la couche

Pour chacun de ces deux symptômes, donne la couche visée, la commande de vérification et pourquoi cette couche : (a) « le SCADA affiche une valeur figée sur une variable OPC-UA alors que la machine tourne » ; (b) « depuis un orage, un device Profinet décroche par intermittence ».

Voir la solution

(a) Valeur OPC-UA figée, machine OK. La machine tourne : le Profinet cyclique est donc sain, la panne est plus haut. Couche applicative (ch. 9). On vérifie la session et l'abonnement OPC-UA : asyncua (lecture directe du nœud, état de la subscription). Si la lecture directe donne la bonne valeur mais que le SCADA reste figé, c'est l'abonnement côté SCADA qui est mort, pas le réseau. On ne redescend en L1 que si même la lecture directe échoue.

(b) Device qui décroche par intermittence depuis un orage. « Intermittent » + « depuis un orage » fleure la couche 1 (ch. 2) : connecteur ou port fragilisé, blindage. On laisse tourner une capture en rotation (exercice 2) et on surveille ethtool -S eth0 / snmp … ifInErrors dans le temps. Un décrochage corrélé à une montée de CRC ou à un carrier change confirme le L1 ; on croisera avec tshark -Y mrp pour voir si l'anneau reroute à chaque décrochage. On ne part pas du protocole : l'intermittence et l'historique physique orientent d'emblée vers le bas.