Zoom sur Modbus TCP/IP

Selon une étude récente, réalisée par ARC Advisory Group, Modbus TCP est le protocole Ethernet Industriel le plus utilisé au monde. Modbus TCP est la variante "encapsulée" dans TCP/IP du protocole Modbus. Petit rappel. Selon une étude récente, réalisée par l’analyste américain ARC Advisory Group, Modbus TCP est le protocole Ethernet Industriel le plus utilisé au monde, avec plus de cent cinquante mille produits compatibles installés aux quatre coins du globe. Modbus TCP est la variante « encapsulée » dans TCP/IP du désormais célèbre protocole Modbus, introduit en 1979 par la société Modicon. Aujourd’hui standard géré par l’organisation Modbus IDA, Modbus TCP a récemment été approuvé par l’IEC en tant que spécification ouverte au public. Cet engouement pour Modbus TCP est particulièrement prometteur étant donné les prévisions faites par ARC concernant l’évolution mondiale du marché d’Ethernet Industriel au cours des cinq prochaines années. Selon l’analyste américain, ce marché devrait croître de 51.4% par an durant cette période, passant de 840 000 unités en 2004, à plus de 6.7 millions d’unité d’ici à 2009 ! Le protocole Modbus Série est populaire depuis longtemps dans le monde des automatismes. Plus d’un million de produits Modbus sur liaison série ont été installés à ce jour dans le monde, et un grand nombre de passerelles avec les diverses variantes d’Ethernet existent déjà. Ajoutez à cela le fait que les spécifications de Modbus TCP sont téléchargeables gratuitement sur Internet, et qu’il existe un grand nombre d’implémentations open source du protocole. Vous comprendrez alors sans mal les raisons du succès de Modbus TCP. Le but de cet article est de décrire le fonctionnement du service de messagerie Modbus TCP. Basé sur un mode de communication client/serveur, celui-ci permet d’échanger des informations en temps réel entre différents produits d’automatismes sur Ethernet TCP/IP. Il convient de préciser que la notion de temps réel est ici entendue au sens « mou », car si avec des temps de réponse variant entre 0.2 et 1 seconde, Modbus TCP couvre une grande partie des besoins, notamment pour des applications où l’information est centralisée (entrées/sorties déportées), il ne constitue pas une solution idéale pour des applications d’automatismes distribués nécessitant des temps de réponse beaucoup plus faibles (jusqu’à quelques micro-secondes dans le cas du contrôle de mouvements). Notons toutefois qu’il existe des manières d’améliorer les performances de Modbus TCP, mais nous ne nous attarderons pas sur ce point ici. Figure 1 : Architecture de communication Modbus TCP/IP Description du protocole Un système de communication basé sur Modbus TCP/IP peut mettre en jeu différents types d’équipements : des clients et des serveurs Modbus TCP/IP, bien entendu, mais également du matériel d’interconnexion (ponts, routeurs ou passerelles) assurant le lien entre le réseau TCP/IP et une ou plusieurs liaisons Modbus Série, sur lesquelles sont connectés différents terminaux Modbus. Le protocole Modbus définit une « unité de données de protocole », ou PDU pour Protocol Data Unit, indépendante des couches de communication sous-jacentes. Le mapping du protocole Modbus sur des bus spécifiques ou des réseaux peut introduire des champs supplémentaires au niveau de l’unité de donnée d’application, ou ADU pour Application Data Unit. C’est le client qui initie la transaction Modbus qui construit l’ADU. Le champ Function Code du PDU indique au serveur le type d’action à mener. Figure2-3 : Description générale d’une trame Modbus (en haut). Trame Modbus TCP/IP (en bas) Dans le cas d’un mapping sur TCP/IP, une entête spécifique baptisée « MBAP Header » est utilisée pour identifier l’ADU Modbus. Cette entête possède quelques spécificités qui permettent de différencier l’ADU Modbus TCP/IP de l’ADU Modbus RTU, utilisée en liaison série. L’adresse esclave traditionnellement utilisée avec Modbus Série est remplacée par un octet baptisé « Unit Identifier ». Celui-ci permet la communication au travers de ponts, de routeurs ou de passerelles utilisant une adresse IP unique pour supporter plusieurs terminaux Modbus indépendants. Toute demande ou réponse Modbus est conçue de façon à ce que le récepteur soit en mesure de vérifier que le message est bien terminé. Dans le cas de PDU de longueur fixe, le champ Function Code apporte toutes les informations nécessaires. Ce n’est pas le cas, en revanche, lorsque le PDU transporte une quantité variable de données. Dans ce cas, le champ réservé aux données inclut un compteur d’octets. Par ailleurs, des informations supplémentaires concernant la longueur des messages sont incluses dans l’entête MBAP pour permettre au récepteur de reconnaître les limites des messages, lorsque ceux-ci ont été découpés en plusieurs morceaux pour la transmission. L’existence de règles à la fois explicites et implicites concernant la longueur des messages, combinée avec l’utilisation d’un code de contrôle de redondance cyclique CRC-32 résulte en une probabilité infinitésimale que des paquets défectueux puissent passer inaperçus. Description Fonctionnelle Figure 4 :Architecture conceptuelle d’un service de messagerie Modbus TCP Parmi les principales fonctions implémentées par un service de messagerie Modbus TCP figurent l’établissement et la terminaison des communications, ainsi que la gestion des flots de données parcourant les connexions TCP établies. La communication entre un client et un serveur Modbus requiert la mise en place d’un système de gestion des connexions TCP. Deux options sont envisageables : soit c’est l’application qui se charge de cette tâche, auquel cas le programmeur doit posséder un certain niveau de connaissances des mécanismes TCP/IP, soit cette gestion est réalisée au travers d’un module dédié, baptisé TCP Connection Management, inclus au niveau de la couche TCP Management de l’architecture composant Modbus. Dans ce cas, la gestion des connexions devient totalement transparente pour l’application, qui se contente d’envoyer et recevoir les messages Modbus. Cette seconde solution entraîne toutefois une baisse de la flexibilité. Dans certains contextes critiques, l’accès aux données internes des équipements doit être interdit aux hôtes indésirables. C’est pourquoi un module de contrôle d’accès (Access Ctl) peut être implémenté si nécessaire. Pour permettre l’établissement des connexions et l’échange de données entre équipements, le service de messagerie Modbus TCP doit fournir une socket d’écoute sur le port 502. Il est important de noter que le port d’écoute 502 TCP est réservé aux communications Modbus. Par défaut, l’écoute est obligatoire sur ce port. Cela étant, il arrive que certaines applications exigent qu’un autre port soit dédié aux communications Modbus TCP. C’est la raison pour laquelle il est fortement recommandé que clients et serveurs soient capables de paramétrer le numéro de port Modbus TCP. Toutefois, même dans le cas où un port spécifique a été désigné, le port 502 doit rester disponible. Pour échanger des données avec un serveur distant, le service de messagerie établit une nouvelle connexion entre un port client et le port 502 du serveur distant. Le numéro de port client local doit être supérieur à 1024, et différent pour chaque connexion. Si le nombre de connexions client et serveur est supérieur au nombre de connexions autorisées, la plus ancienne connexion non utilisée est fermée. Les mécanismes de contrôle d’accès peuvent par ailleurs être activés pour vérifier que les adresses IP des clients distants sont bien autorisées. Si ce n’est pas le cas, la nouvelle connexion est refusée. Notons qu’il appartient à l’utilisateur de fournir une liste d’adresses IP, spécifiant lesquelles sont autorisées et lesquelles ne le sont pas. Par défaut, lorsque le mode de sécurité est activé, les adresses IP non-configurées par l’utilisateur sont interdites d’accès. Figure 7 : Diagramme d’activité d’un module de gestion des connexions TCP Le module TCP Connection Management possède une interface (en général de type BSD Socket) lui permettant de communiquer avec la couche TCP/IP (TCP/IP Stack). Celle-ci peut être paramétrée de façon à adapter le contrôle du flot de données, la gestion des adresses ainsi que la gestion des connexions aux contraintes propres à un produit ou à un système. Pour équilibrer les flots de données entrant et sortant entre clients et serveurs Modbus, des mécanismes de contrôle sont mis en œuvre à tous les niveaux de l’architecture de messagerie Modbus TCP. Le module de gestion des ressources et de contrôle de flot (Ressource Management&Flow Control) met en œuvre un contrôle de flot interne à la couche TCP/IP, auquel viennent s’ajouter d’autres contrôles au niveau des couches liaison de données et application. Client/Serveur Modbus Un équipement Modbus peut intégrer à la fois un module client et un module serveur, mais cela ne revêt pas un caractère obligatoire. Un équipement peut très bien n’intégrer qu’un seul de ces deux services. Un module client Modbus permet à une application quelconque de contrôler de façon explicite les informations échangées avec un équipement distant au travers d’une connexion Modbus. Le module client Modbus construit une requête sur la base des informations transmises par l’application au travers de l’interface client Modbus. Cette interface fournit une API (Application Programming Interface) permettant à l’application de construire des requêtes pour accéder à différents services Modbus. Un client Modbus utilise une transaction Modbus, dont la gestion inclus l’attente et le traitement de confirmations Modbus. La construction d’une requête par le client Modbus, suite à la réception d’une demande émanant de l’application, peut être subdivisée en plusieurs sous-tâches. Tout d’abord, le client instancie une transaction Modbus. Cela lui permet de mémoriser l’ensemble des informations qui lui seront par la suite nécessaires lors de la réception de la réponse du serveur. Après avoir instancié la transaction, le client Modbus procède à l’encodage de la requête (entête MBAP + PDU). L’entête MBAP contient notamment les champs Transaction Identifier et Unit Identifier. Le premier sera utilisé par le serveur pour associer sa future réponse avec la bonne requête. Attention, le Transaction Identifier doit posséder un caractère unique à un instant donné. L’Unit Identifier est, quant à lui, fixé à 0xFF. Il est à noter que ce champ, normalement utilisé pour des questions de routage, est inutile sur TCP/IP, puisque le serveur est désigné par son adresse IP. C’est la raison pour laquelle l’adresse IP de destination doit également être transmise par le client, en plus de l’ADU Modbus. Figure 11 : Diagramme d’activité d’un Client Modbus Un module serveur Modbus est, quant à lui, chargé de recevoir les requêtes et de mettre en œuvre des actions (de lecture et d’écriture notamment) afin d’y répondre. L’exécution de ces actions est réalisée de façon totalement transparente pour le programmeur de l’application. Les fonctions principales d’un serveur Modbus sont l’attente de requêtes sur le port 502 TCP, ainsi que le traitement de ces requêtes et la construction de réponses Modbus en fonction du contexte dans lequel se trouve l’équipement. Entre le module serveur Modbus et l’application on peut également trouver une interface baptisée Modbus Backend, qui permet un accès indirect aux objets de l’application. Un serveur Modbus peut accepter de traiter simultanément plusieurs requêtes. Le nombre de ces requêtes varie entre 1 et 16 en fonction des paramètres de conception, ainsi que des capacités de traitement et de mémoire du serveur. Ce nombre constitue l’une des principales grandeurs caractéristiques d’un serveur Modbus. En effet, celui-ci influe de façon significative sur son comportement et sur ses performances. Plus précisément, le nombre de transactions Modbus traitées simultanément affecte les temps de réponse d’un serveur aux requêtes Modbus. A la réception d’une requête, le serveur analyse l’entête MBAP de l’ADU Modbus. Si celle-ci correspond bien à une entête Modbus, une transaction Modbus est instanciée. Dans le cas où le nombre maximum de transactions simultanée autorisé est dépassé, le serveur construit une réponse d’exception (Exception Code 6 : Server Busy). Dans le cas contraire, une transaction est instanciée et initialisée avec les informations suivantes : l’identifiant de la connexion TCP utilisée (fournie par le module TCP Management), l’ID de la transaction Modbus (contenu dans l’entête MBAP) et l’Unit Identifier (contenu également dans l’entête MBAP). Ensuite, c’est au tour du champ PDU d’être analysé. Si celui-ci est reconnu comme un champ valide, le serveur est prêt à exécuter le service demandé. L’exécution de ce service peut être réalisée de différentes manières en fonction de l’architecture matérielle et logicielle de l’équipement. Par exemple, dans le cas d’un équipement compact ou d’une architecture « mono-thread », dans laquelle le serveur Modbus peut accéder directement aux données de l’application sans passer par le service Backend, le service demandé peut être exécuté de façon locale par le serveur lui-même. Au contraire, dans le cas d’un équipement modulaire multi-processeur ou d’une architecture « multi-thread », pour lesquels les couches Communication et Application sont deux entités parfaitement distinctes, certaines tâches triviales pourront être exécutées par la première tandis que d’autres nécessiteront l’intervention de la seconde au travers de l’interface Backend. Différentes stratégies, non équivalentes du point de vue des temps de réponse atteints, du débit réseau ou encore de l’utilisation de la bande passante de l’interface, peuvent être adoptées pour l’implémentation du Service Backend. Celui-ci utilisera l’interface la mieux appropriée en fonction de l’application : une interface physique basée sur une liaison série, un block de mémoire RAM double-port, une simple ligne d’entrées/sorties, ou encore une interface logicielle basée sur un service d’échange de messages fournit par un OS. Cette interface peut être synchrone ou asynchrone. Le service Modbus Backend a la responsabilité d’implémenter le protocole de transcription permettant au serveur Modbus d’interagir avec l’application. Pour cela, il se peut qu’il ait à mettre en œuvre des mécanismes de fragmentation / reconstruction de paquets, de synchronisation des données, etc. Figure 15 : Diagramme d’activité d’un serveur Modbus Une fois que la requête a été traitée, le serveur Modbus construit une réponse qu’il doit ensuite envoyer au module TCP Management. En fonction du résultat du traitement, deux types de réponses sont envisageables : une réponse positive ou une réponse d’exception, dont l’objectif est de fournir au client des informations concernant les erreurs détectées durant le traitement de la requête. Le PDU de la réponse Modbus doit être préfixé d’une entête MBAP construite à partir des informations contextuelles mémorisées lors de la réception de la requête : Unit Identifier, Protocol Identifier et Transaction Identifier. Le serveur renseigne également le champ « Length », indiquant la longueur du champs PDU+Unit Identifier. Enfin, la réponse Modbus est envoyée au client en utilisant la connexion mémorisée. A la réception de la réponse, le client Modbus utilise le Transaction Identifier pour retrouver la requête correspondante, précédemment envoyée sur la connexion TCP. Si celui-ci ne correspond à aucune requête connue du client, la réponse est ignorée et mise au rebut. Dans le cas contraire, la réponse est analysée et utilisée par le client Modbus pour construire la confirmation qui sera ensuite envoyée à l’application. L’analyse de la réponse consiste à vérifier l’entête MBAP ainsi que le PDU de la réponse Modbus. Si celle-ci provient d’un serveur Modbus directement connecté au réseau TCP/IP, l’identification de la connexion TCP utilisée est suffisante pour identifier le serveur distant sans aucune ambiguïté. Dans ce cas l’Unit Identifier n’est pas significatif et doit être ignoré. Par contre, si le serveur est connecté à un sous-réseau sur liaison série, et que la réponse provient d’un routeur, l’Unit Identifier (qui dans ce cas ne sera pas égal à 0xFF) devra être pris en compte pour l’identification du serveur par le client. Pour ce qui est de l’analyse du PDU de la réponse, le client vérifie la conformité du Function Code ainsi que du format de la réponse. Si le Function Code est le même que celui contenu dans la requête, et si le format de la réponse est correct, le client envoie une confirmation positive à l’application. Si au contraire le Function Code contenu dans la réponse est différent de celui contenu dans la requête originale, ou si le format de la réponse est incorrect, le client signale une erreur à l’application en lui envoyant une confirmation négative. Enfin, si le Function Code correspond à un code d’exception (Function Code + 80H), une réponse d’exception Modbus est transmise à l’application. Il est important de noter qu’une confirmation positive indique seulement à l’application que le serveur a bien reçu la requête et qu’il y a répondu. Une telle confirmation ne la renseigne en aucun cas sur le succès ou l’échec des actions menées, ceci étant du ressort des réponses d’Exception Modbus.