MAATRIX / Блог / В конфиге MTU 1500, по факту 1420: как найти реальный размер пакета до сервера

В конфиге MTU 1500, по факту 1420: как найти реальный размер пакета до сервера

MAATRIX

В настройках интерфейса написано MTU 1500 — стандартное значение по умолчанию почти везде. Но это число описывает только сам интерфейс, а не путь пакета до сервера целиком: между вами и адресатом может стоять VPN-туннель, GRE-линк между дата-центрами или провайдер с PPPoE, и каждый отрезает от доступного размера пакета несколько десятков байт. Конфиг говорит 1500, а по факту через весь путь проходит, условно, 1420 — и эта разница превращается в зависшую SSH-сессию или наполовину загруженный сайт без единой ошибки в логах. Разберёмся, как найти эту разницу инструментально, а не гадать.

Что такое MTU и почему цифра на интерфейсе — не гарантия для всего пути

MTU (Maximum Transmission Unit) — максимальный размер пакета, который конкретный сетевой интерфейс может передать за один раз, без разбивки на части. Это локальный параметр линка, а не глобальная характеристика интернета: у сетевой карты сервера один MTU, у следующего свича на пути — возможно, другой, у провайдера на входе в его сеть — третий, у VPN-туннеля поверх всего этого — четвёртый. Пакет от отправителя до получателя проходит цепочку таких границ, и рабочий размер пакета определяется самым узким звеном этой цепочки — величиной, которую называют Path MTU.

Отсюда и главная ловушка: команда ip link show или ifconfig покажет MTU локального интерфейса, но ничего не скажет о том, что происходит дальше по маршруту. Интерфейс с MTU 1500 готов отправить пакет такого размера — вопрос в том, пропустит ли его следующий узел, и узел за ним, и так до самого сервера. Если на пути есть более узкое место, а определить его автоматически не удалось (почему — в разделе про PMTUD), система продолжает готовить пакеты по 1500 байт, которые где-то на середине маршрута просто перестают проходить.

Поэтому вопрос не «какой MTU у меня в конфиге», а «какой размер пакета реально проходит от точки А до точки Б прямо сейчас» — и ответить на него можно только измерением, а не чтением настроек.

Кто крадёт байты: VPN, GRE, IPsec, VXLAN и другие туннели

Самая частая причина, по которой реальный MTU пути оказывается меньше заявленных 1500, — инкапсуляция. Любой туннель заворачивает исходный пакет в собственный заголовок, и этот заголовок отъедает часть места, доступного для полезной нагрузки на физическом канале с тем же MTU 1500.

Порядок величин по распространённым технологиям — это ориентир, а не точная цифра для вашего случая, потому что режим шифрования и настройки конкретной реализации могут менять overhead на несколько байт:

ТехнологияТипичный overheadИз чего складывается
WireGuard (IPv4)около 60 байт20 IP + 8 UDP + 32 заголовок WireGuard
OpenVPN40-60 байтзависит от режима, шифра, сжатия
IPsec (ESP, туннельный режим)50-70 байтвнешний IP + ESP-заголовок + выравнивание под шифр
GRE24 байта20 внешний IP + 4 заголовок GRE
VXLANоколо 50 байт20 IP + 8 UDP + 8 VXLAN + Ethernet-заголовок

Если физический канал даёт MTU 1500, а туннель поверх него поднят без понижения MTU на туннельном интерфейсе, система внутри туннеля продолжает готовить пакеты по 1500 байт. Поверх них туннель добавляет свои 50-70 байт — итоговый пакет уже не помещается в исходные 1500 байт физического канала. Дальше — один из двух сценариев: пакет либо фрагментируется (если это разрешено), либо, при выставленном флаге «не дробить», просто пропадает, и без работающего PMTUD отправитель об этом не узнаёт.

Отдельно стоит держать в уме двойное туннелирование: VPN поверх PPPoE (свои 8 байт overhead) или VPN внутри VPN в site-to-site схемах между офисами. Overhead каждого слоя тут складывается, и реальный MTU может оказаться заметно ниже, чем при одном туннеле — угадать точное число без измерения почти невозможно.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Path MTU Discovery и чёрная дыра ICMP

В теории системе не нужно ничего искать руками — за это отвечает Path MTU Discovery (PMTUD). Отправитель помечает пакет флагом DF («не дробить»), и если пакет не помещается в MTU какого-то канала по пути, маршрутизатор на этом участке обязан отбросить пакет и отправить обратно ICMP: в IPv4 — «Fragmentation Needed» (тип 3, код 4, с указанием подходящего размера), в IPv6 — «Packet Too Big». Получив это сообщение, отправитель узнаёт реальный MTU узкого места и дальше шлёт пакеты меньшего размера — самонастраивающийся механизм, не требующий ручного вмешательства.

На практике PMTUD ломается на удивление часто, и почти всегда по одной причине: домашние роутеры, корпоративные файрволы и облачные security groups блокируют ICMP целиком или выборочно режут нужные типы сообщений как потенциально опасные. Промежуточный маршрутизатор честно отбрасывает слишком крупный пакет и честно отправляет ICMP с сигналом «уменьшите размер» — а сигнал до отправителя не доходит, потому что его срезал файрвол где-то на обратном пути. Отправитель никогда не узнаёт, что пакет потерян, и продолжает слать пакеты того же «слишком большого» размера снова и снова.

Это состояние называют чёрной дырой PMTUD: соединение установлено, маленькие пакеты через него ходят нормально, а крупные пропадают в тишине без единого сообщения об ошибке. Отличить её от обычной нестабильности канала можно по одному признаку: потеря пакетов из-за перегрузки плавает и задевает пакеты вперемешку независимо от размера, а чёрная дыра PMTUD стабильно режет пакеты одного размера — проблема воспроизводится на 100% при одинаковой нагрузке. Подробный разбор фрагментации в IPv4 и IPv6 и того, почему в IPv6-сетях PMTUD — не опция, а единственный рабочий способ подобрать размер пакета, — в статье MTU и фрагментация: откуда берутся «загадочные» обрывы.

Симптомы: мелкое летает, крупное зависает

Проблема с реальным MTU пути почти никогда не выглядит как «сеть не работает» — она выглядит как «сеть работает через раз», и это чаще всего сбивает с толку: первая мысль обычно про баг в приложении, а не про пару десятков байт заголовка. Характерный набор признаков:

  • ping до сервера проходит без потерь и с нормальной задержкой — обычный ICMP-запрос весит 56-64 байта полезной нагрузки, укладывается в любой мыслимый MTU.
  • SSH подключается, показывает приглашение, но зависает на конкретной команде — логин и обмен ключами это мелкие пакеты, а вывод ls -la в большой директории или прокрутка less генерирует пакеты, которые упираются в реальный MTU пути.
  • Сайт открывается, но не догружается до конца — HTML обычно укладывается в один-два пакета и приходит нормально, а крупные изображения, шрифты или установка TLS (сертификаты нередко крупнее 1400 байт) подвисают.
  • SCP/rsync замирает на одном и том же проценте при каждой попытке — признак упора в конкретный размер пакета, а не случайной нестабильности сети.
  • Проблема воспроизводится стабильно при повторе одного и того же действия, в отличие от плавающих сбоев обычной нестабильной сети.

Если же не проходит вообще ничего, включая маленький ping, — дело не в MTU, а в более базовой проблеме: маршрутизации, NAT или файрволе, который режет соединение целиком. О том, как выглядит и диагностируется чисто маршрутная проблема, — в статье Почему пакет из Москвы в Питер идёт через Стокгольм.

Ищем реальный MTU руками: ping с запретом фрагментации

Не нужно гадать между условными 1400, 1420 и 1450 — точное значение канала находится обычным бинарным поиском через ping, если использовать флаг, который запрещает фрагментацию (программный аналог DF-бита) и заставляет систему честно сообщать об ошибке вместо того, чтобы дробить пакет самостоятельно:

# Linux
ping -M do -s 1472 example.com

# macOS
ping -D -s 1472 example.com

# Windows (PowerShell/cmd)
ping -f -l 1472 example.com

Число после -s (на Windows — -l) — размер полезной нагрузки ICMP без заголовков IP и ICMP, которые в сумме занимают 28 байт для IPv4 (для IPv6 — 48 байт). Значение 1472 проверяет пакет размером ровно 1500 байт целиком. Ответ пришёл — пакет такого размера проходит через весь путь. Видите Frag needed and DF set или sendto: Message too long — размер нужно уменьшать.

Дальше — обычный бинарный поиск: берёте среднее между последним успешным и последним неудачным значением и повторяете, пока не найдёте точную границу с шагом в один байт:

ping -M do -s 1400 example.com   # прошло — пробуем больше
ping -M do -s 1450 example.com   # не прошло — сужаем между 1400 и 1450
ping -M do -s 1420 example.com   # прошло — сужаем между 1420 и 1450

К найденному предельному значению прибавьте 28 байт (или 48 для IPv6) — это и есть реальный MTU пути до сервера. Важно проверять именно тот путь, который вас интересует: если проблема в туннеле, пингуйте адрес внутри VPN-подсети, а не «внешний» IP — иначе измерите MTU физического канала, а не эффективный MTU с учётом overhead инкапсуляции. Иногда узкое место обнаруживается не в вашем туннеле, а на участке нетипичного транзитного оператора — о том, как читать такие расхождения, в статье про асимметричный маршрут туда и обратно.

tracepath: автоматический поиск MTU в Linux

Бинарный поиск через ping работает надёжно, но требует нескольких итераций руками. В Linux есть утилита, которая делает то же самое автоматически за один проход — tracepath. Она строит маршрут до узла, как traceroute, но на каждом хопе проверяет проходящий размер пакета и уменьшает пробный размер при получении ICMP «Fragmentation Needed»:

tracepath example.com

Типичный вывод выглядит так:

 1?: [LOCALHOST]                      pmtu 1500
 1:  10.0.0.1                              0.412ms
 2:  10.0.0.1                              0.397ms
 3:  203.0.113.1                           8.114ms
 4:  203.0.113.1                           8.231ms pmtu 1420
 5:  198.51.100.20                        12.045ms reached
     Resume: pmtu 1420 hops 5 back 5

Строка pmtu 1420 показывает, на каком хопе путь сузился и до какого значения. Последняя строка Resume суммирует итог: конечный Path MTU для всего маршрута и количество хопов туда и обратно. Это удобнее перебора через ping, потому что границу не нужно подбирать вручную — tracepath находит её сама и заодно показывает, на каком участке пути происходит сужение, что полезно, если узкое место не у вас и не на сервере, а где-то посередине, например у транзитного провайдера.

Ограничение то же, что и у PMTUD в целом: tracepath полагается на ICMP-ответы промежуточных узлов, и если ICMP где-то по пути блокируется файрволом, она либо не увидит границу, либо покажет её неверно. В таком случае результат стоит перепроверить бинарным поиском через ping -M do — методы хорошо дополняют друг друга: tracepath быстро даёт первое приближение, ping с DF надёжно подтверждает точное число. На macOS и Windows штатного аналога tracepath нет, там основной метод — ручной бинарный поиск через ping.

Как обойти проблему: понижение MTU и MSS clamping

Когда реальный MTU пути найден и он меньше значения на интерфейсе, есть два рабочих способа привести конфигурацию в соответствие с фактическим состоянием сети — они решают проблему по-разному, и часто имеет смысл применять оба.

Понижение MTU на туннельном интерфейсе. Если узкое место — это сам туннель (VPN, GRE, VXLAN), самый прямой способ — выставить MTU туннельного интерфейса равным найденному реальному значению минус запас в 0-20 байт на случай небольших расхождений между измерением и продакшен-трафиком. На Linux это делается командой:

sudo ip link set mtu 1420 dev wg0

Значение не переживёт перезагрузку — для постоянного применения его нужно прописать в конфиг самого туннеля (у WireGuard это строка MTU = 1420 в секции [Interface]) или в системную конфигурацию сети (netplan, NetworkManager, /etc/network/interfaces). Подробный разбор именно для WireGuard, с формулой расчёта под разный overhead и готовыми значениями под PPPoE и двойное туннелирование, — в статье MTU для WireGuard: как настроить правильно. Минус подхода — он решает проблему только для этого интерфейса и требует ручной синхронизации, если туннель поднят с обеих сторон.

TCP MSS clamping на роутере или файрволе. Более системное решение для TCP-трафика — не трогать MTU интерфейсов, а заставить пограничное устройство (роутер, файрвол, сервер как шлюз) автоматически подрезать MSS (Maximum Segment Size) при установке TCP-соединения, независимо от настроек клиента. На Linux это одно правило iptables, которое обычно вешают на исходящий интерфейс туннеля:

sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

Правило перехватывает пакет с флагом SYN и переписывает в нём заявленный MSS так, чтобы итоговый сегмент гарантированно помещался в MTU исходящего интерфейса. Клиент ничего не меняет в своей конфигурации — он сразу договаривается о правильном размере сегмента, и чёрная дыра PMTUD для этого соединения перестаёт быть проблемой. Ограничение: clamping работает только для TCP — для UDP-трафика внутри туннеля (стриминг, игры, часть VPN-протоколов) нужно именно понижение MTU. Разные сценарии применения и типовые ошибки настройки — в статье VPN и MTU: проблема фрагментации и как подобрать значение.

Комбинация обоих способов даёт наиболее устойчивый результат: MTU понижается на самом туннельном интерфейсе до измеренного значения, а MSS clamping на границе сети подстраховывает случаи, когда клиент подключается с MTU, не совпадающим с вашими расчётами — например, из другой сети с ещё более узким каналом.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Обязательно ли гнаться за точным числом, или можно просто занизить MTU с запасом?

Можно, и в большинстве случаев это снимет проблему — MTU 1400 покрывает почти любую реальную инкапсуляцию с запасом. Плата — чуть больше служебного трафика на мегабайт, потому что полезной нагрузки в каждом пакете меньше. Для разовой настройки такой запас — разумный компромисс; на нагруженном канале лучше найти точное значение измерением.

Почему tracepath и ручной ping -M do иногда показывают разные числа?

Обычно потому что tracepath определяет узкое место по ICMP-ответам промежуточных маршрутизаторов, а если эти ответы где-то по пути частично блокируются файрволом, автоматическое определение может ошибиться. Ручной перебор через ping с запретом фрагментации от ICMP на обратном пути не зависит и в этом смысле надёжнее — при расхождении верьте результату ping.

Нужно ли измерять MTU отдельно для IPv4 и IPv6?

Да, если оба протокола используются параллельно. Заголовки IPv6 крупнее, и туннели часто дают чуть больший overhead для IPv6-инкапсуляции, так что реальный MTU для IPv6-пути может отличаться от IPv4-пути на тот же сервер на десяток-другой байт.

MSS clamping и понижение MTU — взаимоисключающие способы или их можно совмещать?

Совмещать можно и часто разумно: MSS clamping закрывает TCP-трафик независимо от настроек клиента, а понижение MTU на туннеле нужно для UDP-based приложений и как более универсальная защита при клиентах, которых вы не контролируете. Конфликта между ними нет — оба способа снижают эффективный размер пакета, только с разных сторон соединения.

Как убедиться, что найденное значение не изменится через неделю?

Если маршрут и туннель не менялись, число обычно стабильно. Оно может измениться, если провайдер меняет схему подключения (например, добавляет PPPoE), меняется топология VPN или маршрут начинает идти через другого транзитного оператора — при похожих симптомах после таких изменений измерение стоит повторить.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →