🔌 Diagnostic rĂ©seau OT/IT · au shell Linux

Chapitre 07
Diagnostiquer Profinet

Objectifs du chapitre

1. Le contrat temps réel

Au chapitre 6, on a dissĂ©quĂ© une trame Profinet RT : Ethertype 0x8892, Frame ID, donnĂ©es cycliques, puis le trailer APDU-Status. Ici, on ne regarde plus une trame isolĂ©e mais le flux : est-ce que l'Ă©change respecte son contrat ?

Ce contrat est simple. À la mise en route, le CPU (cpu1500, 192.168.0.1) Ă©tablit avec chaque IO-device une connexion applicative, l'AR (Application Relation). Dans cette AR, chacun s'engage Ă  envoyer sa trame cyclique Ă  intervalle fixe — l'update time, configurĂ© dans TIA (typiquement 1 ms, parfois 250 Â”s ou 4 ms selon la charge). Les deux sens comptent : le device est provider de ses entrĂ©es et consumer des sorties ; le CPU, l'inverse.

Si les trames attendues n'arrivent plus, un watchdog se dĂ©clenche. Sa valeur par dĂ©faut est de 3 cycles manquĂ©s : passĂ© ce dĂ©lai, le consumer dĂ©clare le provider absent, l'AR est dĂ©clarĂ©e perdue, et cĂŽtĂ© CPU cela remonte comme une dĂ©faillance de station. Diagnostiquer Profinet, c'est donc vĂ©rifier deux choses sur le fil : la rĂ©gularitĂ© des cycles et l'absence de perte.

Le watchdog vaut par dĂ©faut 3 Ă— l'update time (« Accepted update cycles without IO data » dans TIA Portal). À 1 ms, il suffit donc de 3 ms sans trame pour que le CPU dĂ©clare la station en dĂ©faut et lĂšve une alarme de « dĂ©faillance de station » (station failure) dans son tampon de diagnostic. C'est court : un micro-dĂ©faut de cĂąble suffit. Le shell, lui, mesure ces millisecondes sur le fil.

2. Mesurer le temps de cycle depuis une capture

La mĂ©thode ne varie jamais : on isole le cyclique d'un seul device — par sa MAC source et le filtre pn_rt — puis on regarde le temps qui sĂ©pare deux trames consĂ©cutives. Prenons et200sp-1 (MAC 00:1b:1b:2a:10:20). D'abord on capture le flux Profinet brut (Ethertype 0x8892), puis on relit hors-ligne :

sudo tshark -i eth0 -f 'ether proto 0x8892' -w pn.pcap
tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' \
       -T fields -e frame.time_delta_displayed -e pn_rt.cycle_counter

Le champ frame.time_delta_displayed donne l'Ă©cart de temps avec la trame prĂ©cĂ©dente du mĂȘme affichage filtrĂ© — donc, comme on a filtrĂ© sur une seule MAC source, l'Ă©cart entre deux trames cycliques de ce device. C'est la mesure directe du temps de cycle. Sur un Ă©change sain Ă  1 ms :

# deltas (s) et cycle_counter — Ă©change sain Ă  1 ms
0.001004   12480
0.000998   12512
0.001001   12544
0.000999   12576
0.001003   12608
0.000997   12640

Les deltas oscillent autour de 0,001 s — un mĂ©tronome. Le cycle_counter progresse d'un pas rĂ©gulier (ici +32, on y revient au §3). Maintenant, un Ă©change qui hoquette :

# mĂȘme device, mais un trou
0.001002   13120
0.000999   13152
0.004013   13248
0.001001   13280
0.000998   13312

Le delta de 0,004 s saute aux yeux : quatre fois le cycle. Trois trames ont manquĂ© sur le fil (le device aurait dĂ» Ă©mettre Ă  +1, +2 et +3 ms). On le confirme au compteur : il bondit de 13152 Ă  13248, soit +96 au lieu de +32 — trois pas d'un coup. À 1 ms, un tel trou frĂŽle dĂ©jĂ  le seuil du watchdog : une ou deux trames de plus, et l'AR tombait.

Le jitter, c'est prĂ©cisĂ©ment la dispersion de ces deltas autour de la consigne. Un Ă©change sain a un jitter de quelques microsecondes ; un jitter qui grimpe (deltas qui varient de 0,8 Ă  1,3 ms sans trame perdue) trahit un problĂšme de transport — un port saturĂ©, un switch qui peine, ou pire, un lien tombĂ© en half-duplex (§piĂšge).

Le delta d'inter-arrivĂ©e d'un device filtrĂ© sur sa MAC, c'est son temps de cycle rĂ©el, mesurĂ© sur le fil. Tu n'as pas besoin de connaĂźtre la config TIA pour le trouver : capture, filtre, lis la colonne. Si le delta mĂ©dian vaut 1 ms, l'update time est Ă  1 ms. La capture ne ment pas ; l'ingĂ©nierie, parfois.

Un seul one-liner pour sortir cycle moyen, min et max d'un device — pratique pour juger la rĂ©gularitĂ© d'un coup :

$ tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' \
      -T fields -e frame.time_delta_displayed \
    | awk 'NR>1{n++;s+=$1;if($1>mx)mx=$1;if(mn==""||$1<mn)mn=$1}
           END{printf "cycle moyen=%.4f ms  min=%.4f  max=%.4f  (n=%d)\n",s/n*1000,mn*1000,mx*1000,n}'
cycle moyen=1.0010 ms  min=0.9970  max=4.0130  (n=4192)

Le max trÚs supérieur à la moyenne pointe le trou. On saute la premiÚre ligne (NR>1) car son delta n'a pas de trame précédente.

3. Le CycleCounter : compter les trames perdues

Le delta de temps te dit qu'il manque des trames ; le CycleCounter te dit combien, sans ambiguĂŻtĂ©. Ce compteur voyage dans l'APDU-Status de chaque trame RT (chapitre 6). Il s'incrĂ©mente d'un pas fixe Ă  chaque cycle, en unitĂ©s de 1/32 de milliseconde — soit 31,25 Â”s. À un update time de 1 ms, le pas normal est donc de 32 (1 ms Ă· 31,25 Â”s). Il est codĂ© sur 16 bits : il boucle de 65535 Ă  0, ce dont il faut tenir compte au calcul.

La rĂšgle est limpide : entre deux trames consĂ©cutives d'un mĂȘme provider, le compteur augmente du pas nominal. Un saut supĂ©rieur au pas = des trames perdues sur le fil. Le nombre de trames manquĂ©es vaut :

trames_perdues = (Δcompteur / pas_nominal) − 1

Reprenons la sĂ©quence hoquetante du §2 et calculons les Ă©carts du compteur avec awk :

$ tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' \
      -T fields -e pn_rt.cycle_counter \
    | awk 'NR>1{d=$1-p; if(d<0)d+=65536; if(d!=32) printf "saut de %d (=%d cycles) apres cc=%d\n",d,d/32,p} {p=$1}'
saut de 96 (=3 cycles) apres cc=13152

Un seul saut dĂ©tectĂ© : +96, soit 3 cycles au lieu d'1 → 2 trames perdues entre les deux trames vues (la 3ᔉ est celle qu'on a reçue). Le if(d<0)d+=65536 gĂšre le rebouclage du compteur 16 bits. Additionne tous les sauts sur une capture longue et tu obtiens le total de trames perdues sur l'intervalle — une mĂ©trique de santĂ© bien plus parlante qu'un ressenti « ça rame ».

Deux compteurs Ă  ne pas confondre. Le CycleCounter est une horloge : il avance du temps Ă©coulĂ© (pas de 32 Ă  1 ms), donc un saut mesure des trames manquĂ©es. Le champ DataStatus, lui, porte des bits d'Ă©tat (§4), pas un dĂ©compte. Le premier dit « combien j'en ai ratĂ© », le second « est-ce que ce que je reçois est valable ».

4. Le DataStatus : provider, consumer, validité

Chaque trame RT porte un octet DataStatus (dans l'APDU-Status) qui rĂ©sume l'Ă©tat de l'Ă©metteur. tshark le dĂ©code ; on lit soit l'octet brut, soit le dĂ©tail avec -V :

# l'octet brut, trame par trame
tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' \
       -T fields -e frame.number -e pn_rt.data_status

# le détail bit à bit d'une trame
tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' -V | grep -A8 'DataStatus'

Les bits qui comptent pour le diagnostic :

BitNomSainCe qu'il signale sinon
0State (Run/Stop)1 = Run0 = le provider (CPU ou device) est Ă  l'arrĂȘt
1Redundancy0/1rĂŽle dans un couple redondant (S2/R1)
2DataValid1 = valide0 = donnĂ©es non valables — le provider ne garantit plus ses donnĂ©es
4ProviderState1 = Primary0 = Backup — cette trame n'est pas la source active
5StationProblem0 = OK1 = problĂšme — un module/sous-module du device est en dĂ©faut

Deux rĂ©flexes. Un DataValid=0 dit que le provider a lui-mĂȘme dĂ©clarĂ© ses donnĂ©es inexploitables (module manquant, sous-module non prĂȘt) — le consumer les ignorera. Un StationProblem=1 (aussi appelĂ© le bit d'Ă©tat de station, ou Ident) est le signal « regarde mon diagnostic » : le device signale qu'un de ses modules a un souci, et il Ă©mettra une alarme (§5) pour dire lequel. Sur l'Ă©change sain, on lit typiquement un DataStatus Ă  0x35 (Run + DataValid + Primary, StationProblem Ă  0). DĂšs que le bit 5 passe Ă  1, la valeur change et le device est sur le point de lever une alarme — ou vient de le faire.

Tu n'as pas besoin de mĂ©moriser l'octet. Filtre directement sur le bit dĂ©codĂ© : par exemple -Y 'pn_rt.data_status.station_problem == 1' ne te sort que les trames oĂč une station crie au secours, ou -Y 'pn_rt.data_status.data_valid == 0' pour les donnĂ©es rĂ©putĂ©es mauvaises. C'est le moyen le plus rapide de savoir « qui va mal » dans une grosse capture.

5. Détecter une station qui décroche

C'est le scĂ©nario roi de ce chapitre. Une station perd le contact — cĂąble qui bouge, module qui grille, alimentation qui flĂ©chit — et il faut le lire dans la capture. La sĂ©quence a une signature reconnaissable, toujours la mĂȘme :

  1. Le cyclique du device s'arrĂȘte : plus de trames pn_rt de sa MAC (ou DataStatus qui bascule juste avant).
  2. Une ou plusieurs trames d'alarme (pn_alarm) partent : « module retirĂ© », « port en dĂ©faut », « diagnostic apparu ».
  3. Le watchdog du CPU expire (3 cycles) et la station est déclarée en défaut.
  4. Le CPU tente de rĂ©tablir l'AR : un nouveau DCP identify multicast pour retrouver le device par son nom, puis un Connect pour rouvrir la connexion (exactement le mĂ©canisme du chapitre 6).
t → cyclique sain · 1 ms TROU — trames manquantes watchdog (3× cycle) ⚠ alarme pn_alarm DCP identify + Connect le CPU rĂ©tablit l'AR reprise
Figure 7.1. La signature d'un dĂ©crochage sur l'axe du temps. Le cyclique rĂ©gulier (teal) s'interrompt : c'est le trou. PassĂ© le watchdog, une alarme (ambre) part, puis le CPU relance un DCP identify + Connect (vert) pour retrouver et reconnecter le device. Retrouver cette forme dans une capture, c'est diagnostiquer un dĂ©crochage.

Pour lire la sĂ©quence, on ne filtre plus une MAC mais on trie par le temps et on regarde les trois familles ensemble. Les alarmes d'abord :

$ tshark -r pn.pcap -Y pn_alarm \
      -T fields -e frame.time_relative -e eth.src -e pn_alarm.alarm_type
2.418500   00:1b:1b:2a:10:20   0x0002   # diagnosis appears — et200sp-1
2.418700   00:1b:1b:2a:10:20   0x0006   # module pulled / removed

On voit et200sp-1 lever une alarme « module retirĂ© » Ă  t=2,4188 s. On zoome alors sur la fenĂȘtre autour de cet instant, toutes familles Profinet confondues, pour reconstituer l'histoire :

$ tshark -r pn.pcap -Y 'frame.time_relative > 2.41 && frame.time_relative < 2.60' \
      -T fields -e frame.time_relative -e eth.src -e _ws.col.Protocol -e _ws.col.Info
2.415000  00:1b:1b:2a:10:20  PNIO   RTC1, Len:40  # derniere trame cyclique du device
2.418500  00:1b:1b:2a:10:20  PNIO   Alarm, DiagnosisAppears
2.418700  00:1b:1b:2a:10:20  PNIO   Alarm, ModulePulled
2.421000  00:1b:1b:2a:10:01  PNIO   ... plus aucune trame RT de .20
2.540000  00:1b:1b:2a:10:01  PN-DCP Ident Req "et200sp-1"  # le CPU cherche le device
2.560000  00:1b:1b:2a:10:20  PN-DCP Ident Ok                # il repond → Connect suit

Tout y est : la derniĂšre trame cyclique Ă  2,415 s, l'alarme Ă  2,4185 s, le silence du device, puis Ă  2,54 s le CPU (00:1b:1b:2a:10:01) qui relance un DCP Ident Req ciblant le nom « et200sp-1 », auquel le device finit par rĂ©pondre. La reconnexion s'enchaĂźne (Connect, cf. chapitre 6). Tu viens de diagnostiquer un dĂ©crochage sans jamais ouvrir TIA.

Un jitter qui explose ou des trames perdues par rafales, sans que le device tombe vraiment, trahit souvent un problĂšme de couche basse : un lien qui a nĂ©gociĂ© en 100 Mbit half-duplex au lieu de full. En half-duplex, les collisions et le CSMA/CD retardent les trames de façon erratique — le temps rĂ©el Profinet ne le supporte pas. Ne reste pas bloquĂ© sur Profinet : boucle sur le chapitre 2 (ethtool) et vĂ©rifie duplex, dĂ©bit et compteurs d'erreurs FCS/CRC du port. La cause d'un « problĂšme Profinet » est trĂšs souvent en L1/L2.

6. Statistiques rapides

Avant de plonger trame par trame, deux vues d'ensemble te disent en une commande oĂč regarder. D'abord, le dĂ©bit de trames RT par seconde : un Ă©change sain est parfaitement plat (autant de trames chaque seconde) ; un dĂ©crochage creuse un trou visible :

$ tshark -r pn.pcap -q -z io,stat,1,pn_rt
=================================================
| IO Statistics                                 |
| Interval: 1 s   |   Filter: pn_rt             |
|-----------------|-----------------------------|
| Interval        |            pn_rt   Frames   |
|-----------------|-----------------------------|
|   0 <> 1        |                     4000    |
|   1 <> 2        |                     4000    |
|   2 <> 3        |            3120    # ← le trou : ~880 trames en moins |
|   3 <> 4        |                     3000    # .20 muet, l'AR pas encore reprise |
|   4 <> 5        |                     4000    # reconnecte |
=================================================

La seconde 2→3 pique du nez : c'est lĂ  que le device a dĂ©crochĂ©. On sait maintenant quand zoomer (§5). Ensuite, qui parle Ă  qui — les conversations Ethernet :

$ tshark -r pn.pcap -q -z conv,eth
================================================================================
Ethernet Conversations
                                       |  Frames  |   Bytes  |
00:1b:1b:2a:10:01 <-> 00:1b:1b:2a:10:20   15980    1.2 MB   # cpu1500 ↔ et200sp-1
00:1b:1b:2a:10:01 <-> 00:1b:1b:2a:10:21   19998    1.5 MB   # cpu1500 ↔ et200sp-2 (intact)
================================================================================

Les deux stations devraient afficher un nombre de trames quasi identique. et200sp-1 (.20) en a nettement moins que et200sp-2 (.21) : c'est bien .20 qui a perdu des trames. En un coup d'Ɠil, on a isolĂ© la station coupable et confirmĂ© que sa voisine, elle, est saine.

Un device qui ne se connecte jamais (aucune trame cyclique dĂšs le dĂ©part, jamais d'AR) n'est pas forcĂ©ment en panne : c'est souvent un nom de station erronĂ© (name mismatch). Le CPU cherche « et200sp-1 » par DCP, mais le device s'appelle autrement (ou rien) → il ne le reconnaĂźt pas et ne le connecte pas. VĂ©rifie le nom rĂ©el du device par DCP (chapitre 3, pnio-dcp) et compare-le Ă  celui attendu dans le projet. « Il est bien branchĂ© mais absent du rĂ©seau » = suspecte le nom avant le matĂ©riel.

Récapitulatif

Exercices

Exercice 1 — Temps de cycle, jitter, trames sautĂ©es

On t'a fourni les deltas d'inter-arrivĂ©e (en secondes) du device et200sp-2 (00:1b:1b:2a:10:21), extraits d'une capture : 0.000998, 0.001003, 0.001001, 0.002015, 0.000999, 0.001002. Quel est l'update time configurĂ© ? Y a-t-il des trames perdues, et combien ? Le jitter te paraĂźt-il inquiĂ©tant ? Écris la commande qui aurait produit ces deltas.

Voir la solution

Cinq deltas sur six tournent autour de 0,001 s → l'update time est de 1 ms. Le delta isolĂ© de 0.002015 vaut ≈ 2× le cycle : une trame a Ă©tĂ© sautĂ©e Ă  cet instant (2 cycles Ă©coulĂ©s = 1 trame manquĂ©e). Le jitter sur les cycles sains va de 0,998 Ă  1,003 ms, soit ±5 Â”s : nĂ©gligeable, rien d'inquiĂ©tant cĂŽtĂ© transport — c'est une perte ponctuelle, pas une dĂ©gradation continue. La commande d'extraction :

$ tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:21' \
      -T fields -e frame.time_delta_displayed

Si tu veux confirmer sans compter Ă  la main, ajoute -e pn_rt.cycle_counter : le pas passerait de 32 Ă  64 sur la trame en dĂ©faut.

Exercice 2 — Suivre le CycleCounter et compter les pertes

Sur un intervalle, le cycle_counter de et200sp-1 a pris successivement les valeurs : 65472, 65504, 28, 60, 156, 188. L'update time est 1 ms (pas nominal = 32). Combien de trames ont Ă©tĂ© perdues au total ? Attention au rebouclage. Écris un awk qui compte automatiquement les trames perdues sur toute une capture.

Voir la solution

On calcule chaque Ă©cart, en corrigeant le rebouclage 16 bits (+65536 si nĂ©gatif) :

  • 65504 − 65472 = 32 → 1 cycle, RAS.
  • 28 − 65504 = −65476, +65536 = 60 → pas 32 ! 60/32 ≈ presque 2 cycles. En fait le compteur avance du temps rĂ©el Ă©coulĂ© ; 60 ≈ 2×32 moins le passage de boucle — arrondi, cela vaut 2 cycles, soit 1 trame perdue.
  • 60 − 28 = 32 → RAS.
  • 156 − 60 = 96 = 3 cycles → 2 trames perdues.
  • 188 − 156 = 32 → RAS.

Total : 3 trames perdues sur l'intervalle. Le passage Ă  zĂ©ro (65504 → 28) n'est pas une perte en soi — c'est le rebouclage normal du compteur, qu'il faut corriger sous peine de compter un saut gĂ©ant. Le script gĂ©nĂ©ralisĂ© :

$ tshark -r pn.pcap -Y 'pn_rt && eth.src==00:1b:1b:2a:10:20' \
      -T fields -e pn_rt.cycle_counter \
    | awk 'NR>1{d=$1-p; if(d<0)d+=65536; lost+=(d/32)-1}
           {p=$1} END{printf "trames perdues (total) = %d\n", lost}'
trames perdues (total) = 3

On somme (d/32)−1 Ă  chaque pas : 0 quand le cycle est nominal, positif dĂšs qu'il y a un saut. Sur une capture rĂ©elle, ce chiffre unique est un excellent indicateur de santĂ©.

Exercice 3 — Reconstituer un dĂ©crochage

Une capture pn.pcap couvre une ligne qui « s'est arrĂȘtĂ©e » vers la 12ᔉ seconde. Reconstitue la chronologie de l'incident : repĂšre la station qui dĂ©croche, l'instant de l'arrĂȘt cyclique, l'alarme Ă©mise, et la tentative de reconnexion du CPU. Puis dis quelles couches tu vĂ©rifierais ensuite pour trouver la cause racine.

Voir la solution

1) Localiser le trou et la station. Une vue d'ensemble situe l'instant, une conversation dĂ©signe le coupable :

$ tshark -r pn.pcap -q -z io,stat,1,pn_rt   # trou à l'intervalle 12→13
$ tshark -r pn.pcap -q -z conv,eth          # .20 a bien moins de trames que .21

2) Zoomer sur la fenĂȘtre, toutes familles Profinet, triĂ©es par le temps :

$ tshark -r pn.pcap -Y 'frame.time_relative > 11.9 && frame.time_relative < 12.8' \
      -T fields -e frame.time_relative -e eth.src -e _ws.col.Info
11.980  00:1b:1b:2a:10:20  RTC1 ...            # derniere trame cyclique de .20
11.984  00:1b:1b:2a:10:20  Alarm, ModulePulled # l'alarme
12.100  00:1b:1b:2a:10:01  PN-DCP Ident "et200sp-1"  # le CPU cherche
12.140  00:1b:1b:2a:10:20  PN-DCP Ident Ok     # reprise de l'AR

Chronologie : et200sp-1 (.20) Ă©met sa derniĂšre trame cyclique Ă  11,980 s, lĂšve une alarme « module retirĂ© » 4 ms plus tard (au-delĂ  du watchdog), reste muet, puis le CPU relance un DCP identify sur son nom Ă  12,100 s et le reconnecte.

3) Couches Ă  vĂ©rifier ensuite. L'alarme « module retirĂ© » oriente vers le matĂ©riel du device (un module mal enclenchĂ©, une alim). Mais avant de conclure, on boucle sur les couches basses : L1/L2 avec ethtool sur le port concernĂ© (duplex, dĂ©bit, compteurs FCS/CRC — chapitre 2) pour Ă©carter un lien half-duplex ou un cĂąble douteux, et on confirme que le nom de station est correct (chapitre 3) au cas oĂč le device rejoue mal sa reconnexion. Si tout est propre en L1/L2, la cause est bien l'Ă©vĂ©nement matĂ©riel signalĂ© par l'alarme.