ошибка при установке программы XDP с помощью команды ip

Я пытаюсь установить программу XDP на свой сетевой драйвер, но получаю сообщение об ошибке ELF содержит не связанные с {map, call} данные relo в записи 0, указывающей на раздел 4! Ошибка компилятора?! Ошибка загрузки программы/карты!

код, который я пытаюсь запустить:

#define KBUILD_MODNAME "filter"
#include <arpa/inet.h>
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/udp.h>

static int (*bpf_trace_printk)(const char *fmt,...) = (void *)BPF_FUNC_trace_printk;

int udpfilter(struct xdp_md *ctx) {
    bpf_trace_printk("got a packet\n");
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    if ((void*)eth + sizeof(*eth) <= data_end) {
       struct iphdr *ip = data + sizeof(*eth);
       if ((void*)ip + sizeof(*ip) <= data_end) {
         if (ip->protocol == IPPROTO_UDP) {
            struct udphdr *udp = (void*)ip + sizeof(*ip);
            if ((void*)udp + sizeof(*udp) <= data_end) {
               if (udp->dest == ntohs(7999)) {
                  bpf_trace_printk("udp port 7999\n");
                  udp->dest = ntohs(7998);
              }
            }
          }
        }
      }
   return XDP_PASS;
   }

команда компиляции: clang -O2 -g -Wall -target bpf -c filter.c -o filter.o и все в порядке!

и команда, которую я использую для установки: ip link set enp0s3 xdpgeneric obj filter.o, тогда я получаю указанную выше ошибку.

я не уверен, что должно означать это сообщение, я что-то пропустил?


person walid barakat    schedule 02.07.2021    source источник
comment
На первый взгляд, это может быть связано с тем, как вы называете bpf_trace_printk(). У него должен быть как минимум еще один аргумент для передачи размера строки формата, и я не уверен, что вы можете передать строку формата напрямую, как это может быть причиной создания данных о перемещении. См. другие примеры вызова помощника. См. также его документацию.   -  person Qeole    schedule 02.07.2021
comment
спасибо Qeolo, вы были правы насчет параметра размера. но это не было решением. Я ответил на вопрос и объяснил, как это было сделано. я отдал вам должное :') и надеюсь, что вы взглянете и проголосуете за ответ, если он удобен.   -  person walid barakat    schedule 04.07.2021


Ответы (1)


Ошибка загрузки программы/карты!

Вам не нужно включать этот каталог, упомянутый в другом, во время компиляции. Эта ошибка связана с тем, что ip не удалось найти ожидаемый раздел в файле ELF. См. ip-link справочную страницу:

Если параметр section не передан, то будет использоваться имя раздела по умолчанию (prog), в противном случае будет использоваться указанное имя раздела.

Итак, у вас есть два решения:

  1. Поместите свою функцию в раздел prog ELF:

    __attribute__((section("prog"), used))
    int udpfilter(struct xdp_md *ctx) {
            [...]
    }
    
  2. Используйте опцию section при загрузке программы. По умолчанию clang помещает ваш код в секцию .text:

    # ip link set enp0s3 xdpgeneric obj filter.o sec .text
    

ELF содержит не связанные с {map,call} данные relo в записи 0, указывающие на раздел 4! Ошибка компилятора?!

Как обсуждалось ранее, это вызвано тем, что вы используете bpf_trace_prink(). Вы не можете просто передать строку формата напрямую помощнику, потому что clang поместит ее в определенную секцию ELF и пометит как данные о перемещении, но загрузчик (в данном случае ip) не будет знать, что с ней делать. И, конечно же, вы должны передать ему как минимум второй аргумент, чтобы указать размер строки вашего формата. Подробнее см. в его документации.

Обратите внимание, что мы часто можем видеть обертки, определенные следующим образом для этого помощника:

#define bpf_printk(fmt, ...)                    \
({                                              \
    char ____fmt[] = fmt;                       \
    bpf_trace_printk(____fmt, sizeof(____fmt),  \
             ##__VA_ARGS__);                    \
})

Строка объявлена ​​таким образом, что не вызывает никакого перемещения, и после этого ее удобнее использовать, и вы можете просто сделать bpf_printk("got a packet\n");.

person Qeole    schedule 05.07.2021
comment
спасибо за этот ответ, так получилось, что я видел ваши ответы почти на все вопросы ebpf. и у меня к вам вопрос, есть ли намек на подготовку среды для разработки программ eBPF? например, как получить заголовок pbf helpers и т. д. и иметь стабильную среду разработки - person walid barakat; 06.07.2021
comment
Да, nakryiko.com/posts/libbpf-bootstrap, вероятно, лучший вариант, который вы можете получить. в данный момент. - person Qeole; 06.07.2021