개요

BTF란 BPF Type Format의 약자이다. 마치 Dwarf처럼 Object에 대한 Relocation table을 가지고 있다. 그러나 Dwarf와는 다르게 eBPF의 CO-RE (Compiler once run everywhere)의 기능을 제공하기 위한 정보만을 담고 있기에 간단하고 용량을 적게 차지 한다. eBPF프로그램은 커널의 여러 부위에 붙어서 작동하게 되는데 이러한 과정에서 커널 버전, 혹은 커널 패칭을 통해서 달라질 수 있는 정보들을 BTF에 저장하여 Loading시에 동적으로 Relocation이 일어날 수 있도록 하여서 재 컴파일 없이 BPF프로그램이 언제 어디서나 작동 될 수 있도록 하였다.

BTF는 eBPF에서 Portable과 Debugging을 용의하게 한다. 

BTF는 두가지로 나뉘어 진다.

  • BTF Kernel API (User space와 Kernel space간의 BPF에 대한 조건을 나누기 위해서 사용된다.)
  • BTF ELF file format (User space와 Libbpf간에 BPF Relocation에 대한 조건을 나누기 위해서 사용된다.)

Supports

Compiler

우선 Clang이 컴파일 단계에서 BTF relocation을 ELF포맷에 작성하게 된다. 예를 들어서 task_struct->pid라는 정보에 접근하고 있으면 Clang은 struct의 offset만을 저장하는 것이 아니라 struct task_struct에 pid라는 이름을 가진 위치에 접근하고 있다고 BTF에 기록하게 된다. 이를 통해서 pid가 struct의 어느 위치로 이동하더라도 다시 Relocation이 가능하게 할 수 있게 되었다.

Libbpf

Libbpf에서는 컴파일된 ELF 포맷의 BPF파일을 받아서 parsing과 Loading을 진행하게 된다. Libbpf는 우선 BPF 프로그램의 BTF항목을 확인하고 지금 Host kernel의 BTF와 비교하여 BPF프로그램의 적절하지 못한 Offset이나 Relocatable data를 옮겨 주게 된다. 이를 통해서 BTF의 Mismatch를 해결하고 변경된 시스템에 맞추어서 BPF프로그램이 작동할 수 있도록 Patching한다.

Kernel

커널에서는 이미 Libbpf에 의해서 Parsing된 결과를 받기 떄문에, 큰 수정 없이도 CO-RE를 구현할 수 있게 된다. 그러나 이 밖에도 Kernel이 BPF프로그램과 나누기 위해서 필요한 정보들이 있는데, 예를 들어서 Endian정보나, 혹은 Type에 대한 정보들을 BTF포맷을 통해서 교환하게 된다. 또한 Kernel은 BTF를 통해서 Verification을 보다 정교하게 수행할 수 있게 된다. 추가적으로 Kernel에서 Loading된 BPF에 대한 BTF를 원하는 Application에 BTF에 대한 파일의 위치를 몰라도 전달 할 수 있게 된다.

참고

  1. https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html
  2. https://www.kernel.org/doc/html/latest/bpf/btf.html