Фиксированный заголовок IPv6, система дополнительных заголовков (extension headers), Flow Label и механизм фрагментации на стороне отправителя.
Какова основная функция поля Flow Label в заголовке IPv6?
Чем Payload Length в IPv6 отличается от Total Length в IPv4?
Какой дополнительный заголовок (extension header) всегда должен идти первым?
Почему в IPv6 Fragment Header использует 32-битный Identification вместо 16-битного?
Что дублируется в каждом фрагменте IPv6-пакета?
Каков размер фиксированного заголовка IPv6?
Если вспомнить, как выглядел заголовок IPv4, то там было достаточно много полей. В частности, было поле опций, из-за которого IPv4-заголовок мог быть произвольного размера: минимальный размер 20 байт, максимальный — 60 байт. Поле опций могло занимать от 0 до 40 байт, из-за чего обработка таких заголовков на аппаратном уровне была затруднена.
Когда вы получали IPv4-пакет, нужно было понять, начиная с какого места идут полезные данные. То, что не относится к данным, выкладывалось в буфер, а для данных нужно было поставить указатель на начало — в общем, требовалась дополнительная обработка. Для этого существовало отдельное поле, указывающее размер заголовка IPv4.
В IPv6 решили избавиться от поля непредсказуемого размера. Вместо этого ввели фиксированный заголовок, в который входит только информация, необходимая для маршрутизации — минимальный необходимый набор. Если какое-то поле заведомо влияет на маршрутизацию и полезно всем узлам, оно присутствует в фиксированном заголовке.
Все дополнительные пожелания к обработке пакета вынесены в дополнительные заголовки (extension headers). Они могут присутствовать, а могут и отсутствовать.
В отличие от поля опций IPv4, где была одна большая область непредсказуемого размера, в IPv6 дополнительные заголовки имеют предсказуемый формат. Даже если вы не понимаете, как устроен конкретный заголовок, вы всегда можете его пропустить и перейти к следующему или к полезным данным.
Первые 4 бита заголовка — поле версии. В IPv4 там лежало двоичное 0100 (десятичное 4), в IPv6 — 0110 (десятичное 6).
Версии 0–3 были промежуточными экспериментальными вариантами стандарта, не пошедшими в серию. Версия 4 появилась в 1978 году. Версия 5 была зарезервирована для мультикаста, но потом от отдельного типа протокола IP для мультикаста отказались, объединив всё в IPv4.
Поле версии нужно для быстрой проверки: если первые биты 0110 — это действительно IPv6-пакет. Если биты другие — обработчик канального уровня передал пакет ошибочно.
Поскольку фиксированный заголовок IPv6 имеет постоянный размер, поле Header Length (которое было в IPv4) больше не нужно.
Это переименованное поле Type of Service из IPv4. В IPv4 его позже разбили на два поля:
В IPv6 это поле называется Traffic Class. Сам протокол IPv6 не специфицирует, что внутри должно лежать — можно использовать различные механизмы повышения качества обслуживания.
Важная особенность: поле Traffic Class может изменяться маршрутизаторами в процессе маршрутизации. Маршрутизатор имеет полное право изменить значение этого поля при передаче пакета дальше. За счёт этого возможны разные домены, в которых применяется разная логика использования Traffic Class.
Поле Flow Label (метка потока) дополняет версию (4 бита) и Traffic Class (8 бит) до границы в 32 бита. Это не то же самое, что метки в MPLS (хотя была идея использовать это поле для MPLS; в MPLS метки 24 бита).
Ключевые свойства Flow Label:
Допустим, узел отправляет пакеты из двух приложений — Telnet (flow label = 1) и SSH (flow label = 2). Маршрутизатор упаковывает всё в IPsec для передачи через интернет. После шифрования транспортные заголовки скрыты, все пакеты выглядят одинаково — зашифрованная каша. Но у пакетов Telnet остаётся flow label = 1, а у SSH — flow label = 2.
Это позволяет маршрутизаторам:
Reordering опасен тем, что:
Flow Label особенно полезна, когда содержимое пакета зашифровано и транспортный заголовок не виден.
Поле Payload Length указывает размер данных с учётом дополнительных заголовков, но без учёта фиксированного заголовка.
Это отличие от IPv4, где поле Total Length считало суммарную длину пакета вместе с заголовком. В IPv4 максимальный размер пакета 65 535 байт, из них данных можно было отправить максимум 65 515 байт (за вычетом минимального заголовка в 20 байт).
В IPv6 фиксированный заголовок не включается в Payload Length, поэтому можно указать до 65 535 байт полезных данных.
В IPv4 была контрольная сумма (checksum), закрывающая только заголовок. В IPv6 её убрали по следующим причинам:
Это бывшее поле TTL (Time To Live) из IPv4. Изначально TTL указывал, сколько секунд может жить IP-пакет. Маршрутизаторы должны были вычитать количество секунд, затраченных на маршрутизацию. Но в современных маршрутизаторах маршрутизация занимает микросекунды, поэтому меньше единицы из этого поля вычитать не получалось.
Фактически TTL превратилось в количество прыжков (hops) между маршрутизаторами. В IPv6 поле просто переименовали в Hop Limit, чтобы название соответствовало смыслу.
При маршрутизации из значения вычитается 1. Если значение становится 0 — пакет сбрасывается. Отправитель никогда не отправляет пакеты с Hop Limit = 0. Если маршрутизатор получил пакет с Hop Limit = 1, после маршрутизации получает 0 и сбрасывает пакет — даже если адрес назначения принадлежит его собственному интерфейсу (но достижим через маршрутизацию, а не локально).
Каждое поле адреса занимает 128 бит (4 строки по 32 бита в диаграмме заголовка). Как и в IPv4, поля выровнены по границе 4 байт для удобства обработки на 8-, 16- и 32-битных архитектурах.
Поле Next Header указывает тип следующего вложения после текущего заголовка. Это аналог поля Protocol в IPv4, но с расширенной функциональностью.
Если Next Header находится в фиксированном заголовке — он указывает на тип первого дополнительного заголовка (или данных). Если в первом дополнительном заголовке — указывает на тип второго, и так далее. Последний заголовок в цепочке указывает на тип полезных данных.
Каждый дополнительный заголовок содержит:
Минимальный размер дополнительного заголовка — 8 байт. Заголовки выровнены по границе 8 байт.
Пример расчёта длины:
Примечание: в Википедии написано иначе (число 4-байтовых блоков минус 2), но в RFC указано именно в 8-байтовых блоках минус 1.
Если маршрутизатор хочет блокировать определённые заголовки, он должен явно указать конкретные типы (по значению Next Header), а не блокировать все неизвестные заголовки оптом.
Значения совпадают с реестром IANA (IPv6 Extension Header Types) и частично с полем Protocol из IPv4:
| Значение | Тип | Описание |
|---|---|---|
| 0 | Hop-by-Hop Options | Опции для всех узлов, всегда первый |
| 6 | TCP | Протокол TCP |
| 17 | UDP | Протокол UDP |
| 43 | Routing Header | Заголовок маршрутизации |
| 44 | Fragment Header | Заголовок фрагментации |
| 50 | ESP | IPsec Encapsulating Security Payload |
| 51 | AH | IPsec Authentication Header |
| 60 | Destination Options | Опции для узла назначения |
Любой узел, поддерживающий IPv6, обязан поддерживать:
Содержимое обоих заголовков использует формат TLV (Type, Length, Value):
Даже если опция незнакома, можно перескочить на следующую, зная её длину.
Старшие 2 бита поля Type указывают, что делать, если опция не распознана:
| Биты | Действие |
|---|---|
| 00 | Пропустить опцию, продолжить обработку |
| 01 | Отбросить пакет |
| 10 | Отбросить пакет и отправить ICMP, если адрес назначения не multicast |
| 11 | Отбросить пакет и отправить ICMP в любом случае |
Третий бит по старшинству указывает, можно ли менять опцию при транзите:
Для выравнивания заголовка по границе 8 байт используются две служебные опции:
Поле Payload Length (16 бит) ограничено значением 65 535. Для отправки пакетов большего размера в IPv6 предусмотрена опция Jumbo Payload:
Забавный факт: идея Jumbo Payload перекликается с шуточным RFC о передаче IPv4-пакетов с помощью почтовых голубей. В эпоху IPv6 предлагалось вместо папиросной бумаги привязать к голубю флешку (microSD) — и вся флешка будет одним IP-пакетом.
В IPv6, в отличие от IPv4, фрагментацию может выполнять только узел-отправитель. Транзитные маршрутизаторы не фрагментируют пакеты — они всегда сбрасывают слишком большие пакеты и отправляют отправителю сообщение ICMPv6 Packet Too Big. Это эквивалентно постоянно установленному флагу Don't Fragment (DF) из IPv4.
Причины отказа от транзитной фрагментации:
| Поле | Размер | Описание |
|---|---|---|
| Next Header | 8 бит | Тип следующего заголовка |
| Reserved | 8 бит | Зарезервировано (Header Ext Len = 0, т.к. заголовок всегда 8 байт) |
| Fragment Offset | 13 бит | Смещение фрагмента в 8-байтовых блоках |
| Reserved | 2 бита | Зарезервировано (всегда 0) |
| More Fragments (M) | 1 бит | 1 = не последний фрагмент, 0 = последний |
| Identification | 32 бита | Уникальный идентификатор пакета |
Fragment Offset указывает смещение данных фрагмента в 8-байтовых блоках. Это означает, что все фрагменты, кроме последнего, должны содержать данные, кратные 8 байтам.
Максимальное значение смещения — 65 528 байт (+ 8 = 65 536).
В отличие от IPv4, в IPv6 не весь пакет подвергается фрагментации:
Fragment Offset отсчитывается от начала фрагментируемой части. Нефрагментируемая часть дублируется в каждом фрагменте, чтобы транзитные маршрутизаторы могли обработать Hop-by-Hop Options и Routing Header.
Ограничение: Jumbo Payload и фрагментация несовместимы. Если пакет размером 4 ГБ не пролезает в среду, фрагментация не поможет из-за ограничений Fragment Offset.
В IPv4 поле Identification было 16-битным (65 535 значений), что быстро исчерпывалось на скоростных каналах. Например, на 10-мегабитном канале при пакетах по 500 байт можно отправить ~20 000 пакетов в секунду, перебирая все значения за 3 секунды. На гигабитных каналах это занимало миллисекунды.
Результат: несколько пакетов с одинаковым Identification оказывались в сети одновременно. При фрагментации их куски перемешивались, и собрать оригинальные пакеты было невозможно — получался "Франкенштейн" из кусков разных пакетов.
В IPv6 поле Identification расширено до 32 бит (~4 миллиарда значений). Согласно RFC, идентификатор должен быть уникальным за "последнее разумное время" — как минимум, пока узел-получатель держит таймер сборки фрагментов.
Заголовок IPv6 спроектирован с учётом опыта эксплуатации IPv4: