Ce qu'est vraiment eBPF, et pourquoi la moitié de l'infrastructure moderne en dépend discrètement
Le problème avec l'ancienne façon d'étendre le noyau
Pendant la majeure partie de l'histoire de Linux, pour observer ou modifier quelque chose se passant au cœur du noyau — quel processus ouvre quel fichier, quel paquet réseau arrive sur quelle interface, combien de temps un appel système prend réellement — il n'existait que deux mauvaises options. Écrire un module noyau : du vrai code C chargé directement dans le noyau et s'exécutant avec un accès total et illimité à toute la machine. Un seul bug dans ce code — un pointeur nul, un accès mémoire invalide — ne fait pas planter votre programme, il fait planter tout le système d'exploitation, instantanément, entraînant avec lui tous les autres processus de la machine. Ou bien éviter complètement le noyau et observer les choses depuis l'espace utilisateur, ce qui est sûr mais lent et souvent incapable de voir ce dont vous avez réellement besoin, car le noyau est exactement l'endroit où les événements intéressants se produisent en premier.
eBPF (extended Berkeley Packet Filter — le nom est un vestige historique ; il fait bien plus que du filtrage de paquets aujourd'hui) est la troisième option apparue pour résoudre ce problème : une façon d'exécuter de petits programmes isolés à l'intérieur du noyau, déclenchés par de vrais événements noyau, sans le risque de faire planter toute la machine qu'implique un module noyau.
Comment il parvient à être à la fois rapide et sûr
Un programme eBPF est écrit dans un sous-ensemble restreint du C, compilé en un bytecode spécial, puis chargé dans le noyau via un appel système dédié. Avant que ce bytecode soit autorisé à s'exécuter, le vérificateur du noyau parcourt chaque chemin d'exécution possible du programme et le rejette purement et simplement s'il trouve quoi que ce soit de dangereux : une boucle non bornée qui pourrait bloquer indéfiniment, un accès mémoire hors des limites autorisées, tout ce qui pourrait faire planter le noyau ou exposer une mémoire qu'il ne devrait pas voir. Seul le code qui survit à cette vérification est compilé juste-à-temps en instructions machine natives et attaché à l'événement noyau auquel il est censé répondre — un paquet réseau qui arrive, un appel système effectué, une fonction qui est entrée. Parce qu'il s'exécute réellement comme du code natif à l'intérieur du noyau plutôt que d'être interprété, et parce qu'il est directement attaché à l'événement qui l'intéresse au lieu de le sonder périodiquement, un programme eBPF peut observer et réagir à des événements avec une vitesse et un niveau de détail auparavant réservés au code noyau risquant de planter toute la machine — mais les garanties du vérificateur font qu'un programme eBPF bogué est rejeté au chargement ou arrêté en toute sécurité, jamais autorisé à entraîner le noyau dans sa chute.
Ce à quoi les gens l'utilisent réellement
L'observabilité est l'endroit où la plupart des ingénieurs croisent eBPF pour la première fois, même sans jamais en écrire une ligne eux-mêmes. Des outils comme bpftrace et toute la génération moderne d'outils de débogage de performance Linux utilisent eBPF pour répondre à des questions qui nécessitaient auparavant d'ajouter des logs de debug et de redémarrer un service : quelle fonction consomme réellement le CPU en ce moment, quel processus vient d'ouvrir ce fichier précis, combien de temps a réellement pris cette requête de base de données au niveau du noyau. Parce que les programmes eBPF s'attachent directement au noyau en cours d'exécution, ils peuvent répondre à ces questions sur un système de production en direct, sans rien redémarrer et sans la surcharge des outils de débogage traditionnels — un niveau de « pouvoir observer ce qui se passe maintenant » réellement différent de ce qui existait avant.
Le réseau est le deuxième cas d'usage majeur, et c'est pourquoi eBPF tourne discrètement sous une grande partie de l'infrastructure cloud moderne. Cilium, un plugin réseau pour Kubernetes utilisé à grande échelle, remplace la pile réseau Linux traditionnelle basée sur des règles iptables — qui ralentissent à mesure que leur nombre augmente — par des programmes eBPF qui prennent les décisions de routage et de filtrage directement à l'arrivée des paquets, avec un passage à l'échelle bien meilleur quand un cluster atteint des milliers de pods et de politiques réseau. Quand une entreprise dit que son réseau Kubernetes est « basé sur eBPF », c'est ce qu'elle veut dire : routage des paquets, répartition de charge et application des politiques réseau se produisant comme du code compilé à l'intérieur du noyau plutôt que comme une chaîne lente de recherches de règles en espace utilisateur.
La sécurité, le troisième pilier
Parce que les programmes eBPF peuvent observer chaque appel système, chaque ouverture de fichier et chaque connexion réseau au moment où ils se produisent, ils conviennent extrêmement naturellement aux outils de sécurité runtime qui doivent détecter « ce processus vient de tenter quelque chose qu'il n'a jamais fait » en temps réel, plutôt que de reconstituer ce qui s'est passé après coup à partir de logs. Falco, l'un des outils de sécurité runtime open source les plus connus, est entièrement construit sur cette idée — des programmes eBPF observant les événements noyau en direct et signalant les schémas réellement suspects dès qu'ils se produisent.
Pourquoi « extended » est le bon mot
Le BPF original, de 1992, était un outil bien plus étroit conçu pour exactement un travail : filtrer quels paquets réseau un programme comme tcpdump était autorisé à voir, efficacement, sans copier chaque paquet vers l'espace utilisateur juste pour en rejeter la plupart. eBPF a conservé ce même mécanisme central — une minuscule machine virtuelle vérifiée attachée à des événements noyau — et l'a généralisé pour s'attacher à presque n'importe quel événement noyau, pas seulement l'arrivée de paquets, ce qui explique pourquoi une technologie qui a commencé comme un filtre de paquets sous-tend aujourd'hui des outils d'observabilité, des outils de sécurité et des répartiteurs de charge qui n'ont rien à voir avec le filtrage de paquets.
Pourquoi ça vaut la peine de comprendre même sans jamais écrire de programme eBPF
Vous n'avez pas besoin d'écrire du bytecode eBPF à la main pour bénéficier de comprendre ce que c'est — la plupart des ingénieurs qui en dépendent le font entièrement via des outils construits par-dessus, tout comme la plupart des gens qui bénéficient de TCP/IP n'ont jamais écrit de socket à la main. Ce qui vaut la peine d'être intégré, c'est la forme de l'idée : une façon d'exécuter en sécurité du code personnalisé exactement au moment et à l'endroit où un événement se produit réellement dans le noyau, au lieu d'accepter soit le risque de faire planter toute la machine d'un module noyau, soit les angles morts et la surcharge d'une observation depuis l'espace utilisateur. Une fois que vous reconnaissez cette forme, vous commencez à la remarquer partout — dans la façon dont le réseau Kubernetes d'une entreprise passe à l'échelle, dans la façon dont un incident de production a été débogué en direct sans redémarrage, et dans la raison pour laquelle « basé sur eBPF » est devenu un argument que les fournisseurs mettent en avant plutôt qu'un détail enfoui dans la documentation.