{"id":15629605,"url":"https://github.com/pyaillet/ebpf-discovery","last_synced_at":"2026-02-26T08:40:51.701Z","repository":{"id":83797210,"uuid":"192503728","full_name":"pyaillet/ebpf-discovery","owner":"pyaillet","description":"Repository for material and article on eBPF","archived":false,"fork":false,"pushed_at":"2019-07-08T15:16:22.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-11T08:06:12.193Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyaillet.png","metadata":{"files":{"readme":"README.fr_FR.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-18T08:58:50.000Z","updated_at":"2019-07-08T15:16:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"1fef20d1-0593-4b3b-8eaf-634cb9a95847","html_url":"https://github.com/pyaillet/ebpf-discovery","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyaillet%2Febpf-discovery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyaillet%2Febpf-discovery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyaillet%2Febpf-discovery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyaillet%2Febpf-discovery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyaillet","download_url":"https://codeload.github.com/pyaillet/ebpf-discovery/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyaillet%2Febpf-discovery/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259227951,"owners_count":22824902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T10:27:45.524Z","updated_at":"2026-02-26T08:40:46.679Z","avatar_url":"https://github.com/pyaillet.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Découverte d'eBPF\n\nEn tant qu'utilisateur de Linux, il est possible que la seule chose qui vous\nintéresse soit l'inclusion de la dernière version des drivers de votre matériel\ndans le noyau.\nPourtant, c'est loin d'être le seul pan du kernel qui évolue !\nCe sont notamment des évolutions du kernel (namespace, cgroups, ...) qui ont\npermis de développer les conteneurs logiciels tels que Docker.\nDans cet article, je vous propose de découvrir une autre innovation majeure du\nkernel : eBPF (ce n'est pas moi qui le dit mais [The New Stack](https://thenewstack.io/linux-technology-for-the-new-year-ebpf/)).\n\n## Historique\n\nHistoriquement, lorsqu'on souhaitait faire de la capture réseau sous Unix,\ncette opération était réalisée dans l'espace utilisateur (c'est à dire en\ndehors du kernel).\nEn général, lorsqu'on souhaite capturer du traffic réseau pour identifier un\nproblème, on ne veut pas l'ensemble du traffic mais on souhaite filtrer selon\ncertains critères (protocole, destination, ...).\nPourtant en pratique, cela nécessitait de copier l'intégralité des paquets\ndepuis le kernel vers l'espace utilisateur avant même de déterminer si un\npaquet était intéressant à conserver pour une session particulière de capture.\n\nAinsi en 1992, Steve McCanne et Van Jacobson ont publié\n[un article](http://www.tcpdump.org/papers/bpf-usenix93.pdf) proposant une\nnouvelle architecture pour la capture de paquets en espace utilisateur.\nCelle-ci repose sur une machine virtuelle à registres qui fonctionne dans le\nkernel et permet d'évaluer les règles de filtrage des paquets sans recopie des\npaquets.\nCe mécanisme a été intégré au noyau Linux\n[en 1997 dans la version 2.1.75](https://lwn.net/1998/0212/).\nIl est disponible sur la plupart des Unix et est utilisée par des outils\nstandards comme [tcpdump](https://www.tcpdump.org/) pour sélectionner les\npaquets à capturer.\nÀ ce moment là, la machine virtuelle BPF est assez limitée : elle ne comporte\nque 2 registres 32 bits, une pile de taille minimaliste et ne supporte que les\nsauts vers l'avant.\n\nEn 2012, une [évolution de bpf](https://lwn.net/Articles/475043/) est proposée\nafin de sécuriser et filtrer certains appels systèmes en attachant à leur appel\nun programme bpf permettant d'évaluer le contexte et de permettre ou interdire\nl'appel comme cela était fait pour le traitement du traffic réseau.\n\nMais l'évolution majeure arrive en 2013, Alexei Starovoitov propose alors\n[Extended BPF](https://lwn.net/Articles/575531/). Voici un résumé de ces\névolutions :\n\n- Un vérifieur qui s'assure que le code est sûr :\n  - pas de boucles infinies\n  - pas d'utilisation de pointeurs non vérifiés\n  - ...\n- Un compilateur JIT pour transformer le programme BPF en code natif\n- L'extension des capacités de la machine virtuelle :\n  - passage de 2 registres 32 bits à 10 registres 64 bits\n  - possibilité d'appeler certaines fonctions du kernel\n\nPar la suite, d'autres fonctionnalités seront encore intégrées :\n\n- utilisation de [maps](https://prototype-kernel.readthedocs.io/en/latest/bpf/ebpf_maps.html) pour l'échange d'information entre le programme bpf et l'espace utilisateur\n- la possibilité d'instrumenter encore plus d'événements du kernel avec des programmes bpf\n- ...\n\nPour une liste complète, n'hésitez pas à vous référer à\n[la page de Brendan Gregg](http://www.brendangregg.com/ebpf.html) sur le sujet.\nEn particulier, ce [schéma](http://www.brendangregg.com/eBPF/linux_ebpf_support.png).\n\nPour résumer, BPF est l'appellation d'origine. Linux a introduit l'appellation\neBPF et pour différencier de l'ancienne version celle-ci est parfois nommée\ncBPF.\nDonc :\n\n- lorsqu'on vous parle de cBPF c'est sans les extensions\n- lorsqu'on vous parle d'eBPF il s'agit de la version moderne\n- lorsqu'on vous parle de BPF `¯\\_(ツ)_/¯`\n\n## Principe\n\nMaintenant, qu'on en connaît un peu plus sur l'historique du projet, voyons\ncomment il fonctionne...\n\n### Fonctionnement\n\nTout est basé sur un appel système :\n\n```c\n#include \u003clinux/bpf.h\u003e\n\nint bpf(int cmd, union bpf_attr *attr, unsigned int size);\n```\n\nLe premier argument `cmd` indique l'action à réaliser, exemple : \n`BPF_PROG_LOAD`, pour charger un programme bpf.\nLe deuxième argument `attr` porte les paramètres de l'action à réaliser, sa\nstructure dépend de la commande (valeur du premier argument).\nLe dernier paramètre `size` est la taille de la structure passée en deuxième\nargument.\n\nLes programmes eBPF sont événementiels, c'est à dire que leur exécution est\ndéclenchée en réponse à des actions ou appels de fonctions internes du kernel.\nAfin de conserver des données entre les différentes exécutions du programme, \nmais aussi afin d'échanger des informations entre le programme BPF qui tourne \ndans l'espace du noyau et l'espace utilisateur, eBPF propose d'utiliser des maps. \nLes autres commandes utilisables avec BPF sont dédiées à la création et à la \nmanipulation de ces maps.\n\nMais avant d'aller plus loin, voyons comme sont chargés les programmes eBPF et\ncomment ils sont reliés aux événements qui nous intéressent.\nPour commencer voyons le détail de la structure qui porte les paramètres de\nl'appel à `BPF_PROG_LOAD` :\n\n```c\nstruct {    /* Used by BPF_PROG_LOAD */ \n        __u32         prog_type; \n        __u32         insn_cnt; \n        __aligned_u64 insns;      /* 'const struct bpf_insn *' */\n        __aligned_u64 license;    /* 'const char *' */ \n        __u32         log_level;  /* verbosity level of verifier */\n        __u32         log_size;   /* size of user buffer */ \n        __aligned_u64 log_buf;    /* user supplied 'char *' \n                                     buffer */\n        [...]\n    };\n```\n\n- `prog_type`, permet d'indiquer le type de programme et par quel type\n  d'événement il sera déclenché. Par exemple, pour attacher un programme\n  à l'exécution d'une fonction on utilisera : `BPF_PROG_TYPE_KPROBE`.\n- `insn_cnt` indique le nombre d'instructions du programme\n- `ìnsns` pointe vers la liste des instructions\n- `license` indique la license du programme\n- les 3 attributs suivants (`log_level`, `log_size` et `log_buf`) permettent\n  d'obtenir des informations sur le chargement du programme et le résultat du\n  verifier.\n\nÀ moins, que vous souhaitiez directement écrire le bytecode de votre programme,\nil sera préférable d'utiliser [LLVM](https://llvm.org/) afin de transformer le\ncode C en bytecode bpf. Vous utiliserez alors une commande du type :\n`clang -O2 -emit-llvm -c bpf.c -o - | llc -march=bpf -filetype=obj -o bpf.o`\n\nUne fois la structure correctement alimentée et l'appel système effectué, le\nnoyau prendra en charge votre programme qui subira encore quelques\nmanipulations/transformations :\n- dans un premier temps, le verifier va s'assurer que le programme :\n  - ne comporte pas plus d'instructions que la limite (4096 en Linux 4.14)\n  - est un [Diagramme orienté acyclique](https://fr.wikipedia.org/wiki/Graphe_orient%C3%A9_acyclique).\n    C'est à dire, qu'il ne comporte pas de boucles.\n  - accède uniquement à des zones mémoires identifiées\n  - ...\n- ensuite, avant sa première exécution, le programme sera transformé de\n  bytecode eBPF vers le code natif de la plate-forme pour les [architectures\n  supportées](https://www.kernel.org/doc/Documentation/features/core/eBPF-JIT/arch-support.txt)\n\n### BCC : BPF Compiler Collection\n\nTout cela peut sembler un peu compliqué à mettre en oeuvre. Heureusement, il\nexiste un outil qui simplifie grandement l'utilisation d'eBPF : \n[BPF Compiler Collection](https://github.com/iovisor/bcc).\nCe projet propose notamment un frontend python que nous allons utiliser pour\nmettre en oeuvre quelques exemples de programmes eBPF.\n\nPour commencer, assurez-vous d'avoir une machine linux avec un kernel récent \n( =\u003e4.15). Vous pouvez également utiliser [vagrant](https://www.vagrantup.com/)\navec le\n[Vagrantfile](https://github.com/pyaillet/ebpf-discovery/blob/master/Vagrantfile)\ndisponible sur le \n[repository github](https://github.com/pyaillet/ebpf-discovery) contenant les \nexemples de cet article.\n\nEnsuite installez les dépendances nécessaires (cette étape n'est pas nécessaire\nsi vous utilisez vagrant) :\n```shell\n$ apt update\n$ apt install -y python python-pip bpfcc-tools\n```\n\nPour tester avec un cas simple créez un fichier `first_trace.py` :\n```python\n#!/usr/bin/env python\n\nimport os\nfrom bcc import BPF\n\nprint('Launching in background, pid: ', os.getpid())\n\n# This may not work for 4.17 on x64, you need replace kprobe__sys_clone with kprobe____x64_sys_clone\nBPF(text='''\nint kprobe__sys_clone(void *ctx) {\n  bpf_trace_printk(\"Hello, eBPF!\\\\n\");\n  return 0;\n}\n''').trace_print()\n```\n\nCe script python va créer et un charger un programme eBPF à partir du code\nsource passé en paramètre.\nCe programme sera attaché au syscall clone qui est utilisé dès que l'on\nsouhaite créer un nouveau processus.\nLancez ce script en arrière plan avec la commande :\n`sudo ./first_trace.py \u0026`\n\nIl est nécessaire de le lancer en tant que root afin de pouvoir utiliser\nl'appel système `bpf`.\n\nVous pouvez éventuellement déjà voir des messages apparaître dès qu'un nouveau\nprocessus est créé.\nVous pouvez également lancer le script ci-dessous qui créera un nouveau\nprocessus toutes les 3 secondes. Ce nouveau processus affiche un message et\ns'arrête.\n\n```python\n#!/usr/bin/env python\n\nimport os\nimport time\n\ndef child():\n    print('New child ', os.getpid())\n    os._exit(0)\n\ndef parent():\n    while True:\n        newpid = os.fork()\n        if newpid == 0:\n            child()\n        else:\n            time.sleep(3)\n            os.waitpid(newpid, 0)\n\n\nparent()\n```\n\nUne fois votre test effectué, lancez `sudo kill \u003cpid\u003e`, où vous remplacerez pid\npar l'identifiant du processus lancé en arrière plan qui s'est affiché après\nson lancement.\n\n## Cas d'utilisation\n\nLa technologie eBPF est en plein essor, le fait de pouvoir exécuter du code en\nmode kernel intéresse beaucoup, d'autant plus qu'avec eBPF, il n'est pas\nnécessaire de recompiler le noyau ou d'être spécialiste du développement de\nmodules pour pouvoir le faire.\nAinsi, le projet est utilisé pour :\n\n- De la capture d'événements du kernel, pour\n  - des mesures de performance\n  - du tracing\n- Du filtrage réseau :\n  - haute-performance (anti-DDOS, ...)\n  - avancé et dépendant du contexte\n\n## Conclusion\n\nJ'espère que ce petit tour d'horizon vous a donné envie d'aller plus loin.\nSi c'est le cas, n'hésitez pas à consulter les références que j'ai consultées\npour le rédiger.\nDans un prochain article nous aborderons [Cilium](https://cilium.io/) qui\nutilise cette technologie pour proposer une solution réseau multi-facette dans\nle contexte des conteneurs et notamment Kubernetes.\n\n## Références\n\n- Historique :\n  - Papier original par Steven McCanne et Van Jacobson : http://www.tcpdump.org/papers/bpf-usenix93.pdf \n    et https://www.usenix.org/legacy/publications/library/proceedings/sd93/mccanne.pdf\n  - BPF - in-kernel virtual machine : http://vger.kernel.org/netconf2015Starovoitov-bpf_collabsummit_2015feb20.pdf\n\n- Articles :\n  - What can BPF do for you ? : https://events.static.linuxfound.org/sites/events/files/slides/iovisor-lc-bof-2016.pdf\n  - Awesome eBPF : https://github.com/zoidbergwill/awesome-ebpf\n  - How I ended up writing eBPF : https://bolinfest.github.io/opensnoop-native\n  - eBPF, past, present and future : https://ferrisellis.com/content/ebpf_past_present_future/\n  - eBPF, syscalls and map types : https://ferrisellis.com/content/ebpf_syscall_and_maps/\n\n- Actualité :\n  - https://thenewstack.io/linux-technology-for-the-new-year-ebpf/\n\n- Documentation :\n  - https://en.wikipedia.org/wiki/Berkeley_Packet_Filter\n  - Documentation officielle BPF : https://www.kernel.org/doc/html/latest/bpf/index.html\n  - BPF and XDP Reference Guide : https://cilium.readthedocs.io/en/latest/bpf/\n  - Verifier : https://blogs.oracle.com/linux/notes-on-bpf-5\n\n- Tracing :\n  - http://www.linuxembedded.fr/2019/03/les-secrets-du-traceur-ebpf/\n  - Java Flame graphs : https://www.youtube.com/watch?v=saCGp-T6saQ\n  - Jérémie Lagarde DevoxxFr : https://www.youtube.com/watch?v=rdrnHrQGQlw\n  - Liz Rice : https://www.youtube.com/watch?v=4SiWL5tULnQ\n\n- Network :\n  - XDP : Netronome - https://github.com/Netronome/bpf-samples\n  - Cloudflare : https://blog.cloudflare.com/epbf_sockets_hop_distance/\n  - Facebook : http://vger.kernel.org/lpc_net2018_talks/ebpf-firewall-LPC.pdf\n  - Cilium : https://cilium.io/\n  - Calico : https://www.projectcalico.org/tigera-adds-ebpf-support-to-calico/\n  - Tcpdump : https://medium.com/@cjoudrey/capturing-http-packets-the-hard-way-b9c799bfb6\n  - Toward a faster Iptables in eBPF : https://webthesis.biblio.polito.it/8475/1/tesi.pdf\n  - Toward an eBPF-based clone of iptables : \n    - Slides : https://www.astrid-project.eu/images/Toward%20an%20eBPF-based%20clone%20of%20iptables.pdf\n    - Article complet : https://sebymiano.github.io/documents/21-Securing_Linux_with_a_Faster_and_Scalable_Iptables.pdf\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyaillet%2Febpf-discovery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpyaillet%2Febpf-discovery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyaillet%2Febpf-discovery/lists"}