Как надежно обнаружить пропущенные запросы или ответы по netlink - PullRequest
0 голосов
/ 10 апреля 2020

Мне интересно использовать netlink для простого приложения (чтение статистики cgroup на высокой частоте).

Страница man предупреждает, что протокол ненадежен, намекая на то, что приложение необходимо быть готовым к обработке пропущенных пакетов:

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

Поскольку мои требования просты, я могу просто уничтожить сокет и создание нового всякий раз, когда происходит что-то неожиданное. Но я не могу найти никакой документации о том, что ожидают от моей программы - на странице man для recvmsg(2) даже не упоминается ENOBUFS, например.

Что все делают Мне нужно беспокоиться, чтобы убедиться, что я могу сказать, что запрос от моего приложения или ответ от ядра был отброшен, чтобы я мог сбросить все настройки и начать все сначала? Для меня ясно, что я мог бы делать это всякий раз, когда получаю ошибку от любого из задействованных системных вызовов, но, например, что произойдет, если мой запрос будет отброшен по пути к ядру? Я просто никогда не получу ответ? Нужно ли создавать механизм тайм-аута, в котором я так долго жду ответа?

1 Ответ

0 голосов
/ 12 апреля 2020

Я нашел следующее в Связь между ядром и пользовательским пространством в Linux с использованием сокетов Netlink от Ayuso, Gasca и Lefevre:

Если Netlink не может доставить сообщение, которое передается из ядра в пользовательское пространство, функция recvmsg() возвращает ошибку Нет доступного буфера (ENOBUFS). Таким образом, процесс пользовательского пространства знает, что он теряет сообщения [...]

С другой стороны, переполнение буфера не может происходить при обмене данными между пользователем и пространством ядра, поскольку sendmsg() синхронно передает сообщение Netlink в подсистему ядра. Если используются блокирующие сокеты, Netlink полностью надежен в обмене данными между пользователем и пространством ядра, поскольку выделение памяти будет ждать, поэтому исчерпание памяти невозможно.

Что касается подтверждений, похоже, что беспокоиться о них необязательно:

NLM_F_ACK: приложение пользовательского пространства запросило сообщение о подтверждении из пространства ядра, чтобы убедиться, что данный запрос был успешно выполнен. Если этот флаг не установлен, пространство ядра сообщает об ошибке синхронно через sendmsg() как errno значение.

Так что это похоже на мой простой пример использования c, который я могу просто использовать sendmsg и recvmsg наивно реагируют на любую ошибку (кроме EINTR), начиная все сначала, возможно, с отката. Я предполагаю, что, поскольку я получаю только один ответ на запрос, а ответы крошечные, я никогда не должен видеть ENOBUFS, если у меня только один запрос в полете за раз.

...