База данных пересылки системных пакетов
#include <sys/socket.h>#include <net/if.h>#include <net/route.h>int socket( PF_ROUTE, SOCK_RAW, int family );
TCP/IP в ЗОСРВ «Нейтрино» предоставляет средства маршрутизации пакетов.
Менеджер сокетов хранит базу данных информации о маршрутизации, которая используется для выбора подходящего сетевого интерфейса при передаче пакетов.
Пользовательский процесс (или, возможно, несколько взаимодействующих процессов) поддерживает эту базу данных, отправляя сообщения через специальный вид сокета. Это заменяет фиксированные ioctl(), которые использовались в более ранних версиях. Изменения в таблицу маршрутизации может вносить только суперпользователь.
Этот интерфейс может самопроизвольно отправлять сообщения маршрутизации в ответ на внешние события, такие как получение перенаправления или неспособность найти подходящий маршрут для запроса. Типы сообщений более подробно описаны ниже.
Записи в базе данных маршрутизации
Записи базы данных маршрутизации бывают двух видов: для конкретного хоста или для всех хостов в общей подсети (как указано битовой маской и значением под маской). Эффект аналогичный подстановке специального символа или маршрутизации по умолчанию может быть достигнут путем использования маски из всех нулей. Допускаются иерархические маршруты.
Когда система загружается и адреса назначаются сетевым интерфейсам, каждое семейство протоколов устанавливает запись в таблице маршрутизации для каждого интерфейса, когда он готов к передаче трафика. Обычно протокол определяет маршрут через каждый интерфейс как «прямое» соединение с целевым хостом или сетью. Если маршрут прямой, транспортный уровень семейства протоколов обычно запрашивает отправку пакета на тот же хост, который указан в пакете. В противном случае интерфейс запрашивает адресацию пакета на шлюз, указанный в записи маршрутизации (т.е. пакет пересылается).
Маршрутизация пакетов
При маршрутизации пакета ядро пытается найти наиболее конкретный маршрут, соответствующий месту назначения. (Если есть две разные пары маски и значения под маской, которые совпадают, более конкретным является тот, у которого больше битов в маске. Маршрут к хосту считается снабженным маской, состоящей из такого же количества единиц, что и количество бит в пункте назначения). Если запись не найдена, пункт назначения объявляется недоступным, и создается сообщение о пропущенной маршрутизации, если в сокете управления маршрутизацией, описанном ниже, присутствуют какие-либо прослушиватели.
Запись маршрутизации с использованием специальных символов указывается с нулевым значением адреса назначения и маской из всех нулей. Маршруты с использованием специальных символов используются, когда системе не удается найти другие маршруты, соответствующие пункту назначения. Комбинация маршрутов с использованием специальных символов и перенаправлений маршрутизации может обеспечить экономичный механизм маршрутизации трафика.
Маршрутизация управляющих сообщений
Чтобы открыть канал для передачи сообщений управления маршрутизацией, используйте вызов сокета, описанный выше.
Параметром семейства может быть AF_UNSPEC
, который предоставляет информацию о маршрутизации для всех семейств адресов, или он может быть ограничен конкретным семейством адресов. В каждой системе может быть открыто несколько сокетов маршрутизации.
Сообщения формируются заголовком, за которым следует некоторое количество sockaddr (переменной длины), интерпретируемых по положению и ограниченных записью новой длины в sockaddr. Примером сообщения с четырьмя адресами может быть перенаправление: «Назначение», «Сетевая маска», «Шлюз» и «Автор перенаправления». Интерпретация того, какие адреса присутствуют, дается битовой маской в заголовке последовательностью от младшего до самого старшего бита.
Все сообщения, отправленные менеджеру сокетов, возвращаются, а копии отправляются всем заинтересованным слушателям. Интерфейс предоставляет идентификатор процесса для отправителя. Чтобы различать незавершенные сообщения, отправитель может использовать дополнительное поле последовательности. Однако ответы на сообщения могут быть потеряны, когда буферы менеджера сокетов исчерпаны.
Интерфейс может отклонять определенные сообщения, в зависимости от значения в поле rtm_errno.
Ошибка | Значение |
---|---|
EEXIST | Произведен запрос на дублирование существующей записи. |
ESRCH | Произведен запрос на удаление несуществующей записи. |
ENOBUFS | Недостаточно ресурсов для установки нового маршрута. |
В текущей реализации все процессы маршрутизации выполняются локально, и значения rtm_errno доступны через обычный механизм errno, даже если сообщение ответа маршрутизации потеряно.
Процесс может избежать затрат на чтение ответов на свои собственные сообщения, вызвав setsockopt(), чтобы отключить опцию SO_USELOOPBACK
на уровне SOL_SOCKET
. Процесс может игнорировать все сообщения из маршрутизирующего сокета, выполнив системный вызов shutdown() для дальнейшего ввода.
Если маршрут используется в момент удаления, запись маршрутизации помечается и удаляется из таблицы маршрутизации, но связанные с ней ресурсы не будут освобождены, пока не будут уничтожены все ссылки на нее. Пользовательские процессы могут получить информацию о записи маршрутизации в конкретный пункт назначения, используя сообщение RTM_GET
или вызвав sysctl().
Сообщения:
#define RTM_ADD 0x1 /* Добавить маршрут */#define RTM_DELETE 0x2 /* Удалить маршрут */#define RTM_CHANGE 0x3 /* Изменить показатели, флаги или шлюз */#define RTM_GET 0x4 /* Информация об отчете */#define RTM_LOSING 0x5 /* Ядро ожидает сегментирование */#define RTM_REDIRECT 0x6 /* Указано использовать другой маршрут */#define RTM_MISS 0x7 /* Ошибка поиска по заданному адресу */#define RTM_RESOLVE 0xb /* Запрос на разрешение dst в адрес LL */#define RTM_NEWADDR 0xc /* Адрес добавляется в iface */#define RTM_DELADDR 0xd /* Адрес удаляется из iface */#define RTM_IFINFO 0xe /* iface смещается вверх/вниз и т.п. */
Заголовок сообщения состоит из одного из следующих элементов:
struct rt_msghdr {u_short rtm_msglen; /* Пропустить нераспознанные сообщения */u_char rtm_version; /* Будущая двоичная совместимость */u_char rtm_type; /* Тип сообщения */u_short rtm_index; /* Индекс для связанного ifp */int rtm_flags; /* Флаги, например, DONE */int rtm_addrs; /* Битовая маска, идентифицирующая sockaddr (структуру адреса сокета) в msg */pid_t rtm_pid; /* Идентификация отправителя */int rtm_seq; /* Для идентификации действия отправителем */int rtm_errno; /* Причина ошибки */int rtm_use; /* Из rtentry */u_long rtm_inits; /* Какая метрика инициализируется */struct rt_metrics rtm_rmx; /* Непосредственно метрика */};struct if_msghdr {u_short ifm_msglen; /* Пропустить нераспознанные сообщения */u_char ifm_version; /* Будущая двоичная совместимость */u_char ifm_type; /* Тип сообщения */int ifm_addrs; /* Аналогично rtm_addrs */int ifm_flags; /* Значение if_flags */u_short ifm_index; /* Индекс для связанного ifp */struct if_data ifm_dat /* Статистика и иные данные об if */};struct ifa_msghdr {u_short ifam_msglen; /* Пропустить нераспознанные сообщения */u_char ifam_version; /* Будущая двоичная совместимость */u_char ifam_type; /* Тип сообщения */int ifam_addrs; /* Аналогично rtm_addrs */int ifam_flags; /* Значение ifa_flags */u_short ifam_index; /* Индекс для связанного ifp */int ifam_metric; /* Значение ifa_metric */};
Сообщение RTM_IFINFO
использует заголовок if_msghdr
. Сообщения RTM_NEWADDR
и RTM_DELADDR
используют заголовок ifa_msghdr
. Иные сообщения используют заголовок rt_msghdr
.
Структура показателей следующая:
struct rt_metrics {u_long rmx_locks; /* Ядро должно оставить эти значения неизменными */u_long rmx_mtu; /* MTU для текущего пути */u_long rmx_hopcount; /* Макимальное ожидаемое число промежуточных точек маршрута */u_long rmx_expire; /* Время жизни маршрута, например, для перенаправления */u_long rmx_recvpipe; /* Произведение входящей задержки на пропускную способность */u_long rmx_sendpipe; /* Произведение исходящей задержки на пропускную способность */u_long rmx_ssthresh; /* Предел буфера исходящего шлюза */u_long rmx_rtt; /* Расчетное время движения в обе стороны */u_long rmx_rttvar; /* Ожидаемое отклонение rtt */u_long rmx_pksent; /* Пакеты, отправленные по этому маршруту */};
Флаги включают значения:
#define RTF_UP 0x1 /* Маршрут доступен для использования */#define RTF_GATEWAY 0x2 /* Пункт назначения - шлюз */#define RTF_HOST 0x4 /* Запись хоста (или сеть) */#define RTF_REJECT 0x8 /* Хост или сеть недоступны */#define RTF_DYNAMIC 0x10 /* Заполняется динамически (при перенаправлении) */#define RTF_MODIFIED 0x20 /* Изменяется динамически (при перенаправлении) */#define RTF_DONE 0x40 /* Сообщение подтверждено */#define RTF_MASK 0x80 /* Наличие маски подсети */#define RTF_CLONING 0x100 /* Генерировать новые маршруты при использовании */#define RTF_XRESOLVE 0x200 /* Внешний процесс-демон используется для разрешения имени */#define RTF_LLINFO 0x400 /* Генерируется ARP или ESIS */#define RTF_STATIC 0x800 /* Указывается вручную */#define RTF_BLACKHOLE 0x1000 /* Игнорировать pkts (во время обновлений) */#define RTF_PROTO2 0x4000 /* Протоколозависимый флаг маршрутизации */#define RTF_PROTO1 0x8000 /* Протоколозависимый флаг маршрутизации */
Спецификаторы для показателей в rmx_locks и rtm_inits:
#define RTV_MTU 0x1 /* Инициализировать или заблокировать _mtu */#define RTV_HOPCOUNT 0x2 /* Инициализировать или заблокировать _hopcount */#define RTV_EXPIRE 0x4 /* Инициализировать или заблокировать _expire */#define RTV_RPIPE 0x8 /* Инициализировать или заблокировать _recvpipe */#define RTV_SPIPE 0x10 /* Инициализировать или заблокировать _sendpipe */#define RTV_SSTHRESH 0x20 /* Инициализировать или заблокировать _ssthresh */#define RTV_RTT 0x40 /* Инициализировать или заблокировать _rtt */#define RTV_RTTVAR 0x80 /* Инициализировать или заблокировать _rttvar */
Спецификаторы, адреса которых присутствуют в сообщениях:
#define RTA_DST 0x1 /* sockaddr назначения указан */#define RTA_GATEWAY 0x2 /* sockaddr шлюза указан */#define RTA_NETMASK 0x4 /* sockaddr маски сети указан */#define RTA_GENMASK 0x8 /* sockaddr маски клонирования указан */#define RTA_IFP 0x10 /* sockaddr имени интерфейса указан */#define RTA_IFA 0x20 /* sockaddr адресов интерфейса указан */#define RTA_AUTHOR 0x40 /* sockaddr для автора перенаправления */#define RTA_BRD 0x80 /* для NEWADDR, транслировать или p-p адрес назначения */
Следующий код устанавливает маршрут по умолчанию:
#include <sys/socket.h>#include <sys/uio.h>#include <unistd.h>#include <net/route.h>#include <netinet/in.h>#include <stdio.h>#include <libgen.h>#include <arpa/inet.h>#include <process.h>#include <errno.h>struct my_rt{struct rt_msghdr rt;struct sockaddr_in dst;struct sockaddr_in gate;struct sockaddr_in mask;};int main( int argc, char **argv ){int s;struct rt_msghdr *rtm;struct sockaddr_in *dst, *gate, *mask;struct my_rt my_rt;if ( argc < 2 ){fprintf( stderr, "Usage: %s: <ip_addr_of_default_gateway>\n",basename( argv[0] ) );return (1);}if ( (s = socket( AF_ROUTE, SOCK_RAW, 0 )) == -1 ){perror( "socket" );return (1);}memset( &my_rt, 0x00, sizeof( my_rt ) );rtm = &my_rt.rt;dst = &my_rt.dst;gate = &my_rt.gate;mask = &my_rt.mask;rtm->rtm_type = RTM_ADD;rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;rtm->rtm_msglen = sizeof( my_rt );rtm->rtm_version = RTM_VERSION;rtm->rtm_seq = 1234;rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;rtm->rtm_pid = getpid();dst->sin_len = sizeof( *dst );dst->sin_family = AF_INET;mask->sin_len = sizeof( *mask );mask->sin_family = AF_INET;gate->sin_len = sizeof( *gate );gate->sin_family = AF_INET;inet_aton( argv[1], &gate->sin_addr );AGAIN:if ( write( s, rtm, rtm->rtm_msglen ) < 0 ){if ( errno == EEXIST && rtm->rtm_type == RTM_ADD ){rtm->rtm_type = RTM_CHANGE;goto AGAIN;}perror( "write" );return (1);}return (0);}
setsockopt(), socket(), sysctl()
Предыдущий раздел: Описание API сетевой библиотеки