0

i'm trying to install XDP program on my network driver but i get the error ELF contains non-{map,call} related relo data in entry 0 pointing to section 4! Compiler bug?! Error fetching program/map!

the code i'm trying to run :

#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;
   }

compiling command : clang -O2 -g -Wall -target bpf -c filter.c -o filter.o and it's ok!

and the command i use to install : ip link set enp0s3 xdpgeneric obj filter.o then i get the above error.

i'm not sure what it should means this message, did i miss something?

walid barakat
  • 455
  • 1
  • 6
  • 17
  • 2
    On a quick look, this might be due to the way you call `bpf_trace_printk()`. It should have at least another argument to pass the size of the format string, and I'm not sure you can pass the format string directly like this, that's what might be causing the relocation data to be generated. See [other examples](https://stackoverflow.com/questions/60629844/bpf-trace-printk-format-pointer) for calling the helper. See also [its documentation](https://www.man7.org/linux/man-pages/man7/bpf-helpers.7.html). – Qeole Jul 02 '21 at 14:11
  • thanks Qeolo, you were right about about the size parameter. but it wasn't the solution. i answered the question and explained how it got done. i gave you the credit for sure :') and hope you take the look and upvote for the answer if it's a convenience one. – walid barakat Jul 04 '21 at 18:13

1 Answers1

0

Error fetching program/map!

You don't have to include this directory mentioned in your other at compilation time. This error is due to ip not finding the expected section in the ELF file. See ip-link man page:

If no section option is passed, then the default section name ("prog") will be assumed, otherwise the provided section name will be used.

So you have two solutions:

  1. Place your function in a prog ELF section:

    __attribute__((section("prog"), used))
    int udpfilter(struct xdp_md *ctx) {
            [...]
    }
    
  2. Use the section option when loading the program. By default, clang puts your code into the .text section:

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

ELF contains non-{map,call} related relo data in entry 0 pointing to section 4! Compiler bug?!

As discussed earlier, this is caused by your use of bpf_trace_prink(). You cannot simply pass the format string directly to the helper, because clang will place it in a specific ELF section and mark at as relocation data, but the loader (ip in this case) will not know what to do with it. And of course, you have to pass it at least a second argument, to provide the size of your format string. See its documentation for details.

Note that we can often see wrappers defined like this for that helper:

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

The string is declared in a way that won't trigger any relocation, and after that it's more convenient to use and you could just do bpf_printk("got a packet\n");.

Qeole
  • 8,284
  • 1
  • 24
  • 52
  • thanks for this answer, it happens that i saw your answers in almost all ebpf questions. and i have a question for you, is there's any hint to prepare the environment for eBPF programs development? like how to get pbf helpers header and etc and have a stable development environment – walid barakat Jul 06 '21 at 13:41
  • Yes, https://nakryiko.com/posts/libbpf-bootstrap/ is probably the best option you can get at the moment. – Qeole Jul 06 '21 at 14:05