Scroll to navigation

NETLINK(7) Руководство программиста Linux NETLINK(7)

ИМЯ

netlink - обмен информацией между ядром и пользовательским пространством (AF_NETLINK)

ОБЗОР

#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
netlink_socket = socket(AF_NETLINK, socket_type, netlink_family);

ОПИСАНИЕ

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

Netlink обеспечивает для приложений сервис передачи датаграмм. В качестве socket_type могут использоваться типы сокетов как SOCK_RAW, так и SOCK_DGRAM. Несмотря на это, протокол netlink не различает датаграмные и неструктурированные (raw) сокеты.

По значению netlink_family выбирается модуль ядра или группа netlink для связи. В данный момент определены следующие семейства netlink:

Получает обновления маршрутов и состояние подключений (link); может использоваться для изменения таблицы маршрутизации (IPv4 и IPv6), IP-адресов, параметров подключения, настроек взаимодействия с ответной стороной (neighbor), параметров работы очереди, классов трафика и классификаторов пакетов (см. rtnetlink(7)).
Сообщения из однопроводной подсистемы.
Зарезервировано для будущих протоколов сокетов пространства пользователя.
Переправляет пакеты IPv4 из netfilter в пространство пользователя. Используется модулем ядра ip_queue.
Следит за сокетом INET.
Netfilter/iptables ULOG.
IPsec.
Уведомляет о событиях SELinux.
Open-iSCSI.
Ведёт контроль за системой.
Доступ к таблице FIB из пользовательского пространства.
Точка связи с ядром. Дополнительную информацию смотрите в файле исходного кода ядра Documentation/connector/*.
Подсистема netfilter.
Переправляет пакеты IPv6 из netfilter в пространство пользователя. Используется модулем ядра ip6_queue.
Сообщения маршрутизации DECnet.
Сообщения ядра в пользовательском пространстве.
Обобщённое семейство netlink для использования netlink.

Сообщения netlink состоят из потока байтов с одним или несколькими заголовками nlmsghdr и присоединённой полезной нагрузкой. Доступ к потоку байтов нужно осуществлять только с помощью стандартных макросов NLMSG_*. Подробности смотрите в netlink(3).

В первом и всех последующих заголовках сообщений, состоящих из нескольких частей (несколько заголовков nlmsghdr с полезной нагрузкой в одном потоке байт), установлен флаг NLM_F_MULTI. Последний заголовок имеет тип NLMSG_DONE и этот флаг не устанавливается.

После каждого nlmsghdr следует полезная нагрузка:


struct nlmsghdr {

__u32 nlmsg_len; /* длина сообщения, включая заголовок */
__u16 nlmsg_type; /* тип содержимого сообщения */
__u16 nlmsg_flags; /* дополнительные флаги */
__u32 nlmsg_seq; /* номер в последовательности */
__u32 nlmsg_pid; /* PID процесса, открывшего сокет */ };

Значение nlmsg_type может быть одним из стандартных типов сообщения: сообщения NLMSG_NOOP должны игнорироваться, сообщение NLMSG_ERROR сообщает об ошибке и в нагрузке содержится структура nlmsgerr, сообщение NLMSG_DONE заканчивает сообщение, состоящее из нескольких частей.


struct nlmsgerr {

int error; /* отрицательный errno или
0 для подтверждений */
struct nlmsghdr msg; /* заголовок сообщения, вызвавшего
ошибку */ };

Семейство netlink обычно определяет и другие типы сообщений (см. соответствующие справочные страницы, например, rtnetlink(7) о NETLINK_ROUTE).

Стандартные биты флагов в nlmsg_flags
NLM_F_REQUEST Должен быть установлен у всех сообщений с запросами.
NLM_F_MULTI Сообщение является одной из частей длинного сообщения, которое заканчивается NLMSG_DONE.
NLM_F_ACK Запрашивать подтверждение при успешном выполнении.
NLM_F_ECHO Послать эхо этого запроса.

Дополнительные биты флагов для запросов GET
NLM_F_ROOT Вернуть полную таблицу вместо одной записи.
NLM_F_MATCH Вернуть все записи, подходящие под критерий, переданный в содержимом сообщения. Пока не реализовано.
NLM_F_ATOMIC Вернуть атомарный образ (snapshot) таблицы.
NLM_F_DUMP Макрос для удобства; эквивалентен (NLM_F_ROOT|NLM_F_MATCH).

Заметим, что NLM_F_ATOMIC требует мандата CAP_NET_ADMIN или эффективного UID 0.

Дополнительные биты флагов для запросов NEW
NLM_F_REPLACE Переписать существующий подходящий объект.
NLM_F_EXCL Не перезаписывать, если объект уже существует.
NLM_F_CREATE Создать объект, если он ещё не существует.
NLM_F_APPEND Добавить в конец списка объектов.

Поля nlmsg_seq и nlmsg_pid используются для отслеживания передачи сообщений. В nlmsg_pid указывается источник сообщения. Заметим, что нет связи 1:1 между nlmsg_pid и PID процесса, если сообщение возникло из сокета netlink. Дополнительную информацию ищите в разделе ФОРМАТЫ АДРЕСА.

Тип поля nlmsg_seq и nlmsg_pid скрыт в ядре netlink.

Netlink не является надежным протоколом. Он делает всё возможное для доставки сообщения по адресу (адресам), но может отбрасывать пакеты при нехватке памяти или возникновении других ошибок в работе. Для повышения надёжности передачи отправитель может запросить подтверждение от получателя, установив флаг NLM_F_ACK. Подтверждающим является пакет NLMSG_ERROR с полем ошибки, равным нулю. Приложение должно само создавать подтверждения полученным сообщениям. Ядро пытается послать сообщение NLMSG_ERROR всем ошибочным пакетам. Процесс пользователя также должен следовать этому соглашению.

Однако, надёжная передача от ядра пользователю в любом случае невозможна. Ядро не может послать сообщение netlink, если заполнен буфер сокета: сообщение будет отброшено и ядро и пользовательский процесс будут иметь разное понятие о состоянии ядра. В обязанность приложения входит обнаружение такой ситуации (посредством ошибки ENOBUFS, возвращаемой recvmsg(2)) и выполнение восстановления синхронизации.

ФОРМАТЫ АДРЕСА

Структура sockaddr_nl описывает клиент netlink в пространстве пользователя или в ядре. Она может быть как одноадресной (передача информации только на один адрес), так и посылаться многоадресной группе netlink (значение nl_groups не равно нулю).


struct sockaddr_nl {

sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* ноль */
pid_t nl_pid; /* ID процесса */
__u32 nl_groups; /* маска многоадресных групп */ };

nl_pid — одиночный адрес сокета netlink. Он всегда равен 0, если местом назначения является ядро. Для процесса пользовательского пространства значение nl_pid, обычно, равно PID процесса, которому принадлежит сокет назначения. Однако, значением nl_pid определяется сокет netlink, а не процесс. Если процессу принадлежит несколько сокетов netlink, то значение nl_pid может быть равно ID процесса только у одного сокета. Есть два способа назначить nl_pid сокету netlink. Если приложение задаёт nl_pid до вызова bind(2), то приложение само должно убедиться, что значение nl_pid уникально. Если приложение устанавливает его равным 0, то присвоение уникального значения выполняется ядром. Первому сокету netlink ядро назначает ID процесса, который его открыл, а всем последующим создаваемым процессом сокетам netlink, будет назначено уникальное значение nl_pid.

Значение nl_groups — это битовая маска, где каждый бит представляет номер группы netlink. Каждое семейство netlink имеет набор из 32-х многоадресных групп. Когда для сокета вызывается bind(2), то поле nl_groups структуры sockaddr_nl должно содержать битовую маску групп, которые оно хочет прослушивать. По умолчанию значение этого поля равно нулю, что означает, что многоадресные передачи не будут приниматься. Сокет может передавать многоадресные сообщения любой из многоадресных групп, присвоив nl_groups битовую маску групп, которым он желает передавать данные вызовом sendmsg(2) или при выполнении connect(2). Принимать или посылать сообщения многоадресной группы netlink могут только процессы с эффективным UID, равным 0, или имеющие мандат CAP_NET_ADMIN. Любые ответы на сообщение, полученное многоадресной группой, должны быть отправлены посылающему процессу с PID и многоадресной группе. Некоторые подсистемы ядра Linux могут разрешать отправку и/или приём сообщений другим пользователям. Начиная с Linux 3.0, в группах NETLINK_KOBJECT_UEVENT, NETLINK_GENERIC, NETLINK_ROUTE и NETLINK_SELINUX разрешено принимать сообщения от других пользователей. Отправлять сообщения другим пользователям запрещено.

ВЕРСИИ

Сокетный интерфейс для netlink появился в Linux 2.2.

Linux 2.0 поддерживал более примитивный интерфейс на основе устройств (который всё ещё доступен для совместимости). Этот устаревший интерфейс здесь не описывается.

NETLINK_SELINUX появился в Linux 2.6.4.

NETLINK_AUDIT появился в Linux 2.6.6.

NETLINK_KOBJECT_UEVENT появился в Linux 2.6.10.

NETLINK_W1 и NETLINK_FIB_LOOKUP появились в Linux 2.6.13.

NETLINK_INET_DIAG, NETLINK_CONNECTOR и NETLINK_NETFILTER появились в Linux 2.6.14.

NETLINK_GENERIC и NETLINK_ISCSI появились в Linux 2.6.15.

ЗАМЕЧАНИЯ

В большинстве случаев лучше использовать netlink с помощью функций библиотек libnetlink или libnl, а не через низкоуровневый интерфейс ядра.

ДЕФЕКТЫ

Эта справочной странице не содержится всей необходимой информации.

ПРИМЕР

В следующем примере создаётся сокет netlink семейства NETLINK_ROUTE, который будет прослушивать многоадресные группы RTMGRP_LINK (события о создании/удалении/включении/выключении сетевых интерфейсов) и RTMGRP_IPV4_IFADDR (события о добавлении/удалении адресов IPv4).


struct sockaddr_nl sa;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
bind(fd, (struct sockaddr *) &sa, sizeof(sa));

В следующем примере показано как отправить сообщение netlink ядру (pid 0). Заметим, что приложение должно управлять нумерацией сообщений, чтобы отслеживать подтверждения о доставке.


struct nlmsghdr *nh; /* отправляется nlmsghdr с полезной нагрузкой */
struct sockaddr_nl sa;
struct iovec iov = { (void *) nh, nh->nlmsg_len };
struct msghdr msg;
msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
nh->nlmsg_pid = 0;
nh->nlmsg_seq = ++sequence_number;
/* для запроса подтверждения от ядра, устанавливаем NLM_F_ACK */
nh->nlmsg_flags |= NLM_F_ACK;
sendmsg(fd, &msg, 0);

И последний пример о том, как выполнять чтение сообщения netlink.


int len;
char buf[4096];
struct iovec iov = { buf, sizeof(buf) };
struct sockaddr_nl sa;
struct msghdr msg;
struct nlmsghdr *nh;
msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
len = recvmsg(fd, &msg, 0);
for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);

nh = NLMSG_NEXT (nh, len)) {
/* конец сообщения из нескольких частей */
if (nh->nlmsg_type == NLMSG_DONE)
return;
if (nh->nlmsg_type == NLMSG_ERROR)
/* выполняем обработку ошибок */
...
/* разбираем полезную нагрузку */
... }

СМОТРИТЕ ТАКЖЕ

cmsg(3), netlink(3), capabilities(7), rtnetlink(7)

Информацию о libnetlink можно найти в файлах ftp://ftp.inr.ac.ru/ip-routing/iproute2*.

Информацию о libnl можно найти в каталоге http://people.suug.ch/~tgr/libnl/.

RFC 3549 «Linux Netlink as an IP Services Protocol»

2012-04-14 Linux