mbox series

[0/7] BPF CO-RE Support

Message ID 20210804175411.6783-1-david.faust@oracle.com
Headers show
Series BPF CO-RE Support | expand

Message

David Faust Aug. 4, 2021, 5:54 p.m. UTC
[ These patches depend on the series "Allow means for late BTF generation
  for BPF CO-RE" by Indu Bhagat, here:
  https://gcc.gnu.org/pipermail/gcc-patches/2021-July/576446.html ]

Hello,

This patch series adds support for the BPF Compile Once - Run Everywhere
(BPF CO-RE) mechanism in GCC.

A BPF program is some user code which is injected (via a verifier and loader)
into a running kernel, and executed in kernel context. To do useful work, a BPF
program generally must interact with kernel data structures in some way.
Therefore, BPF programs written in C usually include kernel headers.

This introduces two major portability issues when compiling BPF programs:

   1. Kernel data structures regularly change, with fields added, moved or
      deleted between versions. An eBPF program cannot in general be expected
      to run on any systems which does not share an identical kernel version to
      the system on which it was compiled.

   2. Included kernel headers (and used data structures) may be internal, not
      exposed in an userspace API, and therefore target-specific. An eBPF
      program compiled on an x86_64 machine will include x86_64 kernel headers.
      The resulting program may not run well (or at all) in machines of
      another architecture.

BPF CO-RE is designed to solve the first issue by leveraging the BPF loader to
adjust references to kernel data structures made by the program as-needed
according to versions of structures actually present on the host kernel.

To achieve this, additional information is placed in a ".BTF.ext" section.  This
information tells the loader which references will require adjusting, and how to
perform each necessary adjustment.

For any access to a data structure which may require load-time adjustment,
the following information is recorded (making up a CO-RE relocation record):
- The BTF type ID of the outermost structure which is accessed.
- An access string encoding the accessed member via a series of member and
  array indexes. These indexes are used to look up detailed BTF information
  about the member.
- The offset of the appropriate instruction to patch in the BPF program.
- An integer specifying what kind of relocation to perform.

A CO-RE-capable BPF loader reads this information together with the BTF
information of the program, compares it against BTF information of the host
kernel, and determines the appropriate way to patch the specified instruction.

Once all CO-RE relocations are resolved, the program is loaded and verified as
usual. The process can be summarized with the following diagram:

              +------------+
              | C compiler |
              +-----+------+
                    | BPF + BTF + CO-RE relocations
                    v
              +------------+
         +--->| BPF loader |
         |    +-----+------+
         |          | BPF (adapted)
     BTF |          v
         |    +------------+
         +----+   Kernel   |
              +------------+

Note that a single ELF object may contain multiple eBPF programs. As a result, a
single .BTF.ext section can contain CO-RE relocations for multiple programs in
distinct sections.

Many data structure accesses (e.g., those described in the program itself) do
not need to be patched. So, GCC only generates CO-RE information for accesses
marked as being "of interest." To be compatible with LLVM a new BPF target
builtin, __builtin_preserve_access_index, is implemented. Any accesses to
aggregate data structures (structs, unions, arrays) in the argument will have
appropriate CO-RE information generated and output. This builtin is otherwise
transparent - it does not alter the program's functionality in any way.

In addition, a new BPF target attribute preserve_access_index is added.  This
attribute may annotate struct and union type definitions. Any access to a type
with this attribute is automatically "of interest," and will have CO-RE
information generated accordingly.

Finally, generation of BPF CO-RE information is gated behind a new BPF option,
-mcore (and its negative, -mno-core). Because CO-RE support is intimately tied
to BTF debug information, -gbtf for BPF target implies -mcore, and -mcore
requires BTF generation. For cases where BTF information is desired but CO-RE
is not important, it can be disabled with -mno-core.

David Faust (7):
  dwarf: externalize lookup_type_die
  ctfc: externalize ctf_dtd_lookup
  ctfc: add function to lookup CTF ID of a TREE type
  btf: expose get_btf_id
  bpf: BPF CO-RE support
  bpf testsuite: Add BPF CO-RE tests
  doc: BPF CO-RE documentation

 gcc/btfout.c                                  |   2 +-
 gcc/config.gcc                                |   3 +
 gcc/config/bpf/bpf-passes.def                 |  20 +
 gcc/config/bpf/bpf-protos.h                   |   2 +
 gcc/config/bpf/bpf.c                          | 579 ++++++++++++++++++
 gcc/config/bpf/coreout.c                      | 356 +++++++++++
 gcc/config/bpf/coreout.h                      | 114 ++++
 gcc/config/bpf/t-bpf                          |   8 +
 gcc/ctfc.c                                    |  18 +-
 gcc/ctfc.h                                    |   8 +-
 gcc/doc/extend.texi                           |  16 +
 gcc/doc/invoke.texi                           |  13 +-
 gcc/dwarf2out.c                               |   3 +-
 gcc/dwarf2out.h                               |   1 +
 gcc/testsuite/gcc.target/bpf/core-attr-1.c    |  23 +
 gcc/testsuite/gcc.target/bpf/core-attr-2.c    |  21 +
 gcc/testsuite/gcc.target/bpf/core-attr-3.c    |  41 ++
 gcc/testsuite/gcc.target/bpf/core-attr-4.c    |  35 ++
 gcc/testsuite/gcc.target/bpf/core-builtin-1.c |  64 ++
 gcc/testsuite/gcc.target/bpf/core-builtin-2.c |  26 +
 gcc/testsuite/gcc.target/bpf/core-builtin-3.c |  26 +
 gcc/testsuite/gcc.target/bpf/core-section-1.c |  38 ++
 22 files changed, 1411 insertions(+), 6 deletions(-)
 create mode 100644 gcc/config/bpf/bpf-passes.def
 create mode 100644 gcc/config/bpf/coreout.c
 create mode 100644 gcc/config/bpf/coreout.h
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-attr-1.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-attr-2.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-attr-3.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-attr-4.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-1.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-2.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-builtin-3.c
 create mode 100644 gcc/testsuite/gcc.target/bpf/core-section-1.c