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é. Public : développeur eBPF visant un déploiement sur un parc hétérogène. Sorties capturées sur une VM Ubuntu 24.04 (noyau 6.8).
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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
Le problème : un programme collé à son noyau
Section intitulée « Le problème : un programme collé à son noyau »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.
BTF : la carte des types du noyau
Section intitulée « BTF : la carte des types du noyau »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à :
ls -l /sys/kernel/btf/vmlinux-r--r--r-- 1 root root 6096599 Jul 14 11:47 /sys/kernel/btf/vmlinuxCe 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 :
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;vmlinux.h : les structures du noyau sans ses en-têtes
Section intitulée « vmlinux.h : les structures du noyau sans ses en-têtes »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.
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.hwc -l vmlinux.h150631 vmlinux.hPlus 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.
CO-RE : compiler une fois, s'adapter au chargement
Section intitulée « CO-RE : compiler une fois, s'adapter au chargement »BTF résout la description ; CO-RE (Compile Once Run Everywhere) résout l'adaptation. L'idée est élégante.
-
À 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 à déterminer plus tard. Ces notes sont des relocations. -
Le binaire est distribué tel quel, une seule fois compilé, embarquant ses relocations.
-
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.
CO-RE face à l'ancienne approche
Section intitulée « CO-RE face à l'ancienne approche »| BCC (recompilation) | libbpf + CO-RE | |
|---|---|---|
| Compilation | sur chaque machine cible | une seule fois |
| Dépendances sur la cible | clang + en-têtes du noyau | aucune (juste le BTF du noyau) |
| Démarrage | lent (compile à chaque fois) | rapide (binaire prêt) |
| Taille de l'outil | lourde | légère |
| Portabilité | par recompilation | par 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. Le guide BCC et libbpf compare les deux en pratique.
Points de vigilance
Section intitulée « Points de vigilance »- 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.hreflè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 duvmlinux.hde compilation.
À retenir
Section intitulée « À retenir »- 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/vmlinuxsur 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.