Couche Transport
Introduction
La couche transport est une pièce centrale de l’architecture réseau en couches. Elle a le rôle critique de fournir des services de communication directement aux processus d’application (i.e. communication logique) s’exécutant sur différents hôtes.
Les processus applicatifs utilisent la communication logique fournie par la couche transport pour s’envoyer des messages, sans se soucier des détails de l’infrastructure physique utilisée pour transporter ces messages (on n’a à se soucier ni des NATs possiblement présents ni des redirections de ports).
Terminologie
– Segment : nom donné au (T)PDU (Transport Protocol Data Unit) de la couche transport
– Datagramme : terme utilisé pour parler des segments UDP
– Socket : interface de communication offert par la couche transport. Porte par laquelle les données passent du réseau au processus et inversement.
Démultiplexage / Multiplexage
La tâche la plus fondamentale d’UDP et de TCP est d’étendre le service de livraison IP entre deux systèmes finaux à un service de livraison entre deux processus s’exécutant sur les systèmes finaux. L’extension de la transmission d’hôte à hôte à la transmission de processus à processus est appelée multiplexage et démultiplexage de la couche de transport.
Le but ici est d’avoir une solution pour permettre à plusieurs processus (e.g. YouTube + Zoom + Direct Download) de recevoir directement la donnée en utilisant les services de la couche réseau en même temps.
Ok, reprenons :
- Démultiplexage
💡 Tâche consistant à acheminer les données d’un segment de la couche de transport vers le bon socket.
🏗️ Couche réseau vers plusieurs applications
Par analogie, le fait de recevoir une lettre à la maison et de regarder à qui la lettre est précisément adressée (e.g. mon frère) et de la lui transmettre directement est du démultiplexage.
⚠️ Pour transmettre à la bonne application (démultiplexage), UDP se sert du tuple (IPdest,port_dest) tandis que TCP se sert du quadruplet (IPsource,port_src,IPdest,port_dest).
- Multiplexage
💡 Tâche consistant à rassembler des morceaux de données sur l’hôte source à partir de différents sockets, à encapsuler chaque morceau de données avec des informations d’en-tête (qui seront utilisées ultérieurement dans le démultiplexage) pour créer des segments, et à transmettre les segments à la couche réseau.
🏗️ Plusieurs applications vers une couche réseau
Par analogie, le fait de récolter toutes les lettres que notre famille veut envoyer et les donner au postier est du multiplexage.
💡 Les sockets ont des identifiants uniques, les numéros de ports, qui permettent d’identifier le processus source et destination.
– Chaque numéro de port est écrit sur 16bits de 0 à 65535.
- 0-1023 : réservés à des protocoles standards
🤔 Sur les systèmes d’exploitation de type Unix, un processus doit s’exécuter avec les privilèges de superutilisateur pour pouvoir lier un socket réseau à une adresse IP en utilisant l’un de ces ports.
– On trouve une liste plus exhaustive ici
- 1024-49151 : ports utilisateurs ou enregistrés
- 49152-65535 : ports dynamiques ou éphémères
💭 Chaque socket de l’hôte pourrait se voir attribuer un numéro de port et, lorsqu’un segment arrive sur l’hôte, la couche de transport examine le numéro de port de destination dans le segment et dirige le segment vers le socket correspondant. Les données du segment passent alors par le socket dans le processus attaché. C’est en gros la façon dont UDP procède.
Cependant c’est un peu plus subtil pour TCP.
UDP : transport non-connecté sans état
👉 Achemine au mieux, sans état et sans connexion. Il n’ouvre pas de session et ne corrige pas les erreurs (checksum uniquement).
En soi, lorsqu’on choisit d’utiliser UDP plutôt que TCP, l’application parlera quasiment directement avec le protocole IP.
- Et ça fonctionne comment ?
UDP prend les messages du processus applicatif, attache les champs relatifs aux numéros de port source et destination pour le service de multiplexage/démultiplexage, et y ajoute deux autres petits champs, puis transmet le datagramme obtenu à la couche réseau. La couche réseau encapsule le datagramme de la couche transport dans un paquet IP, puis tente au mieux de livrer le datagramme à l’hôte de destination. Si le datagramme arrive à celui-ci, le protocole UDP utilise le numéro de port de destination pour transmettre les données du segment au processus applicatif approprié.
- Le DNS est un bon exemple de protocole de la couche 4 (i.e. Application) qui utilise UDP.
Lorsque l’application DNS d’un hôte souhaite effectuer une requête, elle construit un message de requête DNS et transmet le message à UDP. Sans effectuer de handshake avec l’entité UDP s’exécutant sur le système final de destination, l’UDP côté hôte ajoute des champs d’en-tête au message et transmet le datagramme obtenu à la couche réseau. La couche réseau encapsule le datagramme UDP dans un paquet et l’envoie à un serveur de noms. L’application DNS du client attend alors une réponse à sa requête. Si il ne reçoit pas de réponse (peut-être parce que le réseau sous-jacent a perdu la requête ou la réponse), il peut essayer de renvoyer la requête, de l’envoyer à un autre DNS ou d’informer l’application qui l’invoque qu’elle ne peut pas obtenir de réponse.
- La structure du segment UDP est définie dans la RFC 768
🤔 On peut se demander pourquoi UDP propose un checksum étant donné que pas mal de protocoles de la couche de liaison (dont le célèbre protocole Ethernet) fournissent également une vérification des erreurs. La raison est qu’il n’y a aucune garantie que tous les liens entre la source et le destinataire proposent une correction d’erreur. Et quand bien même, une erreur peut être introduite au niveau de la mémoire d’un routeur.
Comme le protocole IP est censé fonctionner sur à peu près n’importe quel protocole de couche 2, il est utile que la couche de transport fournisse un contrôle d’erreur par mesure de sécurité. Bien que le protocole UDP fournisse un contrôle d’erreur, il ne fait rien pour récupérer une erreur. Certaines implémentations d’UDP se contentent de rejeter le datagramme endommagé, d’autres le transmettent à l’application avec un avertissement.
TCP : transport connecté avec état
👉 Achemine avec un état (i.e. attend une réponse) avec établissement d’une connexion.
💡 Avec TCP, contrairement à UDP, on peut donc communiquer avec deux processus différents sur le même port tant que l’on a une IP source différente !
On dit que TCP est orienté connexion parce qu’avant qu’un processus applicatif puisse commencer à envoyer de la donnée à un autre, les deux doivent d’abord se "serrer la main" (i.e. handshake).
Une connexion TCP fournit un service full-duplex (i.e. les données circulent dans les deux sens) et point à point (i.e. entre une seule source et une seule destination - pas de multicast !).
- L’ouverture de session TCP se fait via trois séquences
💡 L’isn où Initial Sequence Number avait comme objectif d’éviter les superpositions de connexions. 2 connexions peuvent utiliser les mêmes numéros de ports ET des numéros de séquence proches. Aujourd’hui cette séquence est "complètement" aléatoire. Il est codé sur 4 octets.
TCP voit la donnée comme un flux déstructuré mais ordonné d’octets. L’utilisation des numéros de séquence par TCP reflète ce point de vue dans la mesure où les numéros de séquence portent sur le flux d’octets transmis et non sur la série de segments transmis. Le numéro de séquence d’un segment est donc le numéro du flux d’octets du premier octet du segment.
⚠️ Le n°seq est le n° du premier octet du segment envoyé !
⚠️ Le n°ack est le n° du prochain octet attendu !
La taille maximale du champ de données est fixée par le MSS (Maximum Segment Size).
💭 Le MSS est comme le MTU, mais utilisé avec TCP à la couche 4. En d’autres termes, le MSS est la taille maximale que peut avoir la charge utile, après avoir soustrait l’espace pour les en-têtes IP, TCP et autres. Ainsi, si la MTU est de 1500 octets et que les en-têtes IP et TCP sont de 20 octets chacun, le MSS est de 1460 octets.
⚠️ Contrôle de flux ≠ contrôle de congestion
💡 Le contrôle de flux signifie essentiellement que TCP s’assure qu’un expéditeur ne submerge pas un destinataire en envoyant des paquets plus vite qu’il ne peut les consommer. Il concerne le nœud final (place disponible dans le buffer).
💡 Le contrôle de congestion vise à empêcher un nœud de submerger le réseau (c’est-à-dire les liens entre deux nœuds).
Contrôle de flux
Le contrôle de flux consiste à s’assurer qu’on envoie pas plus de paquets lorsque le buffer de réception est déjà plein, car le destinataire ne serait pas en mesure de les gérer et devrait abandonner ces paquets.
Pour contrôler la quantité de données que TCP peut envoyer, le destinataire annonce sa fenêtre de réception (Receive Window aka `rwnd`), c’est-à-dire l’espace libre dans le tampon de réception.
Chaque fois que le TCP reçoit un paquet, il doit envoyer un message ack à l’expéditeur, accusant réception de ce paquet correctement, et avec ce message ack, il envoie la valeur de la fenêtre de réception actuelle, afin que l’expéditeur sache s’il peut continuer à envoyer des données.
💡 TCP utilise un protocole de fenêtre glissante pour contrôler le nombre d’octets en circulation qu’il peut avoir. Autrement dit, le nombre d’octets qui ont été envoyés mais qui n’ont pas encore été acquittés.
Contrôle de congestion
La retransmission de paquets traite un symptôme de congestion du réseau (la perte d’un segment spécifique de la couche de transport) mais ne traite pas la cause de la congestion du réseau, à savoir un trop grand nombre de sources qui tentent d’envoyer des données à un débit trop élevé. Pour traiter la cause de la congestion du réseau, des mécanismes sont nécessaires pour limiter les émetteurs face à la congestion du réseau.
Divers scénarios de congestion sont possibles :
- Deux connexions qui partagent un seul saut (routeur) avec des buffers infinis
💡 L’un des coûts d’un réseau congestionné : d’importants retards de mise en file d’attente se produisent lorsque le taux d’arrivée des paquets approche de la capacité du lien.
- Deux hôtes (avec retransmissions) et un routeur avec des *buffers* finis
💡 Autre coût d’un réseau congestionné : l’émetteur doit effectuer des retransmissions afin de compenser les paquets abandonnés (perdus) en raison du dépassement de la mémoire tampon.
- Quatre émetteurs, des routeurs avec des tampons finis, et des chemins multi-sauts.
💡 Un autre coût lié à l’abandon d’un paquet en raison de la congestion : lorsqu’un paquet est abandonné le long d’un chemin, la capacité de transmission qui a été utilisée sur chacun des liens en amont pour acheminer ce paquet jusqu’au point où il est abandonné finit par être gaspillée.
💡 La version de TCP normalisée (dans la RFC 5681) utilise un contrôle de congestion de bout en bout plutôt qu’un contrôle de congestion assisté par le réseau, puisque la couche IP ne fournit aucun retour d’information explicite aux systèmes finaux concernant la congestion du réseau (buffer plein = paquet jetté).
🆕 Dans le cas d’ECN (Explicit Congestion Notification), le contrôle de congestion est assisté par la couche IP en combinaison avec une gestion active de file d’attente (AQM) en permettant à l’élément de transfert (e.g. routeur) de notifier le début de congestion mais il reste régulé par la couche transport.
Plus récemment, des extensions d’IP et de TCP (RFC 3168) ont été proposées, mises en œuvre et déployées pour permettre au réseau de signaler explicitement la congestion à un émetteur et à un destinataire TCP. En outre, un certain nombre de variantes des protocoles de contrôle de congestion TCP ont été proposées pour déduire la congestion à partir du retard mesuré des paquets.
Explicit Congestion Notification (RFC 3168) est la forme de contrôle de congestion assistée par le réseau réalisée au sein d’internet. Au niveau de la couche réseau, deux bits (avec quatre valeurs possibles, au total) dans le champ Type of Service de l’en-tête du datagramme IP sont utilisés pour ECN.
Un réglage des bits ECN est utilisé par un routeur pour indiquer qu’il (le routeur) connaît une congestion.
MPTCP
Extension de TCP pour permettre à des terminaux d’établir une communication et d’être capable d’exploiter les ressources de plusieurs chemins à travers des sous-sessions TCP.
👉🏻 Vu que TCP, de base, se fiche de l’ordre d’arrivée des segments, on peut les faire arriver de n’importe quelle source !
💡 D’autres déploiements utilisent TCP Multipath pour agréger la bande passante de différents réseaux. Par exemple, plusieurs types de smartphones, notamment en Corée, utilisent TCP Multipath pour relier le WiFi et la 4G par le biais de proxies SOCKS.