PMTUD

PMTUD (Path MTU Discovery, RFC 1191 для IPv4, RFC 8201 для IPv6) — механизм автоматического обнаружения самого маленького MTU на пути от источника до назначения. Нужен чтобы не фрагментировать пакеты и не резать производительность.

Как работает (IPv4)

  1. Хост шлёт пакет с флагом Don't Fragment (DF) и размером = локальный MTU (обычно 1500).
  2. Промежуточный роутер видит: следующий линк имеет MTU=1400, а пакет 1500 с DF.
  3. Роутер дропает пакет и отвечает ICMP Type 3 Code 4 «Fragmentation Needed» с указанием MTU=1400.
  4. Отправитель уменьшает свой path-MTU до 1400 для этой цели, повторяет.
  5. Процесс повторяется пока пакеты не пройдут.

Как работает (IPv6)

В IPv6 роутеры не фрагментируют — только источник. Все пакеты фактически имеют DF=1. Аналог ICMPv4 «Frag Needed» — ICMPv6 Type 2 «Packet Too Big». Механизм проще и надёжнее.

ICMP Black Hole

Многие фаерволы дропают весь ICMP из «безопасности». В результате:

  1. Отправитель шлёт 1500-байт с DF.
  2. Роутер дропает и шлёт ICMP «Frag Needed» — но ICMP не доходит.
  3. Отправитель ждёт таймаута, ретрансмитит.
  4. Всё повторяется. Соединение висит.

Симптомы: маленькие пакеты (SYN, DNS, HTTP-запросы без данных) проходят, большие — нет. Веб-страницы «загружает» → 0%. TLS-handshake зависает на Certificate.

Решения

1. MSS clamping

Роутер переписывает MSS в SYN-пакетах на меньшее — TCP-стороны сами используют меньше. Не требует ICMP. Работает только для TCP. См. MSS.

2. Разрешить ICMP «Packet Too Big»

В файрволе явно пропустить ICMP Type 3 Code 4 (IPv4) и ICMPv6 Type 2:

iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT

3. PLPMTUD (Packetization Layer PMTUD)

RFC 4821не полагается на ICMP. TCP сам тестирует пробующими пакетами разного размера. Если пропало → уменьшает MTU. Полностью работает вне зависимости от блокировки ICMP.

Включено по умолчанию в Linux (net.ipv4.tcp_mtu_probing = 1 с 2007), Windows Vista+, macOS.

4. Ручная настройка MTU

# Уменьшить MTU интерфейса
ip link set eth0 mtu 1400

# Route-specific MTU
ip route add 10.0.0.0/8 via 192.168.1.1 mtu 1400

Как проверить

# ping с DF-битом (Linux)
$ ping -M do -s 1472 example.com
PING example.com (1.2.3.4) 1472(1500) bytes of data.
1480 bytes from 1.2.3.4: icmp_seq=1 ttl=57 time=15.3 ms

# Уменьшаем до 1450
$ ping -M do -s 1450 example.com
PING example.com (1.2.3.4) 1450(1478) bytes of data.
1458 bytes from 1.2.3.4: icmp_seq=1 ttl=57 time=15.5 ms

# Проверить с флагом DF на конкретный размер
# Windows
ping -f -l 1472 example.com

# macOS
ping -D -s 1472 example.com

tracepath — трассировка MTU

$ tracepath example.com
 1?: [LOCALHOST]                     pmtu 1500
 1:  gw.local                        0.5ms
 2:  isp-gw                          10ms   pmtu 1492
 3:  bgp-router                      15ms
 4:  example-router                  20ms   pmtu 1400
 5:  example.com                     25ms   reached

PMTUD и туннели

При инкапсуляции (VXLAN, GRE, IPsec, WireGuard) MTU inner-канала меньше outer. Если PMTUD ломается — приложения внутри туннеля сталкиваются с blackhole.

Best practice — включить MSS clamping на туннельных интерфейсах всегда:

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

PMTUD в UDP/QUIC

UDP без сохранения состояния — приложение должно само делать PLPMTUD. QUIC имеет встроенный DPLPMTUD (Datagram PLPMTUD, RFC 8899).

См. также