Я использую tc
для подключения моего eBPF (код C скомпилирован с использованием clang), к сети.
Я использую Карты eBPF для хранения некоторых данных.
В частности, я использую bpf_map_update_elem
для обновления карт eBPF изнутри программы BPF, но я также хочу изменить содержимое карты из-за пределов программы. 1111]
Структура карты :
struct rt_val {
int ifaceno;
int macaddr[6];
};
union key_4 {
__u32 b32[2];
__u8 b8[8];
};
struct bpf_map_def SEC("maps") lpm_map_fwd = {
.type = BPF_MAP_TYPE_LPM_TRIE,
.key_size = 8,
.value_size = sizeof(struct rt_val),
.max_entries = 50,
.map_flags = BPF_F_NO_PREALLOC,
};
Обновление карты и поиск в порядке.
Но я хочу динамически изменять содержимое карты eBPF извне выполнения программы.
blockquote>Любые комментарии / предложения, касающиеся того же самого, будут высоко оценены !
Ресурсы:
Особенности системы:
uname -r
: 4.15.0-47- универсальныйOS
: Ubuntu 18
Вы уже нашли все инструменты, необходимые для обновления карт eBPF из пространства пользователя.
bpf()
Системный вызов bpf(cmd, attr, size)
используется для выполнения обновления. cmd
, переданный в качестве первого аргумента, указывает, какой тип операции вы хотите выполнить: в вашем случае это будет BPF_MAP_UPDATE_ELEM
. Затем на странице руководства, на которую вы ссылаетесь, объясняется, как создать attr
: в вашем случае (для обновления карты) это должно быть:
struct { /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY commands */
__u32 map_fd;
__aligned_u64 key;
union {
__aligned_u64 value;
/* [...] */
};
__u64 flags;
};
То есть вы должны построить union bpf_attr
и передать ему дескриптор файла. на карту - ключ записи, которую вы хотите обновить, новое значение для этого ключа и, возможно, некоторые флаги.
Дескриптор файла для карты можно получить:
bpf()
, используя команду BPF_MAP_GET_FD_BY_ID
, bpf()
, который создал карту, но не в этом случае вы использовали tc для загрузки программы). Обратите внимание, что libbpf ( поставляется с ядром или , отраженным на GitHub ), предоставляет оболочки вокруг системного вызова bpf()
и может упростить задачу.
На практике вам не нужно переопределять все это. Как вы упомянули в заголовке, bpftool позволяет обновлять карты из командной строки, не переопределяя весь процесс.
На момент написания этой статьи bpftool не был упакован для Debian / Ubuntu, что означает, что вы должны собрать его из исходного кода. Он поставляется вместе с ядром, поэтому для его загрузки требуется время, но сборка на самом деле очень проста:
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ cd linux
$ cd tools/bpf/bpftool
$ make
(# make install)
(# make doc doc-install)
В качестве альтернативы на этой странице есть неофициальная версия (заявление об отказе: из моей компании). Упакованный двоичный файл был статически собран и должен работать на всех компьютерах Linux x86_64.
После этого вы можете использовать его для отображения карт, существующих в настоящее время в вашей системе:
# bpftool -f map show
Идентификаторы каждой карты будут отображаться слева. Найдите идентификатор, связанный с картой, которую вы хотите обновить (или, если карта была закреплена, запишите ее путь, отображаемый с опцией -f
), а затем используйте одно из:
# bpftool map update id <id> key <key> value <new_value>
# bpftool map update pinned <path> key <key> value <new_value>
Например:
# bpftool map update id 17 key 0x1 0 0 0 0 0 0 0 value 0x1 0x2 0x3...
(Примечание: я бы использовал массив __u8
с, а не int
с для хранения MAC-адреса в вашем struct rt_val
. Ваш macaddr
, скорее всего, будет рассчитывать на 24 байта .)
Если вы не знаете, как значения хранятся на карте, не стесняйтесь вывести их в консоль:
# bpftool map dump id 17
I не знаю ни одного существующего руководства по bpftool, но вы можете найти все подробности на страницах руководства для этого инструмента. Я также написал несколько советов об этом в Твиттере .