Фрагментация в IP сетях и такие вещи как tcp adjust-mss и ip mtu

Дорогой друг! В этот раз поговорим о том, что нарисовано в заголовке, хотя и без того немало писано на эту тему. Побудило меня изложить сие собственное нечеткое понимание до определенного момента того, зачем  именно нужны команды tcp adjust-mss и ip mtu и, главное. в чем их отличие. Ну и так как обе команды своим появлением обязаны такому явлению как фрагментация, и о ней придется упомянуть, дабы все было складно и лаконично.

Фрагментация IP пакетов — что, зачем и надо ли

Фрагментация — есть порубание IP пакетов эпического размера на много маленьких пакетиков. Весь процесс происходит исключительно на сетевом уровне — берется IP пакет и все данные, следующие сразу за заголовком пакета разбиваются на несколько частей, каждая из которых снабжается своим собственным заголовком. Картинка для наглядности (кликабельно):

Фрагментация IP пакетаПо картинке: на входящий интерфейс маршрутизатора со стандартным для ethernet размером MTU в 1500 байт прилетает IP пакет, размер/MTU которого вполне себе помещается в этот интерфейс. И оно бы хорошо, но роутер вовремя осознает, что дальше этот пакет придется отправить в более тощий интерфейс, MTU у которого составляет всего 500 байт. Чтобы это сделать, роутер рубит данные следующие за заголовком пакета на три части, каждую из них снабжает собственным IP заголовком и выплевывает наружу получившиеся три пакета. На всякий случай, под MTU (Maximum Transmission Unit) понимается весь пакет, т.е. IP заголовок плюс данные за ним следующие (на рисунке, MTU — это размеры, указанные в нижней части каждого пакета).

В чем проблема?

Проблема в том, что фрагментация — это всегда плохо, кроме случаев, когда без нее нельзя. Плохо, во первых, потому, что роутер, который рубит пакет, сильно напрягается во время этого занятия, а роутеры, следующие на пути пролетающих кусков пакета сильно напрягаются обратно собирая их в исходное состояние, прежде чем отправить дальше, а может даже и снова разрубить. Во вторых, плохо потому, что каждый фрагмент — это новый IP заголовок, и, соответственно, новые 20 Байт, что, конечно, не есть тьмакакмного, но тоже нафиг не нужный оверхэд. Написал последнее предложение и подумал, что это бред:). Какой нафиг оверхэд, ведь когда на роутер сразу будут прилетать пакеты меньше или равные 500 Мбайт, у них уже будут эти же IP заголовки.  Посему, основной недостаток — Fragmentation is tooo processor and memory intensive task и ее нужно избегать.

Как проблема решается?

Ну, как обычно, двумя способами.

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

Второй способ, реалистичный, это когда задействуется механизм, называющийся PMTUD или Path MTU Discovery. Снова картинка и немного текста под ней:

Path mtu discovery

1. Перед отправкой в сеть любого пакета, каждый хост устанавливает в IP заголовке флаг DF = 1. Это означает, что такой пакет фрагментировать нельзя в принципе и если он целиком не влезет в интерфейс любого маршрутизатора на пути его следования, несчастный просто будет жестоко уничтожен.

2. Маршрутизатор получает это пакет, видит, что он больше чем то, что можно засунуть в его выходной интерфейс и что порубить пакет уже не получится. С учетом полученной информации роутер отбрасывает такой пакет и шлет в адрес приславшего этот пакет хоста ICMP пакет типа 3 с кодом 4, в котором говорится, что «Fragmentation needed and DF bit is set». Т.е. «я бы его порубал, но ты установил DF». В этом же ICMP сообщении роутер сообщает примлемый для него MTU, который, в данном случае, равен 500 Байт.

3. Хост, получив тот самый ICMP type 3 code 4 с рекомендуемым размером MTU все понимает, уменьшает MTU в соответствии с принятыми указаниями и выбрасывает уменьшенный пакет в сторону роутера. Теперь маршрутизатор больше не имеет претензий к размеру прилетевшего IP пакета, посему спокойно пересылает его дальше.

Так это и успешно работает в действительности в большинстве случаев по умолчанию. Любое устройство перед отправкой пакета устанавливает в нем DF бит, тем самым запрещая его фрагментацию, а маршрутизирующие устройства, встречающиеся на пути таких пакетов, посредством icmp type 3 code 4 дают понять какого размера пакет может через них пройти.

Но, во всей этой стройной картине может возникнуть проблема, когда что-то блокирует те самые icmp type 3 code 4 сообщения, не давая хосту, отсылающие слишком крупные пакеты, понять, что их размер надо бы поуменьшить. Это может быть или сетевой файервол или неадекватно настроенныей межсетевой экран самого хоста, отправляющего пакеты (напр  iptables). В этом случае роутер изо всех сил пытается сообщить на ту сторону, что «в меня пакеты такого размера не влезут!», но тот так ничего об этом и не узнает, т.к. нужные ICMP до него просто не долетают. Ну и снова для наглядности:

path mtu discovery icmp blockingЭто еще называют black hole в PMTU discovery. Почти как та, что в космосе, только помельче. Возникнуть такая штука может и у тебя в сети, если сеть большая и в ней много маршрутизаторов, МСЭ и прочих штук, на которых ты, одержимый безопасностью, решил заблокировать все подряд. Или может возникнуть оно в сети провайдера, с чем я лично не встречался, но кто-то, видимо, имел опыт. Проявляться оно может по разному. Например, ты хочешь открыть сайт, а он не открывается. Страница вроде как начинает загружаться, но дальше заголовка дело не идет, потому как заголовок передался в маленьких пакетах, которые меньше MTU пути, а оставшаяся часть страницы хочет прилететь в пакетах побольше, которые уже не проходят, но сервер, отсылающий их тебе, об этом не знает. Или ты можешь подключиться куда-нибудь по FTP и начать скачивать файл. Само подключение и авторизация прошли нормально (маленькие пакетики), а файл так и не загружается (пакетики покрупнее). Ну и так далее в том же духе.

Бороться с этим можно или поиском того места, где блокируются важные icmp type 3 code 4 сообщения или посредством модификации MSS в заголовках TCP (естественно, применимо только для TCP сессий) на некоторых роутерах, находящихся на пути трафика. Но о втором способе чуть позже.

Теперь поговорим о GRE тунелях и особенностях их настройки с позиции темы статьи на роутерах Cisco ISR.

И будем использовать такую простую картинку:

GRE_tunnel_mtu

В этой ситуации, представим, что хост 1 шлет пакеты в адрес хоста 2 и размер этих пакетов, скажем, составляет 1000 Байт. Что произойдет? Правильно, будет все хорошо. Просто все хорошо, без пояснения. Теперь, пусть хост 1 послал в адрес хоста 2 IP пакет размером 1480 Байт. Что произойдет теперь? Теперь снова все будет хорошо, но уже не с первого раза и с использованием механизма PMTU Discovery. Чтобы понять, почему так произойдет, достаточно посмотреть в этой статье на формат и размер заголовков стандартного GRE пакета. Ну на всякий случай, еще раз, вот так он выглядит, если размер изначального пакета (его MTU, на картинке это подписано как Original IP Packet), до упаковки в заголовок GRE составлял 100 Байт:GRE ЗаголовокВ нашем случае размер оригинального пакета составляет не 100, а 1480 байт. После того, как добавим к этому добру заголовок GRE и новый IP заголовок (тот, что желтым), размер пакета увеличится еще на 24 Байта, в результате получим IP пакет размером 1504 Байт.

При работе с чистым GRE роутер ведет себя как грамотный персонаж. Он знает, что если пакет предстоит упаковать в GRE заголовок, т.е. отправить в туннельный интерфейс (пусть будет Tunnel 0), то MTU туннельного интерфейс должно быть не больше чем 1476 Байт, т.к. сам GRE заголовок добавит еще 24 байта (см. картинку), что в сумме даст 1500 Байт = MTU физического интерфейса f0/0. Поэтому, получив от хоста 1 пакет в 1480 байт роутер его уничтожит и отправит хосту ICMP type 3 code 4, в котором сообщит, что MTU должно быть 1476. После этого хост уменьшит MTU до нужного значения и без проблем достучится до хоста 2.

А теперь представим другую ситуацию, которая уже ближе к сути сего текста и почти касается вопроса команд tcp adjust mss и ip mtu

Представим, что на картинке выше между роутерами настроен уже не просто GRE туннель, а GREoverIPSec в одном из вариантов.

Т.е. теперь, если бы оригинальный пакет составлял в размере всего 100 Байт, к нему бы, помимо 24 байт GRE заголовка, о которых роутер знает (и учитывает в работе PMTU Discovery, понижая MTU до 1476) прицепились бы еще заголовки, добавленнные IPSec, в общей сложности аж 60 байт (Новый IP заголовок+ESP header+ESP Trailer + ESP Auth). И вот эти лишние 60 байт роутер уже при работе PMTU Discovery не считает.GRE over IPSec

Теперь хост 1 снова шлет в сторону маршрутизатора тем же размером в 1480 Байт. Маршрутизатор получает его, говорит, что 1480 много и нужно чтобы было 1476. Хост пересылает пакет уменьшив MTU до указанных 1476 Байт. Роутер добавляет к этому пакету заголовок GRE (+4 байта), вешает на него новый IP заголовок (+20 байт), что уже дает 1500 байт = MTU интерфейса fa0/0. Но теперь ему нужно этот пакет в 1500 байт еще упаковать в IPSec со всеми пречитающимися заголовками, хедерами и трейлерами. В случае с исходным пакетом в 1480 байт к получившимся после упаковки в GRE пакету в 1500 байт добавится еще как минимум 60 байт (а то и больше, в зависимости от алгоритмов шифрования), что превзойдет допустимый на интерфейсе MTU.

Что должен роутер сделать в такой ситуации? У него два пути. Фрагментирование или уничтожение пакета. На практике обычно случается первый вариант (даже если DF бит стоял IP заголовке исходного пакета в 1480 байт, в новом IP заголовке, который дорисовал GRE, его может не быть, поэтому фрагментация возможна). Т.е. роутер, берет GRE пакет в 1500 байт, шифрует его и получившийся переросший зашифрованный пакет фрагментирует на два (или больше), нещадно расходуя свои ресурсы. Его IPSec пир на той тороне, получива два таких куска, прежде чем их расшифровывать будет вынужден сначала собрать эти два куска воедино, также тратя на это много энергии. Результат — сильное снижение производительности, замедление трафика при большом числе соединений через туннель. То есть — ничего хорошего. Тут описан один из вариантов проблемы, который решается фрагментацией, хотя на деле их может быть несколько. Но общая суть следующая. В подобных схемах, где есть и GRE и IPSec,  MTU туннельного GRE интерфейса с учетом всех возможных манипуляций по раздуванию размера итогового IP пакета при работе IPSec и самого GRE, должен быть установлен в 1400 Байт. Это такой best practice. Если роутер будет знать, что у него на интерфейсе Tunnel 0 MTU = 1400 байт и в результате работы механизма PMTUD скажет об этом размере хосту 1, какие бы заголовки дальше роутер не вешал на этот пакет, его итоговый размер все равно не превысит 1500 Байт, соответствующие MTU исходящего интерфейса f0/0.

Для этого и используются команды, которые вешаются на тунельные интерфейсы:

ROUTER-1(config-if)#ip mtu ?
<68-17916> MTU (bytes)

и

ROUTER-1(config-if)#ip tcp adjust-mss ?
<500-1460> Maximum segment size in bytes

 Сначала про IP mtu

С ним все просто. Прямо вручную задается, какой MTU должен быть на туннельном интерфейсе, обычно это, как написано выше, 1400 байт, и после этого не имеем никаких проблем с фрагментацией.  Больше и писать то не очем. Единственный случай, когда этой команды для решения проблем с «большими пакетами» может не хватить — случай, описанный выше, где между роутерами стоит файервол, блокирующий ICMP (в том числе и type 3 code 4) при том, что у нас нет к нему доступа, т.е. мы никак не можем разрешить прохждение нужных ICMP. Тогда, роутер хоть и попросит отсылающий пакет хост 1 уменьшить до 1400 байт, хост 1 об этом не узнает. И еще один момент. Дабы не было никаких проблем, ip mtu должен быть обязательно выставлен с обоих концов GRE туннеля, т.е. на туннельных интерфейсах каждог из взаимодействующих роутеров, дабы у них не возникло взаимного недопонимания.

 Теперь про ip tcp adjust-mss

Если раньше речь шла исключительно о сетевом уровне, где есть только IP заголовок и следующие за ним данные, то тут уже появляется четвертый, транспортный уровень модели OSI. Команда, как видно, имеет действие только на TCP трафик, поэтому дальше говорим только о нем. Тут нужно понимать, что такое MSS в терминологии TCP. А MSS (Maximum Segment Size) — это общий размер данных, идущих сразу же за TCP заголовком. Картинка:

mss_and_mtu

Из картинки видно, что MSS = IP MTU — IP заголовок — TCP заголовок. Т.е. это MTU минус 40 Байт. И отсюда же понятно, что когда изменяется MTU, это означает, что изменяется MSS, т.к. размер заголовков IP и TCP всегда одинаковый — по 20 байт. Получается, что можно подстроить MTU на нужном интерфейсе командой #ip mtu как описано выше, или подстроить MSS, командой #ip tcp adjust-mss но результат результат при этом будет один и тот же — уменьшится MSS, а как следствие — MTU. В чем тогда принципиальная разница?

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

Что касается MSS — его между собой согласовывают взаимодействующие хосты, а не транзитные для трафика сетевые устройства. Хосты прямо в рамках установления TCP сессии говорят друг другу, какой MSS для каждого из них приемлем, потом они выбирают наименьшее для них двоих значение и все пакеты, которые будут передаваться в рамках этой TCP сессии будут иметь именно такой MSS. Для наглядности вставлю картинку с cisco.com:

tcp_mssТут у client A стандартное для сети ethernet MTU равное 1500 Байт, а соответственно MSS = 1500-40= 1460 Байт. У клиента B MTU и MSS равны соответственно 4462 и 4422, что свойственно для сетей token ring. В итоге они соглашаются использовать меньшее MSS, равное 1460 байт, которое подходит для них обоих. Еще раз, эти MSS, удобные для каждого из них, хосты сообщают друг другу при обмене пакетами SYN SYN/ACK и ACK.

Теперь что же делает команда #ip tcp adjust-mss? Например, в соответствии с принятыми ранее best practices, мы хотим установить MSS равным 1360 Байт, чтобы MTU был 1400 Байт. Смотрим опять на картинку с двумя хостами.

1. Хост 1 шлет хосту 2 SYN пакет в котором говорит, что у него MSS равен 1460 Байт.

2. Роутер, ближайший к хосту 1, у которого в настройках туннельного интерфейса написано #ip tcp adjust-mss 1360,  смотрит на этот syn пакет и переписывает указанный там MSS с 1460 на 1360.

3. Хост на том конце — хост 2 — видит, что хост 1 хочет согласовать MSS = 1360, вместо 1460, который он увидел бы без вмешательства роутера.

4. Хост 2 сообщает в своем SYN/ACK свой MSS, который равен 1460. Проходя через туннельный интерфейс того же маршрутизатора, ближайшего к хосту 1,  в SYN/ACK размер MSS также переписывается на 1360 Байт и хост 1 получает от хоста 2 такой же желаемый MSS в 1360 Байт.

5. Сессия между хостом 1 и хостом 2 устанавливается и все, передающиеся в рамках этой сессии пакеты имеют MSS не больше 1360 байт, а, следовательно MTU, не превышающий 1400 Байт.

Преимущество tcp adjust-mss в том, что это более умная команда, которая залезая в сессию между хостами, делает так, что они сами согласовывают между собой правильный MSS и, соответственно, правильный MTU. Ее не нужно вводить на всех транзитных роутерах, а достаточно ввести только на одном. В этом случае, даже если на пути прохождения трафика есть неадекватные неподконтрольные тебе МСЭ, блокирующие icmp type 3 code 4, нужные для PMTU Discovery, нет ничего страшного. С помощью ip tcp adjust mss хосты сами (с помощью лишь ближайших к ним роутеров, подкорректирующих MSS) установят нужный MSS. В этом случае PMTU Discovery не нужен вообще. Но, ествественно, работает это только для TCP трафика.

Вот кста, хорошая статья с cisco.com для детального осознания изложенного.

Тут меня немного отвлекли, вынужден продолжить чуть позже, если не забуду:)


Не забывайте оставлять комментарии, если пост был вам полезен!
Опубликовано в Сети Метки: , , , ,
Заодно посмотрите мои фоты в моем профиле вконтакте. Любые вопросы по существу статей можете задать там же.
Hostenko — лучший WordPress-хостинг