Search code examples
clinux-kernelllvm-clangbpfebpf

ebpf - sections names


Is it mandatory to have unique names for every program section in bpf program? For instance, this program compiles fine with llvm-5.0 :

...
SEC("sockops")
int bpf1(struct bpf_sock_ops *sk_ops)
{
   return 1;
}

SEC("sockops")
int bpf2(struct bpf_sock_ops *sk_ops)
{
   return 1;
}

SEC("sockops")
int bpf3(struct bpf_sock_ops *sk_ops)
{
   return 1;
}

SEC("sockops")
int bpf_main(struct bpf_sock_ops *sk_ops)
{
   __u32 port = bpf_ntohl(sk_ops->remote_port);

   switch (port) {
      case 5000: 
         bpf_tail_call(sk_ops, &jmp_table, 1);
         break;
      case 6000:
         bpf_tail_call(sk_ops, &jmp_table, 2);
         break;
      case 7000:
         bpf_tail_call(sk_ops, &jmp_table, 3);
         break;
   }     

   sk_ops->reply = 0;

   return 1;
}  

char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;

However, llvm-objdump reports only one program section:

$ llvm-objdump-5.0 -section-headers bpf_main.o

bpf_main.o:        file format ELF64-BPF

Sections:
Idx Name          Size      Address          Type
  0               00000000 0000000000000000 
  1 .strtab       000000a5 0000000000000000 
  2 .text         00000000 0000000000000000 TEXT DATA 
  3 sockops       000001f8 0000000000000000 TEXT DATA 
  4 .relsockops   00000030 0000000000000000 
  5 maps          0000001c 0000000000000000 DATA 
  6 .rodata.str1.16 00000021 0000000000000000 DATA 
  7 .rodata.str1.1 0000000e 0000000000000000 DATA 
  8 license       00000004 0000000000000000 DATA 
  9 version       00000004 0000000000000000 DATA 
 10 .eh_frame     00000090 0000000000000000 DATA 
 11 .rel.eh_frame 00000040 0000000000000000 
 12 .symtab       00000138 0000000000000000

Is there a compiler option to give at least a warning?

UPDATE - so I understand that sections provided in the same bpf file must have unique names. Is it true in cases when bpf programs reside in different files and compiled independently, so that they could be loaded and call one another, e.g. tail calls?


Solution

  • Apparently the compiler concatenates everything in the same section (I simplified bpf_main to have it compile and to test).

    $ readelf -x sockops bpf_prog.o
    
    Hex dump of section 'sockops':
      0x00000000 b7000000 01000000 95000000 00000000 ................
      0x00000010 b7000000 01000000 95000000 00000000 ................
      0x00000020 b7000000 01000000 95000000 00000000 ................
      0x00000030 b7000000 00000000 95000000 00000000 ...............
    

    From here, I cannot see how you intend to later retrieve the individual programs to load them properly. Usually, user space tools get one program from a section, and attempt to load them by passing the instructions to the kernel through the bpf() syscall; here, whatever program you use will probably try to load the concatenated four programs at once.

    Is there a particular reason why you would like to have all programs in sections with the same name?

    I have no idea for the warning in LLVM on such a thing. I guess not: people may have reason to put different stuff in a section. The case here is specific to BPF, and I do not think people usually try to put several programs in a same section. But this is just a guess, I may be wrong.

    Regarding your update:

    I do not believe using similar sections names in different object files is an issue. As long as your user space tool is able to retrieve the programs from object files and to perform relocation, it should work fine. The kernel does not see any section name anyway. What it takes from the attr argument is an array of instructions:

    struct { /* anonymous struct used by BPF_PROG_LOAD command */
        __u32       prog_type;  /* one of enum bpf_prog_type */
        __u32       insn_cnt;
        __aligned_u64   insns;
        __aligned_u64   license;
        __u32       log_level;  /* verbosity level of verifier */
        __u32       log_size;   /* size of user buffer */
        __aligned_u64   log_buf;    /* user supplied buffer */
        __u32       kern_version;   /* checked when prog_type=kprobe */
        __u32       prog_flags;
        char        prog_name[BPF_OBJ_NAME_LEN];
        __u32       prog_ifindex;   /* ifindex of netdev to prep for */
    };
    

    (from include/uapi/linux/bpf.h, note the insns attribute). For tail calls your user space code also needs to create the specific maps holding referenced to the programs you want to jump to (more bpf() calls). But there again, it's all the responsibility of user space to extract the information from the ELF files. Libbpf should be able to handle it correctly I think, but I have not tried it.

    A side note to finish: I don't know what your use case is exactly, but since you are trying to compile your code in different object files and to use calls, you might be interested to learn that eBPF now supports “function calls”, i.e. you can define several (non-inline) functions, possibly in several ELF files, and call them in your program. More information in the cover letter. Again, I didn't have the time to experiment with it so far.