Опубликован: 30.07.2013 | Уровень: для всех | Доступ: свободно
Лекция 10:

Вспомогательные механизмы

Аннотация: Роль приложений в управлении фрагментацией IPv6. Работа с множеством адресов и правила выбора адресов по умолчанию. Особенности API к системам разрешения имен в условиях сосуществования разных протоколов сетевого уровня. Эффективное и безопасное использование множественных подключений (multihoming).

Фрагментировать или нет?

Механизм управления фрагментацией IPv6 требует дополнительных соображений и комментариев, потому что он существенным образом отличается от его аналога в IPv4. Главное отличие, конечно же, в том, что фрагментацию IPv6 может вести только источник, хотя информация об оптимальной длине пакета скрыта дальше в сети.

В первую очередь, такая особенность механизма фрагментации IP влияет на работу транспортных протоколов. Начнем с хрестоматийного примера TCP. Раньше, в среде IPv4, перед TCP было два основных пути:

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

Более хитроумная реализация TCP могла пробовать второй путь, но переключаться на первый, если PMTUD не работает, например, из-за слишком строгой фильтрации пакетов ICMP в сети.

В среде IPv6 первый путь полностью закрыт, потому что флаг DF неявно установлен всегда, а пакеты, длина которых больше PMTU, не достигнут адресата ни при каких условиях. Теперь сам источник пакета должен выбрать его подходящий размер. Как следствие, при переходе к IPv6 растет важность правильной и надежной работы PMTUD.

В первую очередь, этот факт касается сетевых администраторов, увлеченных борьбой с "нежелательным" трафиком ICMP.

Тем не менее, даже ненадежная сигнализация ICMP не мешает проводить PMTUD, используя сквозной принцип1"Надейся в первую очередь на себя, затем на удаленную сторону, и только в последнюю на транзитные узлы". и некоторую эвристику. Например, если "тройное рукопожатие" TCP проходит успешно, но затем оказывается, что полноразмерные сегменты куда-то пропадают — удаленная сторона не квитирует новые данные, — то здесь явно замешан PMTU, и источнику TCP следует понизить размер сегмента. Хотя подсказок в виде очередного значения MTU он не получит, его выручит двоичный поиск, ограниченный снизу заведомо "габаритным" значением (1280 байт в IPv6), а сверху — MTU локального интерфейса. Пробное значение можно повышать, пока сегменты достигают удаленной стороны. Как только оценка окажется завышенной, сегменты перестанут проходить, и надо будет перейти к понижению пробной величины. На этой идее основана так называемая процедура PMTUD уровня пакетизации [RFC 4821].

Тем не менее, PMTUD — не абсолютная необходимость даже в среде IPv6. Теперь минимальный размер MTU равен относительно большой величине, 1280 байт, так что примитивная реализация TCP может себе позволить ориентироваться на эту постоянную. Так же может поступить и более сложный вариант TCP, если он обнаружит, что PMTUD все-таки не работает.

Итак, в среде IPv6 перед TCP открываются следующие пути:

  • сегментировать поток, исходя из величины PMTU 1280 байт;
  • оптимизировать размер сегмента с помощью PMTUD.

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

Представим себе, что некий прикладной протокол работает поверх UDP. В этом случае размер исходящей дейтаграммы задает приложение, и размер этот может достигать внушительной величины. Это не наша фантазия: в реально существующих протоколах, например, в NFS, возникают сообщения длиной порядка нескольких тысяч байт. Как подобная дейтаграмма достигнет адресата?

Первый подход мы уже нащупали: приложение может посредством сетевого API попросить локальный модуль IPv6, чтобы тот фрагментировал пакеты исходя из MTU 1280 байт. Это не самый эффективный, зато простой и надежный путь: из-за своего чрезмерного размера пакеты теряться заведомо не будут.

Тем не менее, пакеты теряются еще по ряду причин, и прикладной протокол должен быть устойчив (или безразличен) к таким потерям. Данное свойство прикладных протоколов, работающих поверх UDP, позволяет оптимизировать размер фрагмента IPv6. Для этого надо, чтобы модуль IPv6 сам выполнял PMTUD. Как это будет работать? Например, так:

  1. приложение шлет данному адресату свое первое большое сообщение;
  2. модуль IPv6 фрагментирует составленный пакет, взяв первым приближением PMTU величину MTU выходного интерфейса;
  3. возможно, такие фрагменты не пройдут всю трассу; но модуль IPv6 примет извещения ICMPv6 "пакет слишком велик" и получит второе приближение PMTU;

Это приближение будет довольно точным благодаря обязательному значению MTU в сообщении "пакет слишком велик". В классическом IPv4 источнику приходилось вести вместо этого поиск вслепую, так как маршрутизатор не подсказывал значения MTU. Впрочем, двоичный поиск сходится довольно быстро. Подумайте, в каком случае двоичный поиск вслепую выиграет у поиска с подсказкой маршрутизатора. (Например, когда число шагов достаточно велико, а MTU каждого нового шага меньше предыдущего - "телескопическая трасса").

  1. приложение обнаружит потерю сообщения, например, не получив отклика удаленной стороны в течение какого-то времени, и повторит сообщение (или пошлет следующее, если в данном протоколе потери можно игнорировать);
  2. модуль IPv6 фрагментирует пакет, используя новое приближение PMTU;
  3. возможно, фрагменты опять не пройдут; но в результате модуль IPv6 снова уточнит величину PMTU;
  4. приложение еще раз повторит сообщение (или пошлет следующее)…

И так до тех пор, пока приближение PMTU не станет меньше или равно его истинному значению для данной трассы. После этого фрагментированные пакеты начнут доходить до адресата, и прикладной сеанс продолжится. Чтобы подобная схема работала, модуль IPv6 должен кэшировать значения PMTU для своих недавних адресатов. Подходящее место для этих сведений — кэш адресатов, DC [§5.2 RFC 1981].

Как мы помним, трасса — это путь по сети, от источника к адресату через транзитные узлы, который проходит (или прошел бы) пакет в данный момент времени. Для простоты мы сейчас не будем говорить о маршрутизации от источника, когда трассу выбирает источник пакета, и маршрутизации согласно политике, когда выбор следующего шага основан на произвольных характеристиках пакета и внешних параметрах. Тогда трасса IP зависит от узла-источника и от адреса назначения пакета, а также от настроек источника и каждого транзитного узла в момент обработки пакета (грубо говоря, от их таблиц маршрутов). Конечно, в "живой" сети трасса может со временем меняться вместе с настройками источника и транзитных узлов. Однако, пока сеть стабильна, трасса остается постоянной хотя бы какое-то время. Именно поэтому источник имеет право кэшировать значения PMTU, используя в роли ключа адрес назначения.

Однозначность соответствия между адресатом и наблюдаемой величиной PMTU может оказаться нарушена, если сеть использует ECMP и пакеты одному адресату могут приходить по разным путям с неодинаковым значением PMTU. Между тем, существующие реализации хоста IP кэшируют одно значение PMTU на адресата еще со времен IPv4, а IPv6 лишь стандартизует эту практику. Поэтому надо с осторожностью применять распределяющие хэш-функции ECMP, зависящие от чего-либо сверх адреса назначения пакета, например, номера вышестоящего протокола или портов TCP/UDP. (Обсудите самостоятельно, насколько допустимо, чтобы такая хэш-функция зависела от адреса источника пакета.)

Еще один путь открывается, когда прикладной протокол позволяет варьировать размер сообщений, например, если приложение сегментирует некий поток байтов или более крупных единиц данных. В этом случае приложение могло бы выбрать такой размер своих сообщений, чтобы их фрагментация на данной сетевой трассе не требовалась .2 Этот прием иногда называют "семантическая фрагментация", так как он требует хотя бы минимального понимания, что значат передаваемые данные. Например, мы его уже встретили в MLDv2 (§6.4). Но, чтобы приложение узнало подходящий размер, требуется обратная связь от локального модуля IPv6 к приложению. Ее тоже можно обеспечить в рамках сетевого API. Скажем, приложение может запрашивать у модуля IPv6 текущее приближение PMTU для данного адресата. Или же модуль IPv6 может подсказывать приложению PMTU по своей инициативе, в виде служебной структуры ,3 Это cmsghdr в терминах API сокетов Беркли. когда приложение ожидает ответа удаленной стороны, а вместо него приходит извещение ICMPv6 "пакет слишком велик".

Наконец, оптимистичное приложение, которое верит в возможности PMTUD, захочет запретить модулю IPv6 фрагментацию своих исходящих пакетов. Такое приложение должно активно следить за текущим приближением PMTU и корректировать размер своих сообщений. Модуль IPv6 и приложение проводят PMTUD в паре: модуль IPv6 обрабатывает извещения ICMPv6 и оценивает PMTU, а приложение генерирует новые пробные пакеты согласно последней оценке.

Именно эти идеи нашли отражение в расширенном API для IPv6, основанном на сокетах Беркли [RFC 3542]. Приложение управляет фрагментацией и PMTUD с помощью опций сокета из Табл. 9.1 на уровне IPPROTO_IPV6 [§11 RFC 3542]. Некоторые опции можно избирательно устанавливать для отдельных сообщений с помощью служебной структуры cmsghdr.

Таблица 9.1. Опции сокета, управляющие фрагментацией IPv6
Опция Смысл
IPV6_USE_MIN_MTU Использовать минимальный MTU (1280 байт)
IPV6_PATHMTU Запросить приближение PMTU для подключенного сокета
IPV6_RECVPATHMTU Разрешить возврат приближения PMTU из вызова recvfrom()

Обсудите преимущества и недостатки альтернативного подхода к определению PMTU, когда каждый транзитный узел по трассе пакета записывает фактическое значение MTU в специальную пошаговую опцию, если ее текущее значение больше MTU [draft-park-pmtu-ipv6-option-header] , так что прошедший всю трассу короткий пакет содержит в себе точное значение PMTU.

Еще один практический способ понизить долю фрагментированных пакетов — это не занижать MTU интерфейсов без необходимости [§5 RFC 2460]. Сегодня стандарт де-факто для подключения конечных пользователей на канальном уровне — это Ethernet, а он диктует значение MTU 1500 байт. Это же значение мы встречаем и в других канальных протоколах, например, в PPP [§2 RFC 1661]. В центре сети может понадобиться запас MTU сверх 1500 байт, чтобы пакеты от конечных пользователей можно было подвергать дополнительной инкапсуляции, например, туннелировать, не вызывая фрагментации. Конечно, в сложной сети с несколькими административными зонами выбрать для каждого канала оптимальное значение MTU может быть непросто. Тем не менее, опускать его ниже 1500 байт точно не стоит.

Еще мы до сих пор не задали минимальный размер буфера сборки IPv6. Как мы помним, в IPv4 он составлял 576 байт. Теперь мы видим значение, которое лучше подходит современным условиям: 1500 байт. Иными словами, всякий узел IPv6 обязан собрать адресованный ему пакет, если длина пакета после сборки не превышает 1500 байт [§5 RFC 2460]. Какой вывод должны сделать вышестоящие протоколы? Не следует создавать пакеты длиннее 1500 байт, если нет уверенности, что адресат готов принимать их. Например, в TCP подобные сведения можно извлечь из опции MSS.

В качестве упражнения вычислите наиболее вероятные длины полноразмерных сегментов TCP, которые можно будет увидеть в сети после перехода на IPv6. Не забудьте, что фактическая длина полноразмерного сегмента TCP может оказаться меньше значения опции MSS [RFC 6691]. (Подсказка: учтите возможность расширений из [RFC 1323].)

Сергей Субботин
Сергей Субботин

"Теоретически канал с адресацией EUI 64 может соединить порядка 2^63 "

запись вида 2^63  не понятна и отнимает время на попытку ее осмыслить.

ее можно заменить например на записи вида  264  или 1,8 * 1019

 

Павел Афиногенов
Павел Афиногенов

Курс IPv6, в тексте имеются ссылки на параграфы. Разбиения курса на параграфы нет.

Сергей Смоляр
Сергей Смоляр
Россия, Ялта