xdp-project / xdp-tutorial

XDP tutorial
2.5k stars 580 forks source link

Maps are compiled into different sections within the object file #265

Open CanCebeci opened 2 years ago

CanCebeci commented 2 years ago

I am trying to use basic-02-prog-by-name as a skeleton to compile and load a bpf program that uses multiple maps.

The problem is, when I define multiple maps, each with SEC("maps"), they are compiled into and object file that has multiple sections named "maps", one per map.

To illustrate the issue I am running into, consider the following: I modify xdp_prog_kern.c to include three instances of the map defined in the third basic tutorial:

struct bpf_map_def SEC("maps") xdp_stats_map_1 = {
    .type        = BPF_MAP_TYPE_ARRAY,
    .key_size    = sizeof(__u32),
    .value_size  = sizeof(struct datarec),
    .max_entries = XDP_ACTION_MAX,
};

struct bpf_map_def SEC("maps") xdp_stats_map_2 = {
    .type        = BPF_MAP_TYPE_ARRAY,
    .key_size    = sizeof(__u32),
    .value_size  = sizeof(struct datarec),
    .max_entries = XDP_ACTION_MAX,
};

struct bpf_map_def SEC("maps") xdp_stats_map_3 = {
    .type        = BPF_MAP_TYPE_ARRAY,
    .key_size    = sizeof(__u32),
    .value_size  = sizeof(struct datarec),
    .max_entries = XDP_ACTION_MAX,
};

and I modify the xdp_pass_func to access these maps:

SEC("xdp_pass")
int  xdp_pass_func(struct xdp_md *ctx)
{
        struct datarec *value;
        __u32 key = 0;
        value = bpf_map_lookup_elem(&xdp_stats_map_2, &key);
    return XDP_PASS;
}

When I run make, the generated object file has three "maps" sections

llvm-readelf -S xdp_prog_kern.o
There are 27 section headers, starting at offset 0x13e0:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .strtab           STRTAB          0000000000000000 0012c8 000118 00      0   0  1
  [ 2] .text             PROGBITS        0000000000000000 000040 000000 00  AX  0   0  4
  [ 3] xdp_pass          PROGBITS        0000000000000000 000040 000048 00  AX  0   0  8
  [ 4] .relxdp_pass      REL             0000000000000000 000e18 000010 10     26   3  8
  [ 5] xdp_drop          PROGBITS        0000000000000000 000088 000010 00  AX  0   0  8
  [ 6] maps              PROGBITS        0000000000000000 000098 000014 00  WA  0   0  4
  [ 7] maps              PROGBITS        0000000000000000 0000ac 000014 00  WA  0   0  4
  [ 8] maps              PROGBITS        0000000000000000 0000c0 000014 00  WA  0   0  4
  [ 9] license           PROGBITS        0000000000000000 0000d4 000004 00  WA  0   0  1
  [10] .debug_loc        PROGBITS        0000000000000000 0000d8 000048 00      0   0  1
  ...

When I try to load the program (xdp_pass) with xdp_loader, I get the following error:

  libbpf: Program 'xdp_pass' contains unrecognized relo data pointing to section 7

That is because libbpf loops over the sections in the object file and only loads the maps in the last section that is named "maps". Also note that trying to access xdp_stats_map_3 instead of xdp_stats_map_2 works fine, meaning the program is successfully loaded in that case.

Why does make produce and object file with multiple "maps" sections? How can I work around this? Is there a way to get an object file with a unified "maps" section?

Thanks :)

tohojo commented 2 years ago

Hmm, haven't seen this one before. Only weird thing I can see is that I usually put the SEC() macro after the definition (just before the ;) for maps. If that doesn't help, what LLVM version are you seeing this with?

CanCebeci commented 2 years ago

I had the issue with Clang 13. I don't have it with Clang 10.

tohojo commented 2 years ago

Can Cebeci @.***> writes:

I had the issue with Clang 13. I don't have it with Clang 10.

Hmm, well in that case it wounds like a regression bug in Clang? I'd suggest you try reporting it as such :)