Comment le MTU est 65535 en UDP mais Ethernet ne permet pas une taille de trame supérieure à 1500 octets

11

J'utilise un Ethernet rapide de 100 Mbps, dont la taille de trame est inférieure à 1500 octets (1472 octets pour la charge utile selon mon manuel). En cela, j'ai pu envoyer et recevoir un paquet UDP de taille de message 65507 octets, ce qui signifie que la taille du paquet était de 65507 + 20 (en-tête IP) + 8 (en-tête UDP) = 65535.

Si la taille de la charge utile de la trame elle-même est au maximum de 1472 octets (selon mon manuel), comment la taille de paquet IP peut-elle être supérieure à celle qui est ici de 65535?

J'ai utilisé le code de l'expéditeur comme

char buffer[100000];
for (int i = 1; i < 100000; i++)
{
    int len = send (socket_id, buffer, i);
    printf("%d\n", len);
}

Code récepteur comme

while (len = recv (socket_id, buffer, 100000))
{
     printf("%d\n". len);
}

J'ai observé que send returns -1sur i > 65507et recvimprime ou reçoit un paquet de maximum of length 65507.

sysadmin1138
la source

Réponses:

11

Les datagrammes UDP n'ont pas grand-chose à voir avec la taille MTU, vous pouvez les rendre aussi gros que vous le souhaitez, jusqu'à 64 Ko est maximum mentionné ci-dessus. Vous pouvez même envoyer l'un d'eux dans un paquet entier tant que vous utilisez des trames jumbo avec une taille plus grande que le grand datagramme.

Cependant, les trames jumbo doivent être prises en charge par tous les équipements sur lesquels la trame passera, ce qui pose problème. Pour des raisons pratiques, les trames Ethernet sont la taille de transport la plus courante, le MTU pour ces derniers est d'environ 1500 octets, je dirai que 1500 vont de l'avant, mais ce n'est pas toujours. Lorsque vous créez un datagramme UDP plus grand que le MTU sous-jacent (qui, comme indiqué, est le plus souvent Ethernet), il sera discrètement divisé en un nombre de trames de 1500 octets. Si vous tcpdumpez ce trafic, vous verrez un certain nombre de paquets rompus à la limite MTU qui auront le plus d'indicateurs de fragments défini avec un numéro de fragment. Le premier paquet aura un numéro de fragment de 0 et plus de fragments seront définis et le dernier aura un numéro de fragment non nul et plus de fragments non définis.

Alors pourquoi s'en soucier? Le détail de l'implémentation compte vraiment. La fragmentation peut nuire aux performances du réseau, ce n'est plus un gros problème, mais il faut en être conscient. Si une énorme taille de datagramme est utilisée, si un fragment est perdu, les datagrammes entiers devront être renvoyés. De même à des volumes élevés et aujourd'hui ce sont des volumes parfaitement réalisables, une mauvaise association des cadres au remontage est possible. Il peut également y avoir des problèmes pour que les paquets UDP fragmentés traversent les configurations de pare-feu d'entreprise où les équilibreurs de charge répartissent les paquets, si un fragment se trouve sur un pare-feu et l'autre sur un autre, le trafic sera abandonné comme incomplet.

Ne créez donc pas de datagrammes UDP plus grands que la fragmentation de la taille MTU, sauf si vous devez le faire et si vous devez spécifier que l'infrastructure communiquée entre est proche (même sous-réseau fermé), auquel cas les trames jumbo seraient probablement une bonne option.

Martyn A
la source
De bonnes informations sur le «drapeau plus de fragments». Est-ce un indicateur dans l'en-tête UDP ou dans l'en-tête IP?
Jean Jésus du
Remarque: Certains systèmes d'exploitation NE transmettront PAS UDP si les données sont fragmentées. IE Linux doc,By default, Linux UDP does path MTU (Maximum Transmission Unit) discovery. This means the kernel will keep track of the MTU to a specific target IP address and return EMSGSIZE when a UDP packet write exceeds it.
Rahly
2

La couche IP fragmentera votre paquet à l'extrémité d'envoi, puis le réassemblera à l'extrémité de réception, avant de le transmettre à UDP. Depuis la couche UDP, vous ne pouvez pas vraiment dire que le paquet a été fragmenté. Si vous utilisez un outil de capture de paquets comme Wireshark , vous devriez pouvoir voir que votre ordinateur reçoit des paquets IP limités à la MTU.

Jeff
la source
1

Il s'avère que permettre à la pile TCP / IP de fragmenter les paquets selon les besoins est beaucoup plus faible que d'envoyer des paquets individuels.

geekosaure
la source
1
Voulez-vous dire que TCP / IP se fragmente et se rassemble? Si oui, alors pourquoi les gens disent-ils tout le temps que votre code devrait se charger du réassemblage du côté récepteur. Je n'ai pas observé de fragmentation pour l'instant, mais j'avais vu de nombreux forums qui le disent et même des gens l'acceptant.
Pour ceux d'entre nous qui sont confrontés au modèle OSI, pourriez-vous ajouter un peu plus de détails à votre réponse s'il vous plaît?
Robert Harvey
J'étais un peu inquiet parce que je ne peux pas dire si c'est des devoirs ou non. C'est un compromis: comme UDP n'offre aucune garantie de livraison, si un fragment de paquet est abandonné, le paquet entier est perdu. Si vous voulez un transport fiable sur UDP, vous devez gérer tout cela vous-même; mais si vous faites (par exemple) des protocoles de streaming (ou NFS sur UDP, qui a pris le chemin du streaming), il est plus faible de simplement supprimer ces paquets ou de retransmettre le plus gros paquet après un long délai si nécessaire. Vous devez équilibrer vos besoins par rapport aux fonctionnalités du protocole et à la surcharge du protocole.
geekosaur
1

UDP ne sait rien de MTU. Les paquets UDP peuvent avoir n'importe quelle taille de 8 à 65 535 octets. Les couches de protocole sous UDP peuvent envoyer un paquet d'une taille spécifique ou refuseront d'envoyer ce paquet avec une erreur si elles sont trop grandes.

La couche sous UDP est généralement IP, IPv4 ou IPv6. Et le paquet IP peut avoir n'importe quelle taille de 20 (IPv4) / 40 (IPv6) à 65535 octets, c'est le même maximum que UDP. Cependant, IP prend en charge un mécanisme appelé fragmentation . Si un paquet IP est plus grand que ce que la couche ci-dessous peut transporter, IP peut diviser un seul paquet en plusieurs paquets appelés fragments. Chaque fragment est en fait un paquet IP qui lui est propre (possède un en-tête IP propre) et est également envoyé seul à la destination; c'est alors la tâche de la destination de collecter tous les fragments et de reconstruire le paquet complet à partir d'eux avant de passer les données reçues sur la couche supérieure suivante (par exemple UDP).

Le protocole Ethernet ne peut transporter que des trames avec une charge utile comprise entre 46 et 1 500 octets (il existe des exceptions mais cela dépasse le cadre de cette réponse). Si les données de charge utile sont inférieures à 46 octets, elles sont remplies pour être exatiquement de 46 octets. Si les données utiles dépassent 1 500 octets, l'interface refusera de les accepter. Si cela se produit, c'est à la couche IP de décider maintenant de fragmenter le paquet, de sorte qu'aucun fragment ne dépasse 1 500 octets ou de signaler une erreur à la couche supérieure suivante si la fragmentation a été désactivée ou interdite pour cette connexion particulière.

La fragmentation est généralement à éviter, car

  • C'est gaspiller des ressources du côté de l'expéditeur.
  • cela gaspille des ressources du côté récepteur.
  • il augmente la surcharge du protocole pour la même quantité de données utiles.
  • si un seul fragment est perdu, le paquet entier est perdu.
  • si un seul fragment est corrompu, le paquet entier est corrompu.
  • en cas de renvoi, tous les fragments doivent être renvoyés.

C'est pourquoi TCP adopte intelligemment sa taille de trame afin que les paquets n'aient jamais besoin d'IP pour les fragmenter. Cela peut être fait en interdisant à IP de fragmenter les paquets et si IP signale qu'un paquet est trop gros pour être envoyé, TCP réduit la taille de la trame et réessaye, jusqu'à ce qu'aucune erreur ne soit plus signalée.

Pour UDP, cependant, ce serait la tâche de l'application elle-même, car UDP est un protocole "stupide", il n'a pas de logique de gestion propre, ce qui le rend très flexible, rapide et simple.

La seule taille UDP sur laquelle vous pouvez compter pour être toujours transportable est l'en-tête UDP 576 moins 8 octets et l'en-tête IP moins 20 (v4) / 40 (v6) octets, car la norme IP requiert que chaque hôte IP puisse recevoir des paquets IP avec une taille totale de 576 octets. Votre implémentation de protocole ne serait pas conforme au standard si elle ne peut pas accepter des paquets d'au moins cette taille. Notez cependant que la norme ne dit pas 576 sans fragmentation, donc même un paquet IP de 576 octets peut être fragmenté entre deux hôtes.

La seule taille de paquet sur laquelle vous pouvez compter pour être transportable sans fragmentation est de 24 octets pour IPv4 et de 56 octets IPv6, car les plus petits en-têtes IP pour un fragment sont de 20/48 octets (v4 / v6) et un fragment doit avoir au moins 4/8 octets (v4 / v6) de données utiles. Ainsi, un système de transport sous la couche IP qui ne peut pas transporter au moins des paquets de ces tailles, ne peut pas être utilisé pour transporter du trafic IP.

Et avant que quiconque commente qu'un en-tête IPv6 ne dispose que de 40 octets: c'est correct mais, contrairement à un en-tête IPv4, un en-tête IPv6 standard n'a pas de champs d'en-tête pour la fragmentation. Si un paquet doit être fragmenté, un en-tête d'extension de fragmentation doit être ajouté sous l'en-tête de base IPv6 et cet en-tête d'extension fait 8 octets. Contrairement à IPv4, les décalages de fragmentation dans IPv6 sont comptés en unités de 8 octets et non de 4 octets, donc un fragment ne peut transporter qu'une charge utile qui est un multiple de 8 octets en cas d'IPv6.

Mecki
la source
0

Pour répondre à votre question, "Si la taille de la charge utile de la trame elle-même est au maximum de 1472 octets (selon mon manuel), comment la taille de paquet IP peut-elle être supérieure à celle qui est ici 65535?"

Cela est dû à une fonctionnalité de déchargement appelée UFO (UDP Fragmentation Offload). Veuillez vous référer à ce lien.

Vous pouvez vérifier et basculer les fonctionnalités de déchargement via ethtool -k ethX et ethtool -K ethX respectivement.

Nehal Dattani
la source
0

Si vous surveillez les trames sortantes, il est possible que votre carte réseau prenne en charge le déchargement de segmentation et il est activé. Avec le déchargement de segmentation activé, la carte réseau elle-même gère la segmentation du paquet / de la trame dans la taille appropriée, plutôt que la pile réseau. Cela libère le processeur de l'ordinateur pour effectuer d'autres tâches, améliorant ainsi les performances. Sous linux, "ethtool -k [périphérique]" affichera les drapeaux de déchargement.

Andrew Bowers
la source