У вас есть требование, которое не согнуть: удалённая сторона должна получить тот же IP-пакет 1,500 байт, который выпускает отправитель, включая заголовки. Туннель не может упаковать этот пакет вместе со своим кадрированием во второй IP-пакет 1,500 байт, поэтому что-то в проекте должно уступить. Порядок ниже — тот, который я использую в окне изменений: записать бюджет в байтах, доказать, что нижележащая сеть действительно может пронести, затем выбрать ровно один механизм переноса и подтвердить внутренний пакет на другой стороне.

Запишите бюджет в байтах до правки профиля

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

Проект решают два числа: самый большой внешний пакет, который путь несёт без фрагментации, и дополнительные байты, нужные вашей инкапсуляции. Когда первое меньше второго плюс 1,500, одно из них должно измениться. Тогда выбор становится узким, а не творческим, поэтому я записываю оба числа до обсуждения вариантов. Ничто на уровне туннеля не сжимает эти байты, и никакое одно целое значение MTU не снимает данное вам требование.

Проверьте нижележащую сеть ping с do-not-fragment

Измеряйте путь, а не доверяйте MTU интерфейса, потому что важен самый маленький участок внешнего пути. В Linux, -M do устанавливает бит do-not-fragment и -s принимает полезную нагрузку ICMP, поэтому кадр 1,500 байт отвечает при 1,472 байтах полезной нагрузки, если вычесть заголовок IP 20 байт и заголовок ICMP 8 байт. Поднимайте нагрузку, пока проверка не провалится, затем прыгните к jumbo-размеру, чтобы увидеть, несёт ли путь его вообще.

ping -M do -s 1472 -c 2 198.51.100.10
ping -M do -s 8972 -c 2 198.51.100.10
tracepath -n 198.51.100.10

Путь, который проходит 1,472 и проваливается на 8,972, не может пронести внутренний пакет 1,500 байт вместе с накладными расходами в одном внешнем пакете. Это ответ, который был нужен до открытия конфигурации VPN. Он же определяет, какой из двух следующих разделов относится к вам, поэтому держите оба результата проверки рядом с заявкой. Догадка здесь стоит окна обслуживания, потому что туннель, который сообщает о себе up, ничего не говорит о самом большом пакете, который примет путь.

Поднимайте MTU пути только там, где согласен каждый переход

Jumbo-кадры — свойство end-to-end, а не настройка, которую вы включаете на двух конечных точках, которыми случайно управляете. Каждый коммутатор, маршрутизатор и стык провайдера на внешнем пути должны согласиться на больший размер, и один переход 1,500 байт молча отбросит пакет, который вы только что увеличили. Поднять только локальный интерфейс — классическая половинчатая правка, из-за которой туннель выглядит сломанным, пока нижележащая сеть тихо теряет пакеты.

ip link set dev eth1 mtu 9000
ip link show dev eth1
ping -M do -s 8972 -c 2 198.51.100.10

Измените интерфейс, затем проверьте тот же путь снова, прежде чем менять что-то ещё. Если проверка всё ещё проваливается, откатите с помощью ip link set dev eth1 mtu 1500 и перейдите к фрагментации, вместо того чтобы спорить с провайдером о канале, который вам не принадлежит.

Используйте фрагментацию туннеля, когда нижележащая сеть не может вырасти

Поддерживаемый механизм фрагментации ниже внутреннего пакета позволяет нескольким внешним пакетам нести один внутренний, и противоположная конечная точка туннеля собирает их заново, прежде чем отдать оригинал в стек. Опция UDP fragment в Community OpenVPN — одна реализация этой идеи, и это не то же самое, что обычная IP-фрагментация внешнего пакета. Оба узла должны работать на версии, поддерживающей формат, и путь данных должен быть тем, о котором вы думаете: клиенты OpenVPN 3 и ускоренные ядром каналы данных имеют разные ограничения, поэтому профиль, работающий на одном клиенте, может отказать на другом.

openvpn --config client.ovpn --tun-mtu 1500 --fragment 1400 --verb 4

Обычная внешняя фрагментация — другой вариант, и он слабее. Маршрутизаторы IPv6 вовсе не фрагментируют пересылаемый пакет, поэтому слишком большой внешний пакет просто умирает, и отправитель узнаёт об этом, только если соответствующие сообщения ICMPv6 выживут на пути. Фрагменты также приглашают фильтрацию и усиление потерь, поэтому я отношусь к этому как к запасному варианту, а не плану.

Внешний переносчик на основе потока обходит вопрос размера, сегментируя собственный поток байтов, и восстановленный внутренний пакет всё ещё может быть 1,500 байт. Это транспортное решение со своей ценой, включая известное поведение TCP внутри TCP, поэтому принимайте его осознанно, а не как побочный эффект спора об MTU.

Подтвердите, что внутренний пакет приходит неизменным

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

ip link show dev tun0
ping -M do -s 1472 -c 2 10.8.0.1
tcpdump -ni tun0 -c 5 'icmp and greater 1000'

Если запись показывает внутренний пакет полного размера на дальнем конце, выбор переноса работает, и остаётся его зафиксировать. Если она ничего не показывает, пока туннель сообщает о себе up, внешний пакет отбрасывается где-то между конечными точками, что возвращает вас к проверке, а не к настройкам шифра.

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

Похожие статьи