IPv6-адрес отправителя обычно определяется при помощи функции
bind
. Но если адрес отправителя поставляется вместе с данными, это может снизить непроизводительные затраты. Этот параметр также позволяет серверу гарантировать, что адрес отправителя ответа совпадает с адресом получателя клиентского запроса — некоторым клиентам требуется такое условие, которое сложно выполнить в случае IPv4 (см. упражнение 22.4).
Когда IPv6-адрес отправителя задан в качестве вспомогательных данных и элемент
ipi6_addr
структуры
in6_pktinfo
имеет значение
IN6ADDR_ANY_INIT
, возможны следующие сценарии: если адрес в настоящий момент связан с сокетом, он используется в качестве адреса отправителя; если в настоящий
момент никакой адрес не связан с сокетом, ядро выбирает адрес отправителя. Если же элемент
ipi6_addr
не является неопределенным адресом, но сокет уже связался с адресом отправителя, то значением элемента
ipi6_addr
перекрывается уже связанный адрес, но только для данной операции вывода. Затем ядро проверяет, действительно ли запрашиваемый адрес отправителя является адресом направленной передачи, присвоенным узлу.
Когда структура in6_
pktinfo
возвращается в качестве вспомогательных данных функцией
recvmsg
, элемент
ipi6_addr
содержит IPv6-адрес получателя из полученного пакета. По сути, это аналог параметра сокета
IP_RECVDSTADDR
для IPv4.
Задание и получение предельного количества транзитных узлов
Предельное количество транзитных узлов обычно задается параметром сокета
IPV6_UNICAST_HOPS
для дейтаграмм направленной передачи (см. раздел 7.8) или параметром сокета
IPV6_MULTICAST_HOPS
для дейтаграмм многоадресной передачи (см. раздел 21.6). Задавая предельное количество транзитных узлов в составе вспомогательных данных, мы можем заменить как значение этого предела, задаваемое ядром по умолчанию, так и ранее заданное значение — и для направленной, и для многоадресной передачи, но только для одной операции вывода. Предел количества транзитных узлов полученного пакета используется в таких программах, как
traceroute
, и в некоторых приложениях IPv6, которым нужно проверять, что полученное значение равно 255 (то есть что пакет не пересылался маршрутизаторами).
Полученное предельное количество транзитных узлов возвращается в виде вспомогательных данных функцией
recvmsg
, только если приложение включает параметр сокета
IPV6_RECVHOPLIMIT
. В структуре
cmsghdr
, содержащей эти вспомогательные данные, элемент
cmsg_level
будет иметь значение
IPPROTO_IPV6
, элемент
cmsg_type
— значение
IPV6_HOPLIMIT
, а первый байт данных будет первым байтом целочисленного предела повторных передач. Мы показали это на рис. 22.5. Нужно понимать, что значение, возвращаемое в качестве вспомогательных данных, — это действительное значение из полученной дейтаграммы, в то время как значение, возвращаемое функцией
getsockopt
с параметром
IPV6_UNICAST_HOPS
, является значением по умолчанию, которое ядро будет использовать для исходящих дейтаграмм на сокете.
Чтобы задать предельное количество транзитных узлов для исходящих пакетов, никаких специальных действий не требуется — нам нужно только указать управляющую информацию в виде вспомогательных данных для функции
sendmsg
. Обычные значения для предельного количества транзитных узлов лежат в диапазоне от 0 до 255 включительно, но если целочисленное значение равно -1, это указывает ядру, что следует использовать значение по умолчанию.
ПРИМЕЧАНИЕ
Предельное количество транзитных узлов не содержится в структуре in6_pktinfo — некоторые серверы UDP хотят отвечать на запросы клиентов, посылая ответы на том же интерфейсе, на котором был получен запрос, с совпадением IPv6-адреса отправителя ответа и IPv6-адреса получателя запроса. Для этого приложение может включить параметр сокета IPV6_RECVPKTINFO, а затем использовать полученную управляющую информацию из функции recvmsg в качестве управляющей информации для функции sendmsg при отправке ответа. Приложению вообще никак не нужно проверять или изменять структуру in6_pktinfo. Но если в этой структуре содержался бы предел количества транзитных узлов, приложение должно было бы проанализировать полученную управляющую информацию и изменить значение этого предела, поскольку полученный предел не является желательным значением для исходящего пакета.
Задание
адреса следующего транзитного узла
Объект вспомогательных данных
IPV6_NEXTHOP
задает адрес следующего транзитного узла дейтаграммы в виде структуры адреса сокета. В структуре
cmsghdr
, содержащей эти вспомогательные данные, элемент
cmsg_level
будет иметь значение
IPPROTO_IPV6
, элемент
cmsg_type
— значение
IPV6_NEXTHOP
, а первый байт данных будет первым байтом структуры адреса сокета.
На рис. 22.5 мы показали пример такого объекта вспомогательных данных, считая, что структура адреса сокета — это 24-байтовая структура
sockaddr_in6
. В этом случае узел, идентифицируемый данным адресом, должен быть соседним для отправляющего узла. Если этот адрес совпадает с адресом получателя IPv6-дейтаграммы, мы получаем эквивалент параметра сокета
SO_DONTROUTE
. Установка этого параметра требует прав привилегированного пользователя. Адрес следующего транзитного узла можно устанавливать для всех пакетов на сокете, если включить параметр сокета
IPV6_NEXTHOP
со значением
sockaddr_in6
(раздел 27.7). Для этого необходимо обладать правами привилегированного пользователя.
Задание и получение класса трафика
Объект вспомогательных данных
IPV6_TCLASS
задает класс трафика для дейтаграммы. Элемент
cmsg_level
структуры
cmsghdr
, содержащей эти данные, будет равен
IPPROTO_IPV6
, элемент
cmsg_type
будет равен
IPV6_TCLASS
, а первый байт данных будет первым байтом целочисленного (4-байтового) значения класса трафика (см. рис. 22.5). Согласно разделу А.3, класс трафика состоит из полей
DSCP
и
ECN
. Эти поля должны устанавливаться одновременно. Ядро может маскировать или игнорировать указанное пользователем значение, если ему это нужно (например, если ядро реализует
ECN
, оно может установить биты
ECN
равными какому-либо значению, игнорируя два бита, указанных с параметром
IPV6_TCLASS
). Класс трафика обычно лежит в диапазоне 0–255. Значение -1 говорит ядру о необходимости использовать значение по умолчанию.
Чтобы задать класс трафика для пакета, нужно отправить вспомогательные данные вместе с этим пакетом. Чтобы задать класс трафика для всех пакетов, отправляемых через сокет, необходимо использовать параметр сокета
IPV6_TCLASS
(раздел 27.7). Класс трафика для принятого пакета возвращается функцией
recvmsg
во вспомогательных данных, только если приложение включило параметр сокета
IPV6_RECVTCLASS
.
22.9. Управление транспортной MTU IPv6
IPv6 предоставляет приложениям средства для управления механизмом обнаружения транспортной MTU (раздел 2.11). Значения по умолчанию пригодны для подавляющего большинства приложений, однако специальные программы могут настраивать процедуру обнаружения транспортной MTU так, как им нужно. Для этого имеется четыре параметра сокета.
Отправка с минимальной MTU
При работе в режиме детектирования транспортной MTU пакеты фрагментируются по MTU исходящего интерфейса или по транспортной MTU в зависимости от того, какое значение оказывается меньше. IPv6 требует минимального значения MTU 1280 байт. Это значение должно поддерживаться любой линией передачи. Фрагментация сообщений по этому минимальному значению позволяет не тратить ресурсы на обнаружение транспортной MTU (потерянные пакеты и задержки в процессе обнаружения), но зато не дает возможности отправлять большие пакеты (что более эффективно).
Минимальная MTU может использоваться приложениями двух типов. Во- первых, это приложения многоадресной передачи, которым нужно избегать порождения множества ICMP-сообщений «Message too big». Во-вторых, это приложения, выполняющие небольшие по объему транзакции с большим количеством адресатов (например, DNS). Обнаружение MTU для многоадресного сеанса может быть недостаточно выгодным, чтобы компенсировать затраты на получение и обработку миллионов ICMP-сообщений, а приложения типа DNS обычно связываются с серверами недостаточно часто, чтобы можно было рисковать утратой пакетов.