Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

CO-RE et BTF : rendre un programme eBPF portable

Par mis à jour le

Améliorer cette page

CO-RE permet de compiler un programme eBPF une seule fois et de le charger sur des noyaux différents, sans le recompiler sur chaque machine. C'est ce qui a fait passer eBPF du bricolage fragile à l'outil de production. Cette page explique le problème que CO-RE résout, le rôle de BTF (l'information de types du noyau qui rend tout cela possible), et le montre sur une machine réelle : le BTF présent, les types du noyau exposés, un vmlinux.h généré. Cette leçon est facultative pour un administrateur : elle sert surtout à qui développe et distribue des outils eBPF, mais elle explique pourquoi votre noyau expose /sys/kernel/btf/vmlinux. Sorties capturées sur une VM Ubuntu 24.04 (noyau 6.8).

  • Comprendre pourquoi un programme eBPF cassait en changeant de noyau
  • Définir BTF et son rôle dans la portabilité
  • Expliquer le principe de CO-RE : compiler une fois, adapter au chargement
  • Vérifier que votre noyau expose le BTF nécessaire
  • Situer CO-RE face à l'ancienne approche par recompilation

Pourquoi un programme eBPF cassait-il entre deux noyaux ?

Section intitulée « Pourquoi un programme eBPF cassait-il entre deux noyaux ? »

Un programme eBPF lit souvent des structures de données du noyau : une tâche, un fichier ouvert, un paquet réseau. Or l'agencement de ces structures en mémoire, l'offset (la position, en octets, de chaque champ), change d'une version du noyau à l'autre. Un champ qui se trouve à l'octet 40 sur un noyau peut être à l'octet 48 sur le suivant.

Un programme compilé pour un noyau précis lit donc les champs aux mauvais endroits sur un autre noyau : au mieux des valeurs absurdes, au pire un refus de chargement. Le programme est collé à son noyau de compilation.

L'ancienne réponse, celle de BCC, était de recompiler sur chaque machine, contre les en-têtes du noyau local. Cela fonctionne, mais impose un compilateur et les en-têtes du noyau sur toutes les cibles, alourdit les images, et coûte du temps et de la mémoire à chaque démarrage. Sur un parc de serveurs, c'est une contrainte lourde.

La solution repose sur BTF (BPF Type Format), une description compacte de tous les types du noyau : chaque structure, chaque champ, chaque taille. Les noyaux récents intègrent cette carte et l'exposent en un point unique. Sur la VM de test, elle est bien là :

Fenêtre de terminal
ls -l /sys/kernel/btf/vmlinux
-r--r--r-- 1 root root 6096599 Jul 14 11:47 /sys/kernel/btf/vmlinux

Ce fichier de 6 Mo décrit l'intégralité des types du noyau en cours d'exécution. On peut le lire avec bpftool, qui le restitue en C :

Fenêtre de terminal
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c | head -20
#ifndef __VMLINUX_H__
#define __VMLINUX_H__
...
typedef unsigned char __u8;
typedef short unsigned int __u16;
typedef unsigned int __u32;
typedef long long unsigned int __u64;

De ce BTF, on génère un unique fichier d'en-tête, vmlinux.h, qui contient toutes les définitions de types du noyau courant. Le programme eBPF l'inclut, et n'a plus besoin des en-têtes du noyau installés sur la machine de compilation.

Fenêtre de terminal
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
wc -l vmlinux.h
150631 vmlinux.h

Plus de 150 000 lignes décrivant le noyau, produites depuis la machine elle-même. C'est la première brique de la portabilité : compiler contre une description exacte du noyau, sans dépendre de paquets d'en-têtes.

Comment CO-RE compile-t-il une fois et s'adapte-t-il au chargement ?

Section intitulée « Comment CO-RE compile-t-il une fois et s'adapte-t-il au chargement ? »

BTF résout la description ; CO-RE (Compile Once Run Everywhere) résout l'adaptation. L'idée est élégante et se déroule en trois temps.

  1. À la compilation, le programme n'écrit pas « lis le champ à l'octet 40 ». Grâce à l'attribut preserve_access_index (visible dans l'en-tête généré plus haut), il note « lis le champ tel-champ de telle structure », en laissant l'offset à résoudre au chargement. Ces notes sont des relocations.

  2. Le binaire est distribué tel quel, une seule fois compilé, embarquant ses relocations.

  3. Au chargement, sur la machine cible, la bibliothèque libbpf lit le BTF du noyau local, retrouve l'offset réel de chaque champ demandé, et réécrit les accès en conséquence avant de passer le programme au vérificateur.

Résultat : le même binaire lit les bons champs sur un noyau 5.15 comme sur un noyau 6.8, parce que les offsets sont résolus au dernier moment, machine par machine. Plus de compilateur sur les cibles, plus de recompilation au démarrage.

Le tableau compare les deux approches sur ce qui compte à l'exploitation : où l'on compile, ce qu'il faut installer sur la cible et le coût au démarrage.

BCC (recompilation)libbpf + CO-RE
Compilationsur chaque machine cibleune seule fois
Dépendances sur la cibleclang + en-têtes du noyauaucune (juste le BTF du noyau)
Démarragelent (compile à chaque fois)rapide (binaire prêt)
Taille de l'outillourdelégère
Portabilitépar recompilationpar relocation au chargement

Cela ne condamne pas BCC : il reste excellent pour apprendre et prototyper, parce qu'écrire un programme dans une chaîne Python et le lancer est immédiat. Mais pour distribuer un outil eBPF à un parc de machines, CO-RE est la voie. La leçon BCC et libbpf compare les deux en pratique.

Trois limites de CO-RE se rencontrent en pratique, et chacune se vérifie avant un déploiement.

  • Pas de BTF, pas de CO-RE. Sur un vieux noyau sans /sys/kernel/btf/vmlinux, il faut se rabattre sur la recompilation, ou fournir un BTF externe (des projets distribuent des BTF pour les noyaux qui n'en embarquent pas).
  • CO-RE relocalise les champs, pas la logique. Si un champ disparaît ou change de sens entre deux noyaux, CO-RE ne l'invente pas : le programme doit gérer cette variabilité explicitement (libbpf offre des tests de présence de champ).
  • vmlinux.h reflète le noyau qui l'a généré. Le régénérer sur un noyau très différent donne un fichier différent ; c'est normal, il décrit un noyau donné. La portabilité vient de la relocation au chargement, pas du vmlinux.h de compilation.
  • Les offsets des champs du noyau changent entre versions : un programme compilé en dur est collé à son noyau.
  • BTF est la description de tous les types du noyau, exposée dans /sys/kernel/btf/vmlinux sur les noyaux récents.
  • vmlinux.h, généré depuis le BTF, remplace les en-têtes du noyau à la compilation.
  • CO-RE compile le programme une fois avec des relocations, que libbpf résout au chargement en lisant le BTF local.
  • Le même binaire tourne alors sur des noyaux différents, sans compilateur ni en-têtes sur les cibles.
  • BCC reste idéal pour apprendre ; libbpf + CO-RE est la voie pour distribuer un outil.

Ce quiz vérifie le raisonnement de la portabilité : ce qui change entre deux noyaux, ce que BTF apporte, et à quel moment CO-RE adapte le programme.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn