Столкнулся я с одной проблемой, которую интуитивно удалось решить, но при этом до конца не ясно почему она возникла. Описываю ситуацию: Поставил на удаленном объекте cisco 881, подключил этот объект к DMVPN хабу. К циске 881 подключил точку доступа. Вроде gre туннель поднялся, маршруты прошли, компьютеры увидели корп. сеть, интернет (через офис) и т.д. Создалось ощущение, что все заработало. Тем не менее возникла проблема при подключении клиентов через wi-fi. Клиенты (ipad, android, ноутбуки с виндой) вроде подключились, но заработали как-то непонятно и все по разному. К примеру один iphone выходит в интернет (имеется ввиду через браузер), но не может выйти в appstore. Другой iphone выходит и в интернет и в appstore. Аналогично с андроидом (кто то попадает в интернет, кто-то в интернет и play market, а кто-то никуда не может попасть). На файерволе эти подключения не блокируются 100% (до циски там стоял dlink dfl 210 который терминировал ipsec туннель с офисом и все работало)
На туннельном интерфейсе стояло значение ip mtu 1400. Помогло выставление значения ip tcp adjust-mss 1360 на туннельном интерфейсе.
Вопрос у меня такой: Почему возникали такие проблемы в работе до того как я задал значение ip tcp adjust-mss? Как мне казалось задание значения mtu должно быть достаточно. Если я правильно понимаю единственная ситуация когда могут возникать проблемы это ситуация когда клиент отправляет пакет большего чем 1400, причем ставит DF бит в значение 1. Но в такой ситуации как я опять таки понимаю маршрутизатор формирует ICMP пакет отправителю в котором говорит клиенту уменьшить mtu до 1400. Т.е в результате должно работать и без задания значения mss. Либо я что-то до конца не понимаю?
Буду очень благодарен если кто-то может объяснить мне причину возникновения проблем без параметра ip tcp adjust-mss.
Еще несколько слов о Path MTU Discovery Black Hole
Еще несколько слов о Path MTU Discovery Black Hole
Вместо вступления
Однажды для каждого настоящего системного администратора (или исполняющего обязанности такового) наступает момент истины. Ему выпадает судьба настроить маршрутизатор на компьютере с установленной ОС GNU/Linux. Те, кто это уже прошел, знают, что ничего сложного в этом нет и можно уложиться в пару команд. И вот наш админ находит эти команды, вбивает их в консоль и гордо идет к пользователям сказать, что уже все работает. Но не тут-то было – пользователи говорят что их любимые сайты не открываются. После траты некоторой части своей жизни на выяснение подробностей обнаруживается, что большая часть сайтов ведет себя следующим образом: 1. При открытии страницы загружается заголовок и больше ничего; 2. В таком состоянии страница висит неопределенно долгое время; 3. Строка статуса браузера все это время показывает что загружает страницу; 4. Пинги и трассировка до данного сайта проходят нормально; 5. Соединение по telnet на 80 порт тоже проходит нормально. Обескураженный админ звонит в техподдержку провайдера, но там от него быстро избавляются, советуя попробовать настроить маршрутизатор на OC Windows, а если уж и там не работает тогда… купить аппаратный маршрутизатор. Я думаю, эта ситуация знакома многим. Некоторые в нее попадали сами, у кого-то с ней сталкивались знакомые, а кто-то встречал таких админов на форумах и прочих конференциях. Итак: если у Вас Такая Ситуация, то — Поздравляю! Вы столкнулись с Path MTU Discovering Black Hole. Данная статья посвящается тому, отчего это бывает, и как решить эту проблему.
Термины, необходимые для понимания статьи
MTU (Maximum Transmission Unit) – этот термин используется для определения максимального размера пакета (в байтах), который может быть передан на канальном уровне сетевой модели OSI. Для Ethernet это 1500 байт. Если приходит пакет большего размера (например по Token Ring), то данные пересобираются в пакеты размером не более MTU ( т е не более 1500 байт). Операция пересборки пакетов под другой MTU называется фрагментацией (fragmentation) и является затратной для маршрутизатора. PMTU (Path MTU) — данный параметр обозначает наименьший MTU среди MTU каналов данных, находящихся между источником и приемником. PMTU discovery – технология определения PMTU разработанная для уменьшения нагрузки на маршрутизаторы. Описана в RFC 1191 в 1988 году. Суть технологии заключается в том, что при соединении двух хостов устанавливается параметр DF (don’t fragment, не фрагментировать), который запрещает фрагментацию пакетов. Это приводит к тому, что узел, значение MTU которого меньше размера пакета, отклоняет передачу пакета и отправляет сообщение ICMP типа Destination is unreachable (Хост недоступен). К сообщению об ошибке прилагается значение MTU узла. Хост-отправитель уменьшает размер пакета и отсылает его заново. Такая операция происходит до тех пор, пока пакет не будет достаточно мал, чтобы дойти до хоста-получателя без фрагментации. МSS(Maximum Segment Size) — максимальный размер сегмента, т.е. самая большая порция данных, которую TCP пошлет на удаленный другой конец соединения. Рассчитывается по следующей формуле: MTU_интерфейса – Размер_IP_заголовка(20 байт) – Размер_TCP_заголовка(20 байт). Итого обычно это 1460 байт. Когда соединение устанавливается, каждая сторона может объявить свой MSS. Выбирается наименьшее значение. Подробнее можно посмотреть здесь. Флаг DF(Don’t fragment) – Бит в поле флагов заголовка IP пакета, который будучи установленным в единицу сообщает о том, что данный пакет запрещено фрагментировать. Если пакет с таким флагом больше, чем MTU следующей пересылки, то этот пакет будет отброшен, а отправителю посылается ICMP ошибка «фрагментация необходима, однако установлен бит не фрагментировать» (fragmentation needed but don’t fragment bit set).
Тестовый полигон
С данной проблемой лучше всего знакомится на практике (но не в цейтноте, когда начальство орет над ухом). Для этого я создал тестовую сеть, изображенную на рис.1
Рис. 1. Тестовая сеть.
Это упрощенный вариант глобальной сети. Роли: 1. Компьютер с именем deb-serv-03 представляет собой наш маршрутизатор на Linux. Внимание – на его интерфейсе eth2 размер MTU уменьшен до 1400 байт; 2. deb-serv-05 – клиент в локальной сети; 3. deb-home – маршрутизатор, расположенный у провайдера; 4. deb-serv – Веб-сервер в Интернете с которым мы хотим обмениваться данными. Получаем с www.site.local, расположенном на нем страничку размером в 5,9Кб. Конечно, в реальности цепочка гораздо больше, но для показательного примера этого хватит. Все компьютеры данной сети работают под управлением Debian GNU/Linux 5.0 Lenny. В разных точках сети я контролирую ситуацию с помощью программы tcpdump.
Нормальное определение PMTU
Для начала посмотрим, что происходит в сети при открытии страницы. Изучаем, как пойдут пакеты с веб-сервера. Смотрим на вывод TCPDUMP#1 (на eth0 deb-serv):
Я привожу только первые 10 пакетов и обрезал в стандартном выводе tcpdump все лишнее. Разбираем: 1. В строках с 1-ой по 3-ю мы видим установку tcp соединения. Стороны обмениваются пакетами SYN, SYN-ACK, ACK. Здесь стоит обратить внимание на поле опций, а именно на параметр MSS, которым обмениваются стороны. С обеих сторон это 1460 байт. Значит максимальный размер пакетов, которые стороны будут посылать друг другу, составит 1460(MSS)+20(TCP Заголовок)+20(IP Заголовок)=1500 байт. 2. В строке 4 отправка запроса на получение веб страницы от deb-serv-05. В строке 5 подтверждение получения данного пакета. 3. В строке 6 мы видим отправку ответа на запрос (т.е. отправку куска веб-страницы). Вероятно из-за особенностей pcap на данном интерфейсе tcpdump видит один пакет размером в 2948 байт, в то время как в сеть уйдут 2 пакета размером 1500 и 1452 байта соответственно. Если посмотреть более подробный вывод tcpdump, то увидим, что на данном пакете(точнее пакетах) стоит флаг DF: IP (tos 0x0, ttl 64, id 5177, offset 0, flags [DF], proto TCP (6), length 2948) 192.168.0.1.80 > 172.16.5.3.48547: Flags [.], seq 1:2897, ack 118, win 181, options [nop,nop,TS val 86620459 ecr 4922429], length 2896 4. Когда эти пакеты с данными доходят до deb-serv-03 они отбрасываются, так как не могут пройти по соединению с MTU 1400 и не могут быть фрагментированы(флаг DF), а в ответ генерируется сообщение ICMP тип 3 код 4: ICMP 172.16.5.3 unreachable — need to frag (mtu 1400), которое мы видим в строке 7 ( в строке 10 приходит сообщение для 2-го пакета). В этом сообщении передается нужный MTU. 5. В строках 8 и 9 мы наблюдаем как deb-serv, получив MTU=1400, отправляет тот же самый кусок веб страницы в пакетах размером 1400 байт. Данные пакеты доходят до deb-serv-05, где генерируется подтверждение, и так повторяется до тех пор, пока вся страница не будет передана. Размер всех последующих пакетов будет не больше 1400 байт. На этом примере демонстрируется процедура определения Транспортного MTU (PMTU), описанная в RCF1911. Я представил ее в упрощенном виде на рис 2.
Рис 2. Процедура определения PMTU.
Встреча с Path MTU Discovery Black Hole
А теперь представим, что к провайдеру пришел новый специалист и решил (например в целях защиты от icmp флуда) запретить пересылку icmp пакетов через deb-home, который теперь в его ведении. Смотрим что получается: Вывод TCPDUMP#1 (на eth0 deb-serv):
Как видите, ситуация вполне ожидаемая. Первые 6 строк в каждом выводе точно такие же, как и при нормальной передаче (см. описание в предыдущем примере). Но вот дальше начинаются расхождения. ICMP 3:4 точно так же генерируется на deb-serv-03 (строки 7, 9 11.13, 15, 17, 19 в TCPDUMP#2), но deb-serv его не получает и продолжает слать пакеты размером в 1500 байт(строки с 6 по 12 в TCPDUMP#1 и 6, 8, 10, 12, 14, 16, 18 и 20 в TCPDUMP#2). С каждым разом время между повторной посылкой все увеличивается (в данных примерах я отбросил временые метки, но на самом деле так работает механизм ретрансмита TCP). Никаких данных размером большим, чем PMTU, в таком случае не передать. Но увы, TCP этого не знает и продолжает слать пакеты с MSS, выбранным в момент установки соединения. Именно эта ситуация и называется Path MTU Discovery Black Hole (Черная дыра в определении транспортного MTU). Я постарался представить ее в упрощенном виде на рис. 3.
Рис. 3. Черная дыра в определении PMTU.
Эта проблема совсем не нова. Она описана в RFC 2923 в 2000 году. Но тем не менее, продолжает встречаться с завидным упорством у многих провайдеров. А ведь именно провайдер виноват в данной ситуации: не нужно блокировать ICMP тип 3 код 4. Причем слушаться «голоса разума» ( т. е. клиентов, понимающих в чем проблема) они обычно не хотят.
Решение проблемы с PMTU
Не будем звонить в техподдержку, а попробуем решить проблему, исходя из собственных средств. Разработчики Linux, тоже знающие о ней, предусмотрели специальную опцию в iptables. Цитата из man iptables:
—set-mss value Explicitly set MSS option to specified value.
These options are mutually exclusive.
Мой вольный перевод для тех, у кого туго с английским:
—set-mss значение Явная установка в опции MSS специфического значения.
Разбираем: 1. В строках 1-3 мы уже привычно наблюдаем установку TCP соединения. Но обратите внимание на значения MSS. В TCPDUMP#1 от deb-serv-05 приходит значение 1360, в то время как в TCDUMP#3 видно, что уходит пакет с MSS=1460. Именно так и работает правило с –set-mss 1360. Оно редактирует значение MSS у пролетающих пакетов. Для SYN пакета, пришедшего в ответ, это значение тоже отредактировано. 2. В строках 4 и 5 обоих выводов мы опять наблюдаем отправку GET запроса и подтверждение получения. 3. В строке 6 для TCPDUMP#1 и строках 6 и7 для TCPDUMP#3 видим отправку пакетов с данными, но теперь размер каждого из пакетов не превышает 1400 байт. Опять происходит странный глюк с TCPDUMP#1, где виден один большой пакет, в то время как в TCPDUMP#3 мы наблюдаем приход 2-х пакетов. 4. Дальнейший обмен пакетами идет в соответствии с правилами протокола TCP. Но ни разу размер пакета на превышал 1400 байт.
В упрощенном виде поведение MSS представлено на рис. 4. Я не стал показывать обмен данными, так как он аналогичен обычному поведению. Рис. 4. Изменение MSS на лету.
Хотя в man iptables описаны две опции, но я пока примененил только одну. Нужная опция зависит от конкретной ситуации. Все ситуации можно разделить на 2 типа:
1. На вашем маршрутизаторе сайты открываются нормально, у клиентов в локальной сети наблюдаются проблемы. В этом случае наименьший MTU на всем пути находится именно на вашем сервере. Обычно это некие протоколы инкапсуляции, типа PPPoE, PPtP и тд. Для данной ситуации лучше всего подойдет опция –clamp-mss-to-pmtu, которая автоматически установит минимальный MSS на все транзитные пакеты.
2. На вашем маршрутизаторе и у клиентов в локальной сети сайты не открываются. В таком случае наименьший MTU находится где-то у провайдера и вычислить его стандартными средствами сложновато. Специально для этого я написал небольшой скрипт на python(не особо заботясь о PEP8 и невозможности выстрелить в ногу), который поможет определить необходимый размер MSS для данной ситуации:
Запускать скрипт нужно с правами суперпользователя. Алгоритм его работы таков: 1. Пытаемся получить некоторое количество данных с сайта с нормальным значением MSS. 2. Если это не получается, то понижаем MSS на iptables цепочке OUTPUT до MTU — 40 – LIM. 3. Если и после этого мы не можем получить данные, то выдаем ошибку о том, что LIM имеет слишком маленькое значение. 4. Последовательно наращивая MSS, ищем тот момент, когда данные перестанут поступать. После этого выводим последнее рабочее значение MSS. 5. Если мы дошли до MSS=MTU-40, то выводим ошибку о том, что не можем определить MSS. Данная ситуация является ошибочной, т. к. в пункте 1 проводим аналогичную проверку, и, если результаты не совпадают, это повод задуматься.
После получения нужного MSS необходимо вписать его в соответствующее правило. Можно обойтись и без скрипта, на глаз понизив значение MSS, но лучше выяснить его точно – меньше накладые расходы на пересылку пакетов.
Надеюсь данная статья поможет Вам решить подобную проблему как у себя, так и у ваших друзей и знакомых. Еще раз обращаюсь к специалистам провайдеров – БЕЗ КРАЙНЕЙ НЕОБХОДИМОСТИ НЕ БЛОКИРУЙТЕ ICMP ТИП 3 КОД 4 – этим вы создаете проблемы вашим колегам.
Maximum transmission unit (MTU) это максимальный объём данных, который может быть передан протоколом за одну итерацию. К примеру, Ethernet MTU равняется 1500, что означает, что максимальный объём данных, переносимый Ethernet фреймом не может превышать 1500 байт (без учёта Ethernet заголовка и FCS — Рис. 1).
Рис. 1
Давайте пробежимся с MTU по уровням OSI:
Layer 2.
Ethernet MTU является частным случаем Hardware MTU. Определение Hardware MTU вытекает из общего определения: Hardware MTU — это максимальный размер пакета, который может быть передан интерфейсом за одну итерацию (по крайней мере значение указано в спецификациях устройства – по факту некоторые чипсеты поддерживают передачу больших размеров пакетов, чем заявлено). Поэтому если взглянуть на рисунок 1 в отрыве от Ethernet, то получим следующее: Рис. 2
Замечание: Однако и тут не обойтись без оговорки. Как вы видите, HW MTU (Ethernet MTU в частности) не включает заголовок L2 в себя. Однако это справедливо для IOS и IOS XE, но для IOS XR и JunOS заголовок L2 включен в размер HW MTU – Рис. 3. Эта особенность может привезти к проблемам при установке OSPF neighborship между платформами под управлением IOS(XE) и IOS XR (OSPF требует совпадения MTU в Hello пакетах). Поэтому, при конфигурации MTU для Ethernet интерфейсов, на стороне IOS XR MTU должно быть на 14 байт больше (12 байт src mac+dst mac и 2 байт EtherType). К примеру, MTU в 1500 в Cisco IOS эквивалентно MTU в 1514 для IOS XR.
Рис. 3
Конфигурация и проверка.
Для того что бы изменить MTU на маршрутизаторах под управлением Cisco IOS используется команда интерфейс уровня:
Layer3.
IP MTU определяет максимальный размер пакета с IP заголовком, который может быть передан на данном интерфейсе не прибегая к фрагментации. Зависимость между IP MTU и HW MTU описывается следующей формулой: IP MTU ≤ HW MTU Соответственно, когда на интерфейс попадает пакет, превосходящий установленное IP MTU, пакет либо подвергается фрагментации, либо, в случае установленного флага DF (DO NOT Fragment) в IP заголовке, дискардится, а устройство может сгенерировать ICMP сообщение Fragmentation Needed, используемое в механизме path MTU discovery (о нём позже), и отправить его назад отправителю исходного пакета.
Конфигурация и проверка.
Для изменения IP MTU на маршрутизаторах под управлением Cisco IOS используется команда интерфейс уровня:
Вот те раз. Команда ip mtu не видна в show run. Да тут есть интересный нюанс – если ip mtu совпадает с hw mtu, то в выводе show run будет отображаться только hw mtu. Если значения разные то отображаются оба.
Layer 4.
TCP Maximum Segment Size (MSS) определяет максимальный размер TCP сегмента (без TCP заголовка!), который может быть использован (отправлен/принят) в ходе TCP сессии. Анонс (именно анонс, не хендшейк) размеров TCP MSS происходит во время установки TCP сессии – принимающая сторона анонсирует стороне отправляющей какой размер TCP сегмент она может принять. Соответственно размер TCP MSS может различаться в рамках одной TCP сессии в зависимости от направления.
Рис. 4
Сторона, производящая анонс, высчитывает значение TCP MSS для себя по следующей формуле: TCM MSS = (IP MTU – [IPHDR + TCPHDR])
Конфигурация.
Тут у нас возможны два сценария – маршрутизатор является транзитным или участником TCP сессии. 1) Транзитное устройство: Для предотвращения дропа пакетов промежуточным устройством в случае наличия линка с малым MTU, маршрутизатор будет прослушивать TCP SYN пакеты и подменять значения MSS анонсируемые конечным устройством. Что приведет к отправке пакетов меньшей величины конечным устройством и вуаля – проблема с дропами на линке с малым MTU упреждена.
2) Терминирующее устройство: Здесь всё просто – маршрутизатор является участником TCP сессии и мы можем установить принудительно, размер MSS который он будет анонсировать.
Кажется всё? Нет, не всё. Вспоминаем про MPLS. Вспоминаем… Закончили вспоминать, переходим к рассмотрению.
Layer 2,5. MPLS.
Рис. 5
MPLS MTU определяет максимальный размер маркированного (кто знает как лучше переводиться Labeled прошу подсказать в комментах) IP пакета. В случае, если размер маркированного пакета превышает MPLS MTU, то пакет либо фрагментируется, либо, при наличии установленного в IP заголовка флага с DF bit, дропается (пока логика как и при превышении IP MTU), с возможной отправкой ICMP сообщения Fragmentation Needed.
Замечание: Вот тут дела обстоят немного по другому, по сравнению c IP MTU. В MPLS сети промежуточный узел может и не иметь маршрута к отправителю пакета, поэтому вместо того что бы слать ICMP сообщение отправителю напрямую, оно инкапсулируется с тем же стеком меток (label stack), что и исходный пакет, и отправляется по его же пути следования. Достигая Egress LSR (конечного MPLS маршрутизатора для данного LSP – за ним уже IP сеть без меток), который знает ip маршруты к узлу отправителя, ICMP сообщение Fragmentation Needed «разворачивается» им, инкапсулируется необходимыми заголовками и отправляется назад в MPLS сеть к отправителю оригинального пакета. Поведение аналогично с TTL Expired, да и в целом скорее относиться к теме MPLS, а не MTU. Поэтому кто не знаком с процессом — www.google.kg/?gws_rd=ssl#q=mpls+ttl+expired
Что здесь ещё интересного? MPLS MTU может быть больше HW MTU (поэтому на Рис. 3 HW MTU частично обозначено пунктиром). При этом IOS выдаст варнинг, но в большинстве случаев будет работать (зависит от чипсета интерфейса) и успешно пропускать по крайней мере baby-giant фреймы. А в иной раз можно получить дроп пакетов, повреждение данных, и сто лет без урожая.
Конфигурация и проверка.
Замечание: MPLS MTU отображается в running конфиге, также как и IP MTU — только в случае, если значение отличается от HW MTU. Но, в отличие от IP MTU, любое изменение HW MTU меняет значение MPLS MTU до значения HW MTU (IP MTU это действие не меняет).
MTU на коммутаторах Cisco.
На заметку администратору.
1) Для того, что бы найти минимальный MTU (забавное сочетание) на сети можно использовать расширенную команду ping, причём как c конечных станций/серверов так и с оборудования Cisco. Пропингуем с маршрутизатора R01 маршрутизатор R02 с выставленным df-bit, c начальным размером пакета в 1000 байт, конечным 1500 байт, и шагом 100 байт. Кол-во повторений 2.
Как видите, проходит только 6 ICMP пакетов размером 1000, 1100, 1200, 1300 байт Начиная с 1400 байт и выше пакеты не проходят. Следовательно, минимальное MTU между двумя точками — 1300 и 1400, что можно уточнить ещё за несколько циклов, ужимая диапазон и умешьшая шаг.
На этом всё. Есть ещё в закромах старый драфт статьи по размерам фреймов и их эволюции, где описаны понятия Jumbo Frame, Baby-Giant Frame, встречающиеся в этой статье. Если посчитаете нужным, могу доработать и выложить и её.