Назад | Перейти на главную страницу

Загадочные отказы «требуется фрагментация» от шлюзовой виртуальной машины

Я устранял серьезную проблему со скоростью WAN. Я исправил это, но для других:

С помощью WireShark, ведения журнала и упрощения конфигурации я сузил его до некоторого странного поведения от шлюза, выполняющего DNAT к серверам во внутренней сети. Шлюз (коробка CentOS) и серверы работают на одном и том же хосте VMware ESXi 5 (и это оказывается важным).

Вот последовательность событий, которые произошли - довольно последовательно -, когда я попытался загрузить файл с HTTP-сервера за DNAT, используя тестовый клиент, подключенный напрямую к WAN-стороне шлюза (в обход фактического подключения к Интернету, обычно используемого здесь) :

  1. Обычное установление TCP-соединения (SYN, SYN ACK, ACK) происходит нормально; шлюз правильно переназначает IP-адрес сервера в обоих направлениях.

  2. Клиент отправляет один сегмент TCP с HTTP GET, и это также правильно DNATted на целевой сервер.

  3. Сервер отправляет 1460-байтовый сегмент TCP с ответом 200 и частью файла через шлюз. Размер кадра на проводе составляет 1514 байтов - 1500 в полезной нагрузке. Этот сегмент должен пересекать шлюз, но этого не происходит.

  4. Сервер отправляет второй 1460-байтовый сегмент TCP, продолжая файл, через шлюз. Опять же, полезная нагрузка ссылки составляет 1500 байтов. Этот сегмент также не пересекает шлюз и никогда не учитывается.

  5. Шлюз отправляет пакет ICMP типа 3 с кодом 4 (пункт назначения недоступен - необходима фрагментация) обратно на сервер, ссылаясь на пакет, отправленный в событии 3. Пакет ICMP указывает, что MTU следующего перехода составляет 1500. Это кажется бессмысленным, так как сеть чиста на 1500 байт, а полезные данные ссылки в 3 и 4 уже были в пределах заявленного предела в 1500 байт. По понятным причинам сервер игнорирует этот ответ. (Первоначально ICMP был отключен чрезмерно усердным брандмауэром, но это было исправлено.)

  6. После значительной задержки (и в некоторых конфигурациях дублирования ACK от сервера) сервер решает повторно отправить сегмент из события 3, на этот раз только. За исключением поля идентификации IP и контрольной суммы, кадр идентичен кадру в событии 3. Они являются такая же длина и новый по-прежнему установлен флаг «Не фрагментировать». Однако на этот раз шлюз успешно передает сегмент клиенту - целиком - вместо того, чтобы отправлять отклонение ICMP.

  7. Клиент подтверждает это, и передача продолжается, хотя мучительно медленно, поскольку последующие сегменты проходят примерно по той же схеме: отклонение, истечение времени ожидания, повторная отправка и последующее прохождение.

Клиент и сервер обычно работают вместе, если клиент перемещается в локальную сеть для прямого доступа к серверу.

Это странное поведение непредсказуемо меняется в зависимости от, казалось бы, несущественных деталей целевого сервера.

Например, на Server 2003 R2 тестовый файл размером 7 МБ будет передаваться более 7 часов, если брандмауэр Windows включен (даже если он разрешает HTTP и все ICMP), в то время как проблема не возникает вообще, и как это ни парадоксально отказ никогда не будет отправлен шлюзом если брандмауэр Windows был отключен. С другой стороны, на Server 2008 R2 отключение брандмауэра Windows не имело никакого эффекта, но передача, хотя и была нарушена, происходила намного быстрее, чем на Server 2003 R2 с включенным брандмауэром. (Я думаю, это потому, что 2008 R2 использует более разумную эвристику тайм-аута и быструю повторную передачу TCP.)

Что еще более странно, проблема исчезла бы, если бы WireShark был установлен на целевом сервере. Таким образом, чтобы диагностировать проблему, мне пришлось установить WireShark на отдельной виртуальной машине для наблюдения за сетевым трафиком на стороне локальной сети (возможно, в любом случае это лучшая идея по другим причинам).

Хост ESXi - это версия 5.0 U2.

Вы не можете отбросить сообщения, требующие фрагментации ICMP. Они необходимы для обнаружения pMTU, что необходимо для правильной работы TCP. Пожалуйста, LART администратор брандмауэра.

Согласно правилу прозрачности, маршрутизатор с фильтрацией пакетов, действующий как брандмауэр, который разрешает исходящие IP-пакеты с установленным битом «Не фрагментировать» (DF), НЕ ДОЛЖЕН блокировать входящие ошибки ICMP Destination Unreachable / Fragmentation Needed, отправленные в ответ на исходящие пакеты от достижения хосты внутри брандмауэра, так как это нарушит совместимое со стандартами использование обнаружения Path MTU хостами, генерирующими законный трафик. - Требования к брандмауэру - RFC2979 (курсив в оригинале)

Это конфигурация, которая уже более десяти лет признается в корне сломанной. ICMP не является обязательным.

Я наконец разобрался с этим. Оказалось, что это проблема с реализацией VMware разгрузки сегментации TCP в виртуальном сетевом адаптере целевого сервера.

Стек TCP / IP сервера отправит один большой блок вместе с сетевым адаптером, ожидая, что сетевая карта разбивает его на сегменты TCP, ограниченные MTU канала. Однако VMware решила оставить это в одном большом сегменте до тех пор, пока… ну, я не уверен, когда.

Кажется, что он фактически остался одним большим сегментом, когда достиг стека TCP / IP шлюзовой виртуальной машины, что вызвало отказ.

В итоговом пакете ICMP была скрыта важная подсказка: IP-заголовок отклоненного пакета указывал размер 2960 байт - намного больше, чем фактический пакет, который он, по-видимому, отклонял. Это точно такой же размер сегмента TCP, который был бы на проводе, если бы он объединил данные из оба сегмента отправлено до сих пор.

Одна вещь, которая затрудняла диагностику проблемы, заключалась в том, что передаваемые данные на самом деле был разделены на фреймы по 1500 байт, насколько может видеть WireShark, запущенный на другой виртуальной машине (подключенной к тому же vSwitch в отдельной группе беспорядочных портов). Я действительно не уверен, почему виртуальная машина шлюза увидела один пакет, а виртуальная машина WireShark - два. FWIW, на шлюзе не включена большая разгрузка приема - я мог понять, было ли это. Виртуальная машина WireShark работает под управлением Windows 7.

Я думаю, что логика VMware в отсрочке сегментации заключается в том, что если данные должны поступать на физическую сетевую карту, можно использовать фактическую разгрузку оборудования сетевой карты. Однако это кажется ошибочным, что он не сможет сегментировать перед отправкой в ​​другую виртуальную машину, и в этом отношении непоследовательно. Я видел, что такое поведение упоминалось в другом месте как ошибка VMware.

Решением было просто отключить разгрузку сегментации TCP на целевом сервере. Процедура зависит от ОС, но вот что:

В Windows в свойствах подключения на вкладке «Общие» или «Сеть» нажмите «Настроить ...» рядом с адаптером и перейдите на вкладку «Дополнительно». Для Server 2003 R2 это дается как «Разгрузка сегментации IPv4 TCP». Для Server 2008 R2 это «большая разгрузка отправки (IPv4)».

Это решение является своего рода кладжем и может повлиять на производительность в некоторых средах, поэтому я все равно приму любой лучший ответ.

У меня были те же симптомы, и проблема оказалась в этой ошибке ядра: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=754294

Я видел ту же проблему на хостах Linux.

Решение состояло в том, чтобы деактивировать разгрузку большого приема (LRO) в сетевом драйвере (vmxnet) шлюза.

Чтобы процитировать базу знаний VMware:

LRO повторно собирает входящие сетевые пакеты в более крупные буферы и передает полученные в результате более крупные, но меньшее количество пакетов в сетевой стек хоста или виртуальной машины. ЦП должен обрабатывать меньше пакетов, чем при отключенном LRO, что снижает его использование для работы в сети.

Видеть http://kb.vmware.com/kb/2055140

Таким образом, пакеты, поступающие на машину шлюза, были объединены сетевым драйвером и отправлены в сетевой стек, который отбросил их больше, чем MTU ...