SwordArMor

Le MTU et le MSS

En théorie

Le MTU est la taille maximale qu’un paquet peut avoir lors de son transport sur le réseau. Elle est généralement de 1500 octets. À partir de ce MTU, nous calculons le MSS, c’est à dire la quantité maximale de données que nous pouvons atteindre dans un seul paquet sans qu’il ne soit fragmenté lorsque nous utilisons le protocole de transport TCP.
Le but de ce mécanisme est d’éviter la fragmentation de paquets. En effet, la performance d’un routeur est déterminée en fonction du nombre de paquets par seconde qu’il peut gérer, indépendamment de leur taille. Pour avoir les meilleurs performances possibles, il faut donc avoir les plus gros paquets possibles. Le MSS est déterminé par TCP lors de la poignée de main initiale.

Seulement, il arrive que cet échange de MSS ne suffise pas à déterminer la taille de paquet optimale. Par exemple, si le paquet passe par un tunnel sur le chemin, vous aurez un MTU inférieur à un moment alors que les deux machines qui se parlent sont capables de recevoir des paquets de 1500 octets.
Dans ce cas, il existe le Path MTU discovery. Si jamais le paquet est trop gros mais qu’il est marqué comme ne pouvant pas être fragmenté (drapeau d’en-tête IP DF, pour Don’t Fragment), la machine va envoyer un paquet ICMP de type 3 code 4 (Fragmentation Needed and Don’t Fragment was Set).

En pratique

Mais… nous avons parfois affaire à des admins bourrins qui bloquent totalement ICMP. Du coup, le paquet ne passe juste pas et la session TCP finit par se fermer.
C’est par exemple le cas avec laposte.net. Nous avons remarqué ceci chez grifon car nous avons un tunnel GRE vers ARN pour la redondance BGP. Il arrive donc que des paquets arrivent par chez eux. Or, ce tunnel a un MTU de 1476 octets, ce qui ne cadre pas avec le MTU de toutes les machines du réseau.

En voyant ça, nous avons d’abord pensé à un simple problème de MTU. Mais en mettant le GRE à 1200, ça n’a rien changé. Effectivement, le problème n’était pas le GRE en lui-même, puisque nous pouvions parfaitement faire passer des paquets de 1500 octets dessus, mais de faire comprendre au serveur que l’on veut joindre qu’il faut réduire le MTU s’il passe par là.

Ainsi, ça ne peut être qu’un problème de PMTUd. Une solution à ce problème est de ne pas avoir besoin d’y faire appel. Nous avons alors essayé de mettre le MTU du port interne de grifon à 1460 pour voir si ça avait une influence dans le calcul du MSS, nada.

Nous aurions pu également changer le MTU de toutes les machines du réseau grifon, mais ce n’est pas possible puisque nous n’avons pas la main dessus.

Il ne nous restait alors plus que la solution de ré-écrire le MSS pour les paquets qui passent par ce routeur. Ce n’est clairement pas la meilleure des solutions, car ça veut dire mettre ses mains dans la couche 4, mais c’est la seule qui marche.
Le routeur de grifon est sous FreeBSD, nous avons donc ajouté la règle pf scrub out all max-mss 1436. Ainsi, tous les paquets ont une MSS maximale de 1436 octets, soit 1476 (MTU GRE) – 40 (en-tête IP et TCP).

Pour aller plus loin

Si vous voulez en savoir plus sur ces histoires de MSS et MTU, vous pouvez lire https://www.bortzmeyer.org/mtu-et-mss-sont-dans-un-reseau.html, https://www.grenode.net/Documentation_technique/Divers/Multiples_encapsulations/ ou http://shaarli.guiguishow.info/?JjNf1g.

Un autre article (mais plus récent que le mien) nous explique pourquoi la fragmentation ne marche pour ainsi dire pas.