.\" -*- coding: UTF-8 -*- .\" Copyright (C) 2015 Alexei Starovoitov .\" and Copyright (C) 2015 Michael Kerrisk .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH bpf 2 "28 juillet 2023" "Pages du manuel de Linux 6.05.01" .SH NOM bpf \- Lancer une commande sur une mappe ou un programme BPF .SH SYNOPSIS .nf \fB#include \fP .PP \fBint bpf(int \fP\fIcmd\fP\fB, union bpf_attr *\fP\fIattr\fP\fB, unsigned int \fP\fIsize\fP\fB);\fP .fi .SH DESCRIPTION L'appel système \fBbpf\fP() effectue une série d'opérations liées aux Berkeley Packet Filters étendus («\ filtres de paquets Berkeley\ »). BPF étendu (ou eBPF) est identique au BPF «\ classique\ » originel (cBPF) utilisé pour filtrer les paquets réseau. Pour les programmes tant cBPF qu’eBPF, le noyau analyse de manière statique les programmes avant de les charger, afin de garantir qu'ils ne puissent pas mettre en danger le système en cours d’exécution. .PP .\" See 'enum bpf_func_id' in include/uapi/linux/bpf.h .\" eBPF étend cBPF de plusieurs manières, notamment par la possibilité d'appeler un ensemble fixé de fonctions d'aide du noyau (à l’aide de l'extension d’opcode \fBBPF_CALL\fP fournie par eBPF) et d'accéder aux structures de données partagées telles que les mappes eBPF. .SS "Conception/architecture de BPF étendu" Les mappes eBPF sont des structures de données génériques pour stocker différents types de données. Les types de données sont généralement traités comme des blobs binaires, donc l'utilisateur indique seulement la taille de la clé et celle de la valeur au moment de la création de la mappe. En d'autres termes, la clé/valeur d'une mappe donnée peut avoir une structure arbitraire. .PP Un processus utilisateur peut créer plusieurs mappes (dont les paires clé/valeur sont des octets de données opaques) et y accéder par les descripteurs de fichier. Différents programmes eBPF peuvent accéder aux mêmes mappes en parallèle. Il appartient au processus utilisateur et au programme eBPF de décider ce qu'ils stockent dans leurs mappes. .PP .\" Defined by the kernel constant MAX_TAIL_CALL_CNT in include/linux/bpf.h Il existe un type de mappe spécial appelé un tableau de programmes («\ program array\ »). Ce type de mappe stocke des descripteurs de fichiers qui renvoient à d'autres programmes eBPF. Quand une recherche est effectuée sur la mappe, le flux du programme est redirigé directement au début d'un autre programme eBPF et il ne renvoie rien au programme appelant. Le niveau de redirections est de 32 pour éviter de créer des boucles infinies. Au moment de l'exécution, les descripteurs de fichier du programme stockés dans la mappe peuvent être modifiés, donc la fonctionnalité de programme peut être modifiée sur la base d'exigences spécifiques. Tous les programmes auxquels renvoie une mappe tableau de programmes (program\-array) doivent avoir été précédemment chargés dans le noyau avec \fBbpf\fP(). Si une recherche de mappe échoue, le programme en cours poursuit son exécution. Voir \fBBPF_MAP_TYPE_PROG_ARRAY\fP ci\-dessous pour des détails. .PP Généralement, les programmes eBPF sont chargés par le processus de l'utilisateur et déchargés automatiquement quand le processus se termine. Dans certains cas, par exemple \fBtc\-bpf\fP(8), le programme restera en vie dans le noyau même après que le processus qui l'a chargé est fini. Dans ce cas, le sous\-système \fBtc\fP garde une référence au programme eBPF après que le descripteur de fichier est fermé par le programme de l'espace utilisateur. Ainsi, la survie d'un programme spécifique dans le noyau dépend de la manière dont il a été rattaché à un sous\-système donné du noyau après qu'il a été chargé par \fBbpf\fP(). .PP Chaque programme eBPF est un ensemble d'instructions qu'on peut exécuter en sécurité jusqu'à leur fin. Un vérificateur interne au noyau détermine de manière statique ce que le programme eBPF interrompt et s'il peut être exécuté en toute sécurité. Pendant la vérification, le noyau ajoute un numéro de référence de manière incrémentale pour chacune des mappes utilisées par le programme eBPF, si bien que les mappes qui y sont rattachées ne peuvent pas être supprimées avant que le programme soit déchargé. .PP Les programmes eBPF peuvent être rattachés à différents événements. Ces événements peuvent être l'arrivée de paquets réseaux, le traçage d'événements, la classification d'événements en disciplines de files d'attente réseau (pour les programmes eBPF rattachés à un classificateur \fBtc\fP(8)), et d'autres types qui pourront être ajoutés dans le futur. Un nouvel événement provoque l'exécution d'un programme eBPF, qui peut stocker des informations sur l’évènement dans des mappes eBPF. Par\-delà les données stockées, les programmes eBPF peuvent appeler un ensemble fixé de fonctions d'aide internes au noyau. .PP Un même programme eBPF peut être rattaché à plusieurs événements (évt) et divers programmes eBPF peuvent accéder à la même mappe\ : .PP .in +4n .EX traçage traçage traçage paquet paquet paquet évt A évt B évt C sur eth0 sur eth1 sur eth2 | | | | | \[ha] | | | | v | \-\-> traçage <\-\- traçage socket tc ingress tc egress prog_1 prog_2 prog_3 classifieur action | | | | prog_4 prog_5 |\-\-\- \-\-\-\-\-| |\-\-\-\-\-\-| mappe_3 | | mappe_1 mappe_2 \-\-| mappe_4 |\-\- .EE .in .\" .SS Arguments L'opération à effectuer par l'appel système \fBbpf\fP() est déterminée par le paramètre \fIcmd\fP. Chaque opération prend un paramètre, fourni par \fIattr\fP, qui est un pointeur vers une union de type \fIbpf_attr\fP (voir ci\-dessous). Les champs inutilisés et de remplissage doivent être mis à zéro avant l'appel. Le paramètre \fIsize\fP est la taille de l'union vers laquelle pointe \fIattr\fP. .PP La valeur fournie dans \fIcmd\fP est une parmi\ : .TP \fBBPF_MAP_CREATE\fP Créer une mappe et renvoyer un descripteur de fichier qui s'y rapporte. Le drapeau de descripteur de fichier \fIclose\-on\-exec\fP (voir \fBfcntl\fP(2)) est automatiquement activé pour le nouveau descripteur de fichier. .TP \fBBPF_MAP_LOOKUP_ELEM\fP Chercher un élément par clé dans une mappe spécifiée et renvoyer sa valeur. .TP \fBBPF_MAP_UPDATE_ELEM\fP Créer ou mettre à jour un élément (paire clé/valeur) dans une mappe spécifiée. .TP \fBBPF_MAP_DELETE_ELEM\fP Chercher et effacer un élément par clé dans une mappe spécifiée. .TP \fBBPF_MAP_GET_NEXT_KEY\fP Chercher un élément par clé dans une mappe spécifiée et renvoyer la clé de l'élément suivant. .TP \fBBPF_PROG_LOAD\fP Vérifier et charger un programme eBPF, en renvoyant un nouveau descripteur de fichier associé au programme. Le drapeau de descripteur de fichier \fIclose\-on\-exec\fP (voir \fBfcntl\fP(2)) est activé automatiquement pour le nouveau descripteur de fichier. .IP L'union \fIbpf_attr\fP consiste dans diverses structures anonymes utilisées par différentes commandes \fBbpf\fP()\ : .PP .in +4n .EX .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 union bpf_attr { struct { /* Utilisé par BPF_MAP_CREATE */ __u32 map_type; __u32 key_size; /* taille de la clé en octets */ __u32 value_size; /* taille de la valeur en octets */ __u32 max_entries; /* nombre maximal d'entrées dans une mappe */ }; \& struct { /* Utilisé par les commandes BPF_MAP_*_ELEM et BPF_MAP_GET_NEXT_KEY */ __u32 map_fd; __aligned_u64 key; union { __aligned_u64 value; __aligned_u64 next_key; }; __u64 flags; }; \& struct { /* Utilisé par BPF_PROG_LOAD */ __u32 prog_type; __u32 insn_cnt; __aligned_u64 insns; /* \[aq]const struct bpf_insn *\[aq] */ __aligned_u64 license; /* \[aq]const char *\[aq] */ __u32 log_level; /* niveau de bavardage du vérificateur */ __u32 log_size; /* taille du tampon utilisateur */ __aligned_u64 log_buf; /* l'utilisateur a fourni \[aq]char *\[aq] de tampon */ __u32 kern_version; /* vérifier quand prog_type=kprobe (depuis Linux 4.1) */ }; } __attribute__((aligned(8))); .EE .in .\" .SS "mappes eBPF" Les mappes sont des structures de données génériques pour stocker différents types de données. Elles permettent de partager des données entre des programmes eBPF du noyau, mais aussi entre les applications du noyau et de l'espace utilisateur. .PP Chaque type de mappe a les attributs suivants\ : .IP \- 3 type .IP \- nombre maximal d'éléments .IP \- taille de la clé en octets .IP \- valeur de la clé en octets .PP Les fonctions enveloppe suivantes montrent la manière dont diverses commandes \fBbpf\fP() peuvent être utilisées pour accéder aux mappes. Les fonctions utilisent le paramètre \fIcmd\fP pour appeler différentes opérations. .TP \fBBPF_MAP_CREATE\fP La commande \fBBPF_MAP_CREATE\fP crée une nouvelle mappe, renvoyant un nouveau descripteur de fichier qui s'y rapporte. .IP .in +4n .EX int bpf_create_map(enum bpf_map_type map_type, unsigned int key_size, unsigned int value_size, unsigned int max_entries) { union bpf_attr attr = { .map_type = map_type, .key_size = key_size, .value_size = value_size, .max_entries = max_entries }; \& return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } .EE .in .IP La nouvelle mappe possède le type indiqué avec \fImap_type\fP et les attributs indiqués dans \fIkey_size\fP, \fIvalue_size\fP et \fImax_entries\fP. En cas de succès, cette opération renvoie un descripteur de fichier. En cas d'erreur, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné sur \fBEINVAL\fP, \fBEPERM\fP ou \fBENOMEM\fP. .IP Les attributs \fIkey_size\fP et \fIvalue_size\fP seront utilisés par le vérificateur lors du chargement du programme pour vérifier que le programme appelle les fonctions d'aide \fBbpf_map_*_elem\fP() avec une \fIkey\fP correctement initialisée et pour vérifier que le programme n'accède pas à une \fIvalue\fP de l'élément de la mappe au\-delà de la \fIvalue_size\fP indiquée. Par exemple, quand une mappe est créée avec \fIkey_size\fP de \fB8\fP et que le programme eBPF appelle un .IP .in +4n .EX bpf_map_lookup_elem(map_fd, fp \- 4) .EE .in .IP le programme sera rejeté, puisque la fonction d'aide du noyau .IP .in +4n .EX bpf_map_lookup_elem(map_fd, void *key) .EE .in .IP s'attend à lire 8\ octets à l'endroit où pointe \fIkey\fP, mais l'adresse de départ \fIfp\ \-\ 4\fP (où \fIfp\fP est le haut de la pile) crée un accès de la pile hors limites. .IP De même, lorsqu'une mappe est créée avec une \fIvalue_size\fP de \fB1\fP et que le programme eBPF contient .IP .in +4n .EX value = bpf_map_lookup_elem(...); *(u32 *) value = 1; .EE .in .IP le programme sera rejeté puisqu'il accède au pointeur \fIvalue\fP au\-delà de la la limite \fIvalue_size\fP d’un octet spécifiée. .IP Actuellement, les valeurs suivantes sont prises en charge par \fImap_type\fP\ : .IP .in +4n .EX enum bpf_map_type { BPF_MAP_TYPE_UNSPEC, /* Réserver 0 comme type de mappe non valable */ BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_MAP_TYPE_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_ARRAY, BPF_MAP_TYPE_STACK_TRACE, BPF_MAP_TYPE_CGROUP_ARRAY, BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_ARRAY_OF_MAPS, BPF_MAP_TYPE_HASH_OF_MAPS, BPF_MAP_TYPE_DEVMAP, BPF_MAP_TYPE_SOCKMAP, BPF_MAP_TYPE_CPUMAP, BPF_MAP_TYPE_XSKMAP, BPF_MAP_TYPE_SOCKHASH, BPF_MAP_TYPE_CGROUP_STORAGE, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK, /* Voir /usr/include/linux/bpf.h pour la liste complète. */ }; .EE .in .IP .\" FIXME We need an explanation of why one might choose each of .\" these map implementations \fImap_type\fP sélectionne une des implémentations de mappe disponibles dans le noyau. Pour tous les types de mappe, les programmes eBPF accèdent aux mappes avec les mêmes fonctions d'aide \fBbpf_map_lookup_elem\fP() et \fBbpf_map_update_elem\fP(). Vous trouverez ci\-dessous plus de détails sur les différents types de mappes. .TP \fBBPF_MAP_LOOKUP_ELEM\fP La commande \fBBPF_MAP_LOOKUP_ELEM\fP cherche un élément avec une \fIkey\fP donnée dans la mappe à laquelle se rapporte le descripteur de fichier \fIfd\fP. .IP .in +4n .EX int bpf_lookup_elem(int fd, const void *key, void *value) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), }; \& return bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); } .EE .in .IP Si un élément est trouvé, l'opération renvoie zéro et stocke la valeur de l'élément dans \fIvalue\fP, qui doit pointer vers un tampon de \fIvalue_size\fP octets. .IP Si aucun élément n'est trouvé, l'opération renvoie \fB\-1\fP et \fIerrno\fP est positionné sur \fBENOENT\fP. .TP \fBBPF_MAP_UPDATE_ELEM\fP La commande \fBBPF_MAP_UPDATE_ELEM\fP crée ou met à jour un élément avec une \fIkey/value\fP donnée dans la mappe à laquelle se rapporte le descripteur de fichier \fIfd\fP. .IP .in +4n .EX int bpf_update_elem(int fd, const void *key, const void *value, uint64_t flags) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), .flags = flags, }; \& return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } .EE .in .IP Le paramètre \fIflags\fP devrait être formé d'une des manières suivantes\ : .RS .TP \fBBPF_ANY\fP Créer un nouvel élément ou mettre à jour un élément existant. .TP \fBBPF_NOEXIST\fP Créer un nouvel élément seulement s'il n'existe pas. .TP \fBBPF_EXIST\fP Mettre à jour un élément existant. .RE .IP En cas de succès, l'opération renvoie zéro. En cas d'erreur, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné sur \fBEINVAL\fP, \fBEPERM\fP, \fBENOMEM\fP ou \fBE2BIG\fP. \fBE2BIG\fP indique que le nombre d'éléments de la mappe a atteint la limite \fImax_entries\fP spécifiée au moment de la création de la mappe. \fBEEXIST\fP sera renvoyé si \fIflags\fP spécifie \fBBPF_NOEXIST\fP et si l'élément contenant \fIkey\fP existe déjà sur la mappe. \fBENOENT\fP sera renvoyé si \fIflags\fP spécifie \fBBPF_EXIST\fP et si l'élément contenant \fIkey\fP n'existe pas sur la mappe. .TP \fBBPF_MAP_DELETE_ELEM\fP La commande \fBBPF_MAP_DELETE_ELEM\fP efface l'élément dont la clé est \fIkey\fP sur la mappe à laquelle se rapporte le descripteur de fichier \fIfd\fP. .IP .in +4n .EX int bpf_delete_elem(int fd, const void *key) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), }; \& return bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr)); } .EE .in .IP S'il réussit, cet appel système renvoie \fB0\fP. Si l'élément n'est pas trouvé, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné sur \fBENOENT\fP. .TP \fBBPF_MAP_GET_NEXT_KEY\fP La commande \fBBPF_MAP_GET_NEXT_KEY\fP recherche un élément par \fIkey\fP sur la mappe à laquelle se réfère le descripteur de fichier \fIfd\fP et elle définit le pointeur \fInext_key\fP vers la clé du prochain élément. .IP .in +4n .EX int bpf_get_next_key(int fd, const void *key, void *next_key) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .next_key = ptr_to_u64(next_key), }; \& return bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); } .EE .in .IP Si \fIkey\fP est trouvée, l'opération renvoie zéro et \fInext_key\fP pointe vers la clé de l'élément suivant. Si \fIkey\fP n'est pas trouvée, l'opération renvoie zéro et \fInext_key\fP pointe vers la clé du premier élément. Si \fIkey\fP est le dernier élément, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné sur \fBENOENT\fP. Les autres valeurs possibles de \fIerrno\fP sont \fBENOMEM\fP, \fBEFAULT\fP, \fBEPERM\fP et \fBEINVAL\fP. Cette méthode peut être utilisée pour itérer entre tous les éléments d'une mappe. .TP \fBclose(map_fd)\fP .\" Effacer la mappe à laquelle se réfère le descripteur de fichier \fImap_fd\fP. Quand le programme de l'espace utilisateur ayant créé la mappe se termine, toutes les mappes sont effacées automatiquement (mais voir REMARQUES). .SS "Types de mappe eBPF" Les types de mappe suivants sont pris en charge\ : .TP \fBBPF_MAP_TYPE_HASH\fP .\" commit 0f8e4bd8a1fc8c4185f1630061d0a1f2d197a475 Les mappes table de hachage (hash\-table) présentent les caractéristiques suivantes\ : .RS .IP \- 3 Les mappes sont créées et détruites par les programmes dans l'espace utilisateur. Tant les programmes eBPF que ceux de l'espace utilisateur peuvent effectuer des opérations de recherche, de mise à jour et d'effacement. .IP \- Le noyau se charge d'allouer et de libérer les paires clé/valeur. .IP \- L'aide \fBmap_update_elem\fP() échouera si vous insérez un nouvel élément quand la limite \fImax_entries\fP est atteinte (cela garantit que les programmes eBPF ne peuvent pas épuiser la mémoire). .IP \- \fBmap_update_elem\fP() remplace atomiquement les éléments existants. .RE .IP Les mappes table de hachage (hash\-table) sont optimisées pour accélérer la recherche. .TP \fBBPF_MAP_TYPE_ARRAY\fP .\" commit 28fbcfa08d8ed7c5a50d41a0433aad222835e8e3 Les mappes tableau (array) présentent les caractéristiques suivantes\ : .RS .IP \- 3 Elles sont optimisées pour une recherche plus rapide. À l'avenir, le compilateur du vérificateur/JIT pourrait reconnaître les opérations \fBlookup\fP() qui utilisent une clé constante et l'optimiser dans un pointeur constant. Il est également possible d'optimiser une clé non constante dans un pointeur arithmétique direct, car les pointeurs et les \fIvalue_size\fP sont constants durant toute la vie des programmes eBPF. En d'autres termes, \fBarray_map_lookup_elem\fP() peut être mise «\ inline\ » par le compilateur du vérificateur/JIT tout en préservant l'accès concurrent à cette mappe à partir de l'espace utilisateur. .IP \- Tous les éléments du tableau sont préalloués et initialisés à zéro au moment de l'initialisation .IP \- La clé est un indice de tableau et doit être exactement de quatre octets. .IP \- \fBmap_delete_elem\fP() échoue avec l'erreur \fBEINVAL\fP, car les éléments ne peuvent pas être effacés. .IP \- \fBmap_update_elem\fP() remplace les éléments de manière \fBnon atomique\fP\ ; pour des mises à jour atomiques, vous devriez plutôt utiliser une mappe table de hachage (hash\-table). Toutefois, il existe un cas particulier qui peut aussi être utilisé avec les tableaux\ : le \fB__sync_fetch_and_add()\fP interne atomique peut être utilisé sur des compteurs atomiques en 32 ou 64\ bits. Par exemple, il peut s'appliquer sur la valeur entière si elle représente un compteur unique ou, si une structure contient plusieurs compteurs, il pourrait être utilisé sur des compteurs individuels. Cela est très souvent utile pour agréger et compter des événements. .RE .IP Voici quelques cas d'usage des mappes tableau (array)\ : .RS .IP \- 3 Sous forme de variables eBPF «\ globales\ »\ : un tableau d’un élément dont la clé (indice) est \fB0\fP et dont la valeur est un ensemble de variables «\ globales\ » que les programmes eBPF peuvent utiliser pour conserver leur état entre les événements. .IP \- Agrégation d'événements de traçage dans un ensemble fixe de «\ buckets\ ». .IP \- Comptabilité des événements réseaux, par exemple le nombre de paquets et leur taille. .RE .TP \fBBPF_MAP_TYPE_PROG_ARRAY\fP (depuis Linux 4.2) Une mappe tableau de programmes est un type spécial de mappe tableau dont les valeurs ne contiennent que des descripteurs de fichier qui se rapportent à d'autres programmes eBPF. Ainsi, tant \fIkey_size\fP que \fIvalue_size\fP doivent être d'exactement quatre octets. Cette mappe est utilisée en association avec l'aide \fBbpf_tail_call\fP(). .IP Cela signifie qu'un programme eBPF auquel est rattaché un tableau de programmes (program array) peut appeler à partir du noyau .IP .in +4n .EX void bpf_tail_call(void *context, void *prog_map, unsigned int index); .EE .in .IP et donc remplacer le flux de son propre programme par celui du programme sur la tranche du tableau de programmes donné s'il y en a un. Vous pouvez considérer cela comme un saut de tableau vers un autre programme eBPF. Le programme appelé réutilisera ensuite la même pile. Quand un saut vers un nouveau programme a été fait, il ne renverra plus à l'ancien programme. .IP .\" MAX_TAIL_CALL_CNT Si aucun programme eBPF n'est trouvé sur l'indice donné du tableau de programmes (car la tranche de la mappe ne contient pas de descripteur de fichier de programme valable, la recherche d'indice/clé indiquée dépasse la plage ou la limite de 32\ appels en interne a été dépassée), l'exécution continue avec le programme eBPF actuel. Cela peut être utilisé comme solution de repli pour les cas par défaut. .IP .\" Une mappe tableau de programmes sert, par exemple, à tracer ou mettre en réseau, à gérer des appels système individuels ou des protocoles dans leurs propres sous\-programmes et à utiliser leurs identifiants comme identifiant individuel de mappe. Cette approche peut apporter des gains de performance et permet de dépasser la limite du nombre d'instructions d'un programme eBPF. Dans des environnements dynamiques, un démon de l'espace utilisateur pourrait remplacer de manière atomique des sous\-programmes au moment de leur exécution par de nouvelles versions, pour modifier le comportement général d'un programme, par exemple, si les règles globales changent. .SS "Programmes eBPF" La commande \fBBPF_PROG_LOAD\fP est utilisée pour charger un programme eBPF dans le noyau. Le code de retour de cette commande est un nouveau descripteur de fichier associé à ce programme eBPF. .PP .in +4n .EX char bpf_log_buf[LOG_BUF_SIZE]; \& int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, int insn_cnt, const char *license) { union bpf_attr attr = { .prog_type = type, .insns = ptr_to_u64(insns), .insn_cnt = insn_cnt, .license = ptr_to_u64(license), .log_buf = ptr_to_u64(bpf_log_buf), .log_size = LOG_BUF_SIZE, .log_level = 1, }; \& return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); } .EE .in .PP \fIprog_type\fP est un des types de programme suivants\ : .IP .in +4n .EX enum bpf_prog_type { BPF_PROG_TYPE_UNSPEC, /* Réserver 0 comme type de programme non valable */ BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_KPROBE, BPF_PROG_TYPE_SCHED_CLS, BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_XDP, BPF_PROG_TYPE_PERF_EVENT, BPF_PROG_TYPE_CGROUP_SKB, BPF_PROG_TYPE_CGROUP_SOCK, BPF_PROG_TYPE_LWT_IN, BPF_PROG_TYPE_LWT_OUT, BPF_PROG_TYPE_LWT_XMIT, BPF_PROG_TYPE_SOCK_OPS, BPF_PROG_TYPE_SK_SKB, BPF_PROG_TYPE_CGROUP_DEVICE, BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_RAW_TRACEPOINT, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, /* Voir /usr/include/linux/bpf.h pour la liste complète. */ }; .EE .in .PP Pour plus de détails sur le type de programme eBPF, voir ci\-dessous. .PP Les autres champs de \fIbpf_attr\fP sont définis comme suit\ : .IP \- 3 \fIinsns\fP est un tableau d'instructions \fIstruct bpf_insn\fP. .IP \- \fIinsn_cnt\fP est le nombre d'instructions du programme auquel se rapporte \fIinsns\fP. .IP \- \fIlicense\fP est une chaîne de licence, qui doit être compatible GPL pour appeler les fonctions d'aide marquées comme \fIgpl_only\fP (les règles de licence sont les mêmes que celles pour les modules du noyau, pour que même des licences duales, telles que «\ Dual BSD/GPL\ », puissent être utilisées). .IP \- \fIlog_buf\fP est un pointeur vers un tampon alloué à l’appelant (caller\-allocated) où le vérificateur du noyau peut stocker le journal de sa vérification. Ce journal est une chaîne de plusieurs lignes qui peut être vérifiée par l'auteur du programme pour comprendre la manière par laquelle le vérificateur est arrivé à la conclusion que le programme eBPF n'est pas sûr. Le format de sortie peut changer n'importe quand puisque le vérificateur évolue. .IP \- \fIlog_size\fP dimensionne le tampon vers lequel pointe \fIlog_buf\fP. Si la taille du tampon n'est pas assez grande pour stocker tous les messages du vérificateur, \fB\-1\fP est renvoyé et \fIerrno\fP est positionné sur \fBENOSPC\fP. .IP \- Le niveau de précisions \fIlog_level\fP du vérificateur. Une valeur de zéro signifie que le vérificateur ne génèrera aucun journal\ ; dans ce cas \fIlog_buf\fP doit être un pointeur NULL et \fIlog_size\fP doit valoir zéro. .PP Le fait d'appliquer \fBclose\fP(2) au descripteur de fichier renvoyé par \fBBPF_PROG_LOAD\fP déchargera le programme eBPF (mais voir les REMARQUES). .PP .\" .\" Les mappes sont accessibles à partir des programmes eBPF et elles sont utilisées pour échanger des données entre des programmes eBPF et entre des programmes eBPF et d'autres de l'espace utilisateur. Par exemple, des programmes eBPF peuvent traiter divers événements (comme kprobe, packets) et stocker leurs données dans une mappe, et les programmes de l'espace utilisateur peuvent alors récupérer ces données dans la mappe. Inversement, des programmes de l'espace utilisateur peuvent utiliser une mappe en tant que mécanisme de configuration, la mappe étant peuplée par des valeurs vérifiées par le programme eBPF qui modifie ensuite son comportement à la volée en fonction de ces valeurs. .SS "Types de programme eBPF" .\" .\" FIXME .\" Somewhere in this page we need a general introduction to the .\" bpf_context. For example, how does a BPF program access the .\" context? Le type de programme eBPF (\fIprog_type\fP) détermine le sous\-ensemble de fonctions d'aide du noyau que peut appeler le programme. Le type de programme détermine également le format d'entrée du programme (contexte) –\ le format de \fIstruct bpf_context\fP (qui est le blob de données passé au programme eBPF en tant que premier paramètre). .PP Par exemple, un programme de traçage n'a pas exactement le même sous\-jeu de fonctions d'aide qu'un programme de filtrage de socket (bien qu'ils peuvent en avoir en commun). De même l'entrée (le contexte) d'un programme de traçage est un jeu de valeurs de registre, alors que ce sera un paquet réseau pour le filtrage de socket. .PP Le jeu de fonctions disponibles pour les programmes eBPF d'un type donné pourra augmenter dans le futur. .PP Les types de programmes suivants sont pris en charge\ : .TP \fBBPF_PROG_TYPE_SOCKET_FILTER\fP (depuis Linux 3.19) Actuellement, le jeu de fonctions pour \fBBPF_PROG_TYPE_SOCKET_FILTER\fP est\ : .IP .in +4n .EX bpf_map_lookup_elem(map_fd, void *key) /* rechercher la clé dans une map_fd */ bpf_map_update_elem(map_fd, void *key, void *value) /* mettre à jour la clé/valeur */ bpf_map_delete_elem(map_fd, void *key) /* effacer la clé d'une map_fd */ .EE .in .IP .\" FIXME: We need some text here to explain how the program .\" accesses __sk_buff. .\" See 'struct __sk_buff' and commit 9bac3d6d548e5 .\" .\" Alexei commented: .\" Actually now in case of SOCKET_FILTER, SCHED_CLS, SCHED_ACT .\" the program can now access skb fields. .\" Le paramètre \fIbpf_context\fP est un pointeur vers une \fIstruct __sk_buff\fP. .TP \fBBPF_PROG_TYPE_KPROBE\fP (depuis Linux\ 4.1) .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type .\" .\" FIXME We need text here to describe 'kern_version' [À documenter] .TP \fBBPF_PROG_TYPE_SCHED_CLS\fP (depuis Linux\ 4.1) .\" commit 96be4325f443dbbfeb37d2a157675ac0736531a1 .\" commit e2e9b6541dd4b31848079da80fe2253daaafb549 .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type [À documenter] .TP \fBBPF_PROG_TYPE_SCHED_ACT\fP (depuis Linux 4.1) .\" commit 94caee8c312d96522bcdae88791aaa9ebcd5f22c .\" commit a8cb5f556b567974d75ea29c15181c445c541b1f .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type [À documenter] .SS Événements Une fois qu'un programme est chargé, il peut être rattaché à un événement. Divers sous\-systèmes du noyau ont plusieurs manières de le faire. .PP .\" commit 89aa075832b0da4402acebd698d0411dcc82d03e Depuis Linux 3.19, l'appel suivant rattachera le programme \fIprog_fd\fP au socket \fIsockfd\fP, qui a été précédemment créé par un appel \fBsocket\fP(2)\ : .PP .in +4n .EX setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)); .EE .in .PP .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 Depuis Linux 4.1, l'appel suivant peut être utilisé pour rattacher un programme eBPF auquel se rapporte le descripteur de fichier \fIprog_fd\fP à un descripteur de fichier d'événement \fIperf\fP, \fIevent_fd\fP, créé par un appel précédent à \fBperf_event_open\fP(2)\ : .PP .in +4n .EX ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); .EE .in .\" .\" .SH "VALEUR RENVOYÉE" Pour qu'un appel réussisse, le code de retour dépend de l'opération\ : .TP \fBBPF_MAP_CREATE\fP Le nouveau descripteur de fichier associé à la mappe eBPF. .TP \fBBPF_PROG_LOAD\fP Le nouveau descripteur de fichier associé au programme eBPF. .TP Toutes les autres commandes\ : Zéro. .PP En cas d'erreur, la valeur de retour est \fB\-1\fP et \fIerrno\fP est définie pour préciser l'erreur. .SH ERREURS .TP \fBE2BIG\fP Le programme eBPF est trop grand ou une mappe a atteint la limite \fImax_entries\fP (nombre maximal d'éléments). .TP \fBEACCES\fP Pour \fBBPF_PROG_LOAD\fP, même si toutes les instructions du programme sont valables, le programme a été rejeté car il a été considéré comme non sûr. Cela est possible s'il a eu un accès à une zone de la mémoire interdite ou à une pile ou un registre non initialisé, ou parce que les contraintes de la fonction ne correspondent pas aux types réels, ou qu'il y a eu un accès mémoire non aligné. Dans ce cas, il est recommandé d'appeler \fBbpf\fP() à nouveau, avec \fIlog_level\ =\ 1\fP et d'examiner le \fIlog_buf\fP pour connaître la raison exacte fournie par le vérificateur. .TP \fBEAGAIN\fP Pour \fBBPF_PROG_LOAD\fP, indique que les ressources nécessaires sont bloquées. Cela se produit quand le vérificateur détecte des signaux en attente alors qu'il vérifie la validité du programme bpf. Dans ce cas, appeler à nouveau simplement \fBbpf\fP() avec les mêmes paramètres. .TP \fBEBADF\fP \fIfd\fP n'est pas un descripteur de fichier ouvert. .TP \fBEFAULT\fP Un des pointeurs (\fIkey\fP ou \fIvalue\fP ou \fIlog_buf\fP ou \fIinsns\fP) dépasse l'espace d'adressage accessible. .TP \fBEINVAL\fP La valeur indiquée dans \fIcmd\fP n'est pas reconnue par ce noyau. .TP \fBEINVAL\fP Pour \fBBPF_MAP_CREATE\fP, soit \fImap_type\fP, soit les attributs ne sont pas autorisés. .TP \fBEINVAL\fP Pour des commandes \fBBPF_MAP_*_ELEM\fP, certains champs de \fIunion bpf_attr\fP non utilisés par cette commande n'ont pas été positionnés sur zéro. .TP \fBEINVAL\fP Pour \fBBPF_PROG_LOAD\fP, indique une tentative de charger un programme non valable. Les programmes eBPF peuvent être jugés non valables du fait d'instructions non reconnues, de l'utilisation de champs réservés, de dépassements de plage, de boucles infinies ou d'appels à des fonctions inconnues. .TP \fBENOENT\fP Pour \fBBPF_MAP_LOOKUP_ELEM\fP ou \fBBPF_MAP_DELETE_ELEM\fP, indique qu'un élément avec la \fIkey\fP donnée n'a pas été trouvé. .TP \fBENOMEM\fP Ne peut pas allouer suffisamment de mémoire. .TP \fBEPERM\fP L'appel a été fait sans privilèges suffisants (sans la capacité \fBCAP_SYS_ADMIN\fP). .SH STANDARDS Linux. .SH HISTORIQUE Linux 3.18. .SH NOTES .\" commit 1be7f75d1668d6296b80bf35dcf6762393530afc .\" [Linux 5.6] mtk: The list of available functions is, I think, governed .\" by the check in net/core/filter.c::bpf_base_func_proto(). Avant Linux 4.4, toutes les commandes \fBbpf\fP() exigeaient que l'appelant ait la capacité \fBCAP_SYS_ADMIN\fP. Depuis Linux 4.4 jusqu'à présent, un utilisateur non privilégié peut créer des programmes limités de type \fBBPF_PROG_TYPE_SOCKET_FILTER\fP et mappes associées. Toutefois, ils ne peuvent pas stocker des pointeurs du noyau dans les mappes et ils sont actuellement limités aux fonctions d'aide suivantes\ : .IP \- 3 get_random .PD 0 .IP \- get_smp_processor_id .IP \- tail_call .IP \- ktime_get_ns .PD .PP Un accès sans privilèges peut être bloqué en écrivant la valeur \fB1\fP dans le fichier \fI/proc/sys/kernel/unprivileged_bpf_disabled\fP. .PP Les objets eBPF (les mappes et les programmes) peuvent être partagés entre les processus. Par exemple, après \fBfork\fP(2), l'enfant récupère les descripteurs de fichier qui se rapportent aux mêmes objets eBPF. De plus, les descripteurs de fichier qui se rapportent aux objets eBPF peuvent être transférés à travers des sockets de domaine UNIX. Les descripteurs de fichier qui se rapportent aux objets eBPF peuvent être dupliqués de la manière habituelle, en utilisant \fBdup\fP(2) ou des appels similaires. Un objet eBPF n'est désalloué qu'après que tous les descripteurs de fichier qui se rapportent à l'objet sont fermés. .PP .\" There are also examples for the tc classifier, in the iproute2 .\" project, in examples/bpf Les programmes eBPF peuvent être écrits en C\ restreint compilé en bytecode eBPF (en utilisant le compilateur \fBclang\fP). Diverses fonctionnalités sont absentes de ce C\ restreint, telles que les boucles, les variables globales, les fonctions variadiques, les nombres décimaux et le passage de structures comme paramètres d'une fonction. Vous pouvez trouver des exemples dans les fichiers \fIsamples/bpf/*_kern.c\fP de l'arborescence des sources du noyau. .PP Le noyau contient un compilateur «\ just\-in\-time (JIT)\ » qui traduit du bytecode eBPF en langage machine natif pour de meilleures performances. Avant Linux\ 4.15, le compilateur JIT est désactivé par défaut, mais ce qu'il fait peut être contrôlé en écrivant une des chaînes suivantes d’entiers dans le fichier \fI/proc/sys/net/core/bpf_jit_enable\fP\ : .TP \fB0\fP Désactiver la compilation JIT (par défaut). .TP \fB1\fP Compilation normale. .TP \fB2\fP Mode débogage. Les opcodes générés sont écrits en hexadécimal dans le journal du noyau. Ces opcodes peuvent alors être désassemblés avec le programme \fItools/net/bpf_jit_disasm.c\fP fourni dans l'arborescence des sources du noyau. .PP .\" commit 290af86629b25ffd1ed6232c4e9107da031705cb Depuis Linux 4.15, le noyau peut être configuré avec l'option \fBCONFIG_BPF_JIT_ALWAYS_ON\fP. Dans ce cas, le compilateur JIT est toujours activé et \fIbpf_jit_enable\fP est positionné sur \fB1\fP et immuable (cette option de configuration du noyau est fournie pour contrer une des attaques Spectre contre l'interpréteur BPF). .PP .\" Last reviewed in Linux 4.18-rc by grepping for BPF_ALU64 in arch/ .\" and by checking the documentation for bpf_jit_enable in .\" Documentation/sysctl/net.txt Le compilateur JIT pour eBPF est actuellement disponible pour les architectures suivantes\ : .IP \- 3 .\" commit 0a14842f5a3c0e88a1e59fac5c3025db39721f74 x86\-64 (depuis Linux 3.18\ ; cBPF depuis Linux 3.0)\ ; .PD 0 .IP \- .\" commit ddecdfcea0ae891f782ae853771c867ab51024c2 ARM32 (depuis Linux 3.18\ ; cBPF depuis Linux 3.4)\ ; .IP \- .\" commit 2809a2087cc44b55e4377d7b9be3f7f5d2569091 SPARC 32 (depuis Linux 3.18\ ; cBPF depuis Linux 3.5)\ ; .IP \- .\" commit e54bcde3d69d40023ae77727213d14f920eb264a ARM\-64 (depuis Linux 3.18)\ ;; .IP \- .\" commit c10302efe569bfd646b4c22df29577a4595b4580 s390 (depuis Linux 4.1\ ; cBPF depuis Linux 3.7)\ ; .IP \- .\" commit 0ca87f05ba8bdc6791c14878464efc901ad71e99 .\" commit 156d0e290e969caba25f1851c52417c14d141b24 PowerPC 64 (depuis Linux 4.8\ ; cBPF depuis Linux 3.1)\ ; .IP \- .\" commit 7a12b5031c6b947cc13918237ae652b536243b76 SPARC 64 (depuis Linux 4.12)\ ; .IP \- .\" commit 03f5781be2c7b7e728d724ac70ba10799cc710d7 x86\-32 (depuis Linux 4.18)\ ; .IP \- .\" commit c6610de353da5ca6eee5b8960e838a87a90ead0c .\" commit f381bf6d82f032b7410185b35d000ea370ac706b MIPS 64 (depuis Linux 4.18\ ; cBPF depuis Linux 3.16)\ ; .IP \- .\" commit 2353ecc6f91fd15b893fa01bf85a1c7a823ee4f2 riscv (depuis Linux 5.1). .PD .SH EXEMPLES .\" [[FIXME]] SRC BEGIN (bpf.c) .EX .\" == atomic64_add /* Exemple de bpf+sockets : * 1. Créer une mappe tableau de 256 éléments * 2. Charger le programme qui compte le nombre de paquets reçus * r0 = skb\->data[ETH_HLEN + offsetof(struct iphdr, protocol)] * map[r0]++ * 3. Rattacher prog_fd au socket brut à l’aide de setsockopt() * 4. Afficher le nombre de paquets TCP/UDP reçus toutes les secondes */ int main(int argc, char *argv[]) { int sock, map_fd, prog_fd, key; long long value = 0, tcp_cnt, udp_cnt; \& map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 256); if (map_fd < 0) { printf("impossible de créer la projection \[aq]%s\[aq]\en", strerror(errno)); /* probablement non lancé en tant que root */ return 1; } struct bpf_insn prog[] = { BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* r6 = r1 */ BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol)), /* r0 = ip\->proto */ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, \-4), /* *(u32 *)(fp \- 4) = r0 */ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, \-4), /* r2 = r2 \- 4 */ BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* r1 = map_fd */ BPF_CALL_FUNC(BPF_FUNC_map_lookup_elem), /* r0 = map_lookup(r1, r2) */ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* if (r0 == 0) goto pc+2 */ BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ BPF_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* lock *(u64 *) r0 += r1 */ BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ BPF_EXIT_INSN(), /* return r0 */ }; \& prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, sizeof(prog) / sizeof(prog[0]), "GPL"); \& sock = open_raw_sock("lo"); \& assert(setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)) == 0); \& for (;;) { key = IPPROTO_TCP; assert(bpf_lookup_elem(map_fd, &key, &tcp_cnt) == 0); key = IPPROTO_UDP; assert(bpf_lookup_elem(map_fd, &key, &udp_cnt) == 0); printf("TCP %lld UDP %lld packets\en", tcp_cnt, udp_cnt); sleep(1); } \& return 0; } .EE .\" SRC END .PP Vous pouvez trouvez du code complet opérationnel dans le répertoire \fIsamples/bpf\fP de l'arborescence des sources du noyau. .SH "VOIR AUSSI" \fBseccomp\fP(2), \fBbpf\-helpers\fP(7), \fBsocket\fP(7), \fBtc\fP(8), \fBtc\-bpf\fP(8) .PP Les BPF classique et étendu sont expliqués dans le fichier \fIDocumentation/networking/filter.txt\fP des sources du noyau. .PP .SH TRADUCTION La traduction française de cette page de manuel a été créée par Christophe Blaess , Stéphan Rafin , Thierry Vignaud , François Micaux, Alain Portal , Jean-Philippe Guérard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas François , Florentin Duneau , Simon Paillard , Denis Barbier , David Prévot , Cédric Boutillier , Frédéric Hantrais et Jean-Philippe MENGUAL . .PP Cette traduction est une documentation libre ; veuillez vous reporter à la .UR https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3 .UE concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE. .PP Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à .MT debian-l10n-french@lists.debian.org .ME .