Почему верификатор BPF выдает ошибку с нулевым ключом при использовании BPF_MAP_TYPE_QUEUE?

Я пытаюсь загрузить программу BPF с картой очереди. Кажется, я получаю сообщение об ошибке, связанное с нулевым ключом.

libbpf: -- BEGIN DUMP LOG ---
libbpf: 
0: (b7) r1 = 123
1: (63) *(u32 *)(r10 -4) = r1
2: (bf) r3 = r10
3: (07) r3 += -4
4: (18) r1 = 0xffff9df655207800
6: (b7) r2 = 0
7: (b7) r4 = 0
8: (85) call bpf_map_update_elem#2
R2 type=inv expected=fp
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

libbpf: -- END LOG --

программа БНФ

#include <bpf/bpf.h>
#include <string.h>

struct bpf_map SEC("maps") queue_map = {
  .type = BPF_MAP_TYPE_QUEUE,
  .key_size = 0,
  .value_size = sizeof(int),
  .max_entries = 100,
  .map_flags = 0,
};

SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx) {

  int value;
  value = 123;
  bpf_map_update_elem(&queue_map, NULL, &value, BPF_ANY);

  return 0;
}

char _license[] SEC("license") = "GPL";

Однако если я переключу карту очереди на карту массива, обновив .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), и предоставлю действительный ключ функции bpf_map_update_elem, программа bpf загрузится и заработает. Я загружаю программу с помощью libbpf.

int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
                       struct bpf_object **pobj, int *prog_fd)
{
  struct bpf_prog_load_attr attr;

  memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
  attr.file = file;
  attr.prog_type = type;
  attr.expected_attach_type = 0;

  return bpf_prog_load_xattr(&attr, pobj, prog_fd);
}
  1. Что вызывает ошибку?
  2. Я использую файлы заголовков из /tools/perf. Должен ли я использовать разные файлы заголовков?
  3. Нужно ли загружать карты очередей иначе, чем карты массивов?
  4. Есть ли флаги карты, которые мне нужно добавить для карты очереди?

person steepestascent    schedule 21.05.2020    source источник
comment
Я удивлен, что это работает для карты массива. Единственное, что вы изменили в этой строке: .type = BPF_MAP_TYPE_QUEUE,? Также обратите внимание, что bpf_map_update_elem не является допустимым помощником для карт очередей; он ничего не сделает и вернет ненулевой код ошибки.   -  person pchaigno    schedule 22.05.2020
comment
@pchaigno в дополнение к .type = BPF_MAP_TYPE_QUEUE я обновил .key_size = sizeof(int) и предоставил действительный key функции bpf_map_update_elem. Я обновлю вопрос, чтобы быть более ясным. Я обновил программу, чтобы использовать bpf_map_push_elem, и программа загружается и работает как положено!   -  person steepestascent    schedule 23.05.2020


Ответы (1)


Верификатор жалуется, потому что он ожидает указатель для второго аргумента на bpf_map_update_elem() (fp вместо frame pointer, когда вместо этого у вас есть NULL). Но, как упомянул pchaigno, это недействительно для карт очередей; Я не думаю, что это ничего не даст, я считаю, что оно не пройдет проверку (отклонено check_map_func_compatibility(), если бы вы могли каким-то образом передать эту ошибку указателя).

Для очередей (или стеков) вы хотите использовать bpf_map_(push|pull|peek)_elem() помощники.

По другим вашим вопросам:

  1. Не уверен, какие заголовки вы используете в частности. Зависит от того, какие определения вам нужны, я полагаю.

  2. Вы создаете карты таким же образом, но обновляете их по-разному (разные помощники, как объяснялось выше) — в этом смысл наличия очереди вместо, например, очереди. массив.

  3. Нет, я не думаю, что вам нужны определенные флаги для создания карты.

person Qeole    schedule 22.05.2020
comment
Спасибо за помощь. Я ссылался на устаревший пример карты очереди. Я смог загрузить программу, обновив bpf_map_update_elem(&queue_map, NULL, &value, BPF_ANY); до bpf_map_push_elem(&queue_map, &value, BPF_ANY); и добавив этот прототип в файл static int (*bpf_map_push_elem)(void *map, const void *value, unsigned long long flags) = (void *) BPF_FUNC_map_push_elem; - person steepestascent; 23.05.2020