Я пытаюсь написать модуль связи на C, который может обрабатывать подключенные или неподключенные сокеты полностью прозрачно.
будучи ленивым, я подумал, что смогу получить bind()
/ connect()
сокетов udp, чтобы получить одинсокет на клиента "с использованием udp и примитивов send()
/ recv()
.
схема проста, у меня есть" сокет сервера ", связанный с *: PORT с SO_REUSEPORT
, на котором я recvfrom()
,оттуда я создаю новый сокет с опцией сокета SO_REUSEPORT
и использую информацию параметра from из bind()
в *: PORT и подключаюсь к моему новому клиенту.
Я поддерживаюэтот список клиентов (он же сокеты) и может отправить () к ним без проблем.recv (), это другое дело ... Я мог бы предположить, что "разветвление" udp будет учитывать подключенный конечный бит сокета, чтобы найти, в какой сокет распространять пакет.в большинстве случаев это работает, и «правильный» сокет получает данные.но время от времени, неподключенный «серверный» сокет получает данные.
Я вижу в коде ядра:
(на момент публикации не удалось найти работающий lxr, извините за ссылки, не доступные для просмотра).
Я немного растерялся из-за этого reciprocal_scale()
когда нет программы BPF ...
первый вопрос: я в заблуждение, когда говорю, что reuseport_select_sock()
выбирает сокет на основе хэша 4-х кортежей (локальный адрес / порт + внешний адрес / порт)передается в качестве параметра, но полностью игнорирует 4 хеша подключенных сокетов?кажется, что идея последовательно выбирать сокет на основе его 4-х кортежей, не обязательно совпадающих с подключенной конечной точкой?
второй вопрос: я пытаюсь обернуться вокруг написания программы eBPF, чтобы «исправить»такое поведение (потому что это сделало бы мой код пользователя намного проще).Кажется, есть две вспомогательные функции, которые могут приблизить меня к тому, чего я хочу достичь.
int bpf_sk_select_reuseport()
struct bpf_sock *bpf_sk_lookup_udp()
bpf_sk_lookup_udp()
отлично работает для того, что я хочу сделать, он находит подходящий сокет на основе 4-х кортежей в списке носителей для повторного порта.Проблема в том, что bpf_sk_select_reuseport()
хочет, чтобы индекс в массиве reuse->socks[]
обновлял поле selected_sk
... проблема здесь в том, что поиск вернет мне указатель на bpf_sock ... которого у меня нетИдея, как извлечь индекс массива в массиве reuse->socks[]
.
Извините, если он был слишком длинным.даже если я не могу заставить вещи работать так, как я хочу, надеюсь, это может быть информативным для других.
edit Итак, после нескольких дней игры с eBPF я пришел косознание того, что во многом то, что я хотел сделать, - это очень много.
для объявления BPF_MAP_TYPE_REUSEPORT_ARRAY требуется CAP_SYS_ADMIN, что как бы убивает идею ...
даже с CAP_SYS_ADMIN, этоневозможно искать элементы в REUSEPORT_ARRAY ...
, и даже с возможностью поиска элементов, eBPF не разрешает циклы, так как переходы с отрицательными смещениями запрещены.(комментарии в верификаторе явно говорят, что код должен быть группой обеспечения доступности баз данных)
решение с использованием eBPF состояло бы в том, чтобы использовать хеш-таблицу, связывая 5-тиклет пакета, с индексом которого он хранится в REUSEPORT_ARRAY.
, но так как у нас нет способа итерировать REUSEPORT_ARRAY, нам придется полагаться на «угадывание» этого индекса путем повторной реализации алгоритма, используемого в ядре. Сокеты
хранятся в порядкесоздания в REUSEPORT_ARRAY, пронумерованные от 0 до N-1.
когда сокет A закрыт, сокет N (последний сокет в массиве) занимает свое место в массиве, а массив сокращается на один элемент.
программе eBPF придется только искать хеш-таблицу и возвращать связанный индекс ... но это кажется слишком хрупким, поскольку это зависит от того, что ядро всегда будет придерживаться одного и того же алгоритма упорядочения ... что маловероятно.1072 *