Поскольку вы упоминаете «пространство пользователя», я не уверен, о чем именно вы говорите. Итак, давайте начнем с некоторого пояснения.
Карты BPF (или, по крайней мере, большинство существующих типов, включая карты и массивы ha sh) могут быть доступны двумя способами:
- Из пространства пользователя, из любого приложения, работающего в системе и имеющего достаточные права доступа
- Из пространства ядра, из программ BPF
Из пространства пользователя нет функции «помощника». Взаимодействие с картами полностью (*) осуществляется с помощью системного вызова bpf()
(команды BPF_MAP_LOOKUP_ELEM
, BPF_MAP_UPDATE_ELEM
, BPF_MAP_DELETE_ELEM
передаются системному вызову в качестве первого аргумента). См. Справочную страницу bpf(2)
для более подробной информации. Это то, что вы используете в приложении пользовательского пространства, которое загружает и управляет программами и картами BPF, например, bpftool
.
Из пространства ядра, т.е. из программы BPF, все работает по-другому, и доступ осуществляется с одним из «помощников» БНФ, таким как bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)
. См. Справочную страницу bpf-helpers(7)
для получения подробной информации о существующих помощниках. Вы можете найти подробную информацию об этих вспомогательных вызовах в руководстве Cilium или, очевидно, читая код ядра (например, для карт массивов ). Они выглядят как низкоуровневые вызовы функций C, при этом регистры BPF используются для передачи необходимых аргументов, а затем он вызывает из программных инструкций BPF помощник, который компилируется как часть двоичного файла ядра.
Итак, вы упомянули bpf_map_update_elem()
и пространство пользователя. Хотя это имя помощника на стороне ядра, я подозреваю, что вы можете говорить о функции с тем же именем, которое предлагается библиотекой libbpf, чтобы обеспечить оболочку для системного вызова bpf()
. То, что происходит с этой функцией, довольно просто.
- Нет необходимости искать карту из файлового дескриптора в пространстве пользователя: на самом деле происходит обратное, файловый дескриптор открыт из карты у пользователя пространство (например, из его идентификатора карты или из закрепленного пути в виртуальной файловой системе / sys / fs / bpf). Таким образом, fd передается системному вызову
bpf()
и используется ядром как ссылка на карту. - Я не уверен, что вы имеете в виду, но «пользовательское пространство создает память в пользовательском пространстве». Здесь нет необходимости выделять какую-либо память:
key
и value
уже должны быть заполнены на этом этапе, и они передаются ядру через системный вызов bpf()
, чтобы сообщить, какую запись обновить и с какой ценность. То же самое для флагов. - После вызова
bpf()
то, что происходит на стороне ядра, довольно просто. В основном ядро проверяет права доступа , проверяет аргументы (чтобы убедиться, что они безопасны и соответствуют карте), затем обновляет фактические данные. Для карт массива в конечном итоге вызывается array_map_update_elem()
(используется с помощником BPF на стороне ядра, см. Ссылку выше).
(*) Некоторые взаимодействия могут фактически выполняться без системы bpf()
Я полагаю, что с «глобальными данными», хранящимися в картах BPF, используйте приложения mmap()
для памяти ядра. Но это выходит за рамки базового c использования массивов и карт.