Provided by: manpages-fr-dev_4.27.0-1_all bug

NOM

       bpf - Lancer une commande sur une mappe ou un programme BPF

SYNOPSIS

       #include <linux/bpf.h>

       int bpf(int cmd, union bpf_attr *attr, unsigned int size);

DESCRIPTION

       L'appel  système  bpf()  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.

       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 BPF_CALL fournie par eBPF) et  d'accéder  aux
       structures de données partagées telles que les mappes eBPF.

   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.

       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.

       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 bpf(). Si une recherche de
       mappe échoue, le programme en cours poursuit son exécution. Voir BPF_MAP_TYPE_PROG_ARRAY ci-dessous  pour
       des détails.

       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  tc-bpf(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 tc 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 bpf().

       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é.

       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 tc(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.

       Un  même programme eBPF peut être rattaché à plusieurs événements (évt) et divers programmes eBPF peuvent
       accéder à la même mappe :

           traçage     traçage    traçage    paquet       paquet      paquet
            évt A       évt B      évt C    sur eth0     sur eth1    sur eth2
             |             |         |          |           |          ^
             |             |         |          |           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 |--

   Argument
       L'opération à effectuer par l'appel système bpf() est déterminée par le paramètre cmd.  Chaque  opération
       prend  un  paramètre,  fourni  par  attr,  qui  est  un  pointeur  vers  une union de type bpf_attr (voir
       ci-dessous). Les champs inutilisés et de remplissage doivent être mis à zéro avant l'appel. Le  paramètre
       size est la taille de l'union vers laquelle pointe attr.

       La valeur fournie dans cmd est une parmi :

       BPF_MAP_CREATE
              Créer  une mappe et renvoyer un descripteur de fichier qui s'y rapporte. Le drapeau de descripteur
              de fichier close-on-exec (voir fcntl(2)) est automatiquement activé pour le nouveau descripteur de
              fichier.

       BPF_MAP_LOOKUP_ELEM
              Chercher un élément par clé dans une mappe spécifiée et renvoyer sa valeur.

       BPF_MAP_UPDATE_ELEM
              Créer ou mettre à jour un élément (paire clé/valeur) dans une mappe spécifiée.

       BPF_MAP_DELETE_ELEM
              Chercher et effacer un élément par clé dans une mappe spécifiée.

       BPF_MAP_GET_NEXT_KEY
              Chercher un élément par clé dans une mappe spécifiée et renvoyer la clé de l'élément suivant.

       BPF_PROG_LOAD
              Vérifier et charger un programme eBPF, en renvoyant un nouveau descripteur de fichier  associé  au
              programme.  Le  drapeau  de  descripteur  de  fichier  close-on-exec  (voir  fcntl(2))  est activé
              automatiquement pour le nouveau descripteur de fichier.

              L'union bpf_attr consiste dans diverses structures anonymes utilisées  par  différentes  commandes
              bpf() :

           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;      /* 'const struct bpf_insn *' */
                   __aligned_u64 license;    /* 'const char *' */
                   __u32         log_level;  /* niveau de bavardage du vérificateur */
                   __u32         log_size;   /* taille du tampon utilisateur */
                   __aligned_u64 log_buf;    /* l'utilisateur a fourni 'char *'
                                                de tampon */
                   __u32         kern_version;
                                             /* vérifier quand prog_type=kprobe
                                                (depuis Linux 4.1) */
               };
           } __attribute__((aligned(8)));

   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.

       Chaque type de mappe a les attributs suivants :

       -  type

       -  nombre maximal d'éléments

       -  taille de la clé en octets

       -  valeur de la clé en octets

       Les  fonctions  enveloppe  suivantes  montrent  la  manière  dont  diverses  commandes bpf() peuvent être
       utilisées pour accéder aux mappes. Les fonctions utilisent le  paramètre  cmd  pour  appeler  différentes
       opérations.

       BPF_MAP_CREATE
              La  commande  BPF_MAP_CREATE  crée une nouvelle mappe, renvoyant un nouveau descripteur de fichier
              qui s'y rapporte.

                  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));
                  }

              La nouvelle mappe possède le type indiqué avec map_type et les attributs indiqués  dans  key_size,
              value_size et max_entries. En cas de succès, cette opération renvoie un descripteur de fichier. En
              cas d'erreur, -1 est renvoyé et errno est positionné sur EINVAL, EPERM ou ENOMEM.

              Les  attributs  key_size  et  value_size seront utilisés par le vérificateur lors du chargement du
              programme pour vérifier que le programme appelle les fonctions d'aide  bpf_map_*_elem()  avec  une
              key  correctement  initialisée  et  pour  vérifier  que  le  programme n'accède pas à une value de
              l'élément de la mappe au-delà de la value_size indiquée. Par exemple, quand une  mappe  est  créée
              avec key_size de 8 et que le programme eBPF appelle un

                  bpf_map_lookup_elem(map_fd, fp - 4)

              le programme sera rejeté, puisque la fonction d'aide du noyau

                  bpf_map_lookup_elem(map_fd, void *key)

              s'attend  à lire 8 octets à l'endroit où pointe key, mais l'adresse de départ fp - 4 (où fp est le
              haut de la pile) crée un accès de la pile hors limites.

              De même, lorsqu'une mappe est créée avec une value_size de 1 et que le programme eBPF contient

                  value = bpf_map_lookup_elem(...);
                  *(u32 *) value = 1;

              le programme sera rejeté puisqu'il accède au pointeur value au-delà de  la  la  limite  value_size
              d’un octet spécifiée.

              Actuellement, les valeurs suivantes sont prises en charge par map_type :

                  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. */
                  };

              map_type  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
              bpf_map_lookup_elem()  et bpf_map_update_elem(). Vous trouverez ci-dessous plus de détails sur les
              différents types de mappes.

       BPF_MAP_LOOKUP_ELEM
              La commande BPF_MAP_LOOKUP_ELEM cherche un élément avec une key donnée dans la mappe à laquelle se
              rapporte le descripteur de fichier fd.

                  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));
                  }

              Si un élément est trouvé, l'opération renvoie zéro et stocke la valeur de  l'élément  dans  value,
              qui doit pointer vers un tampon de value_size octets.

              Si aucun élément n'est trouvé, l'opération renvoie -1 et errno est positionné sur ENOENT.

       BPF_MAP_UPDATE_ELEM
              La  commande  BPF_MAP_UPDATE_ELEM  crée ou met à jour un élément avec une key/value donnée dans la
              mappe à laquelle se rapporte le descripteur de fichier fd.

                  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));
                  }

              Le paramètre flags devrait être formé d'une des manières suivantes :

              BPF_ANY
                     Créer un nouvel élément ou mettre à jour un élément existant.

              BPF_NOEXIST
                     Créer un nouvel élément seulement s'il n'existe pas.

              BPF_EXIST
                     Mettre à jour un élément existant.

              En cas de succès, l'opération renvoie  zéro.  En  cas  d'erreur,  -1  est  renvoyé  et  errno  est
              positionné  sur EINVAL, EPERM, ENOMEM ou E2BIG. E2BIG indique que le nombre d'éléments de la mappe
              a atteint la limite max_entries spécifiée au moment de  la  création  de  la  mappe.  EEXIST  sera
              renvoyé  si  flags  spécifie  BPF_NOEXIST  et si l'élément contenant key existe déjà sur la mappe.
              ENOENT sera renvoyé si flags spécifie BPF_EXIST et si l'élément contenant key n'existe pas sur  la
              mappe.

       BPF_MAP_DELETE_ELEM
              La  commande  BPF_MAP_DELETE_ELEM  efface l'élément dont la clé est key sur la mappe à laquelle se
              rapporte le descripteur de fichier fd.

                  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));
                  }

              S'il réussit, cet appel système renvoie 0. Si l'élément n'est pas trouvé, -1 est renvoyé et  errno
              est positionné sur ENOENT.

       BPF_MAP_GET_NEXT_KEY
              La commande BPF_MAP_GET_NEXT_KEY recherche un élément par key sur la mappe à laquelle se réfère le
              descripteur de fichier fd et elle définit le pointeur next_key vers la clé du prochain élément.

                  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));
                  }

              Si  key est trouvée, l'opération renvoie zéro et next_key pointe vers la clé de l'élément suivant.
              Si key n'est pas trouvée, l'opération renvoie zéro et next_key  pointe  vers  la  clé  du  premier
              élément.  Si  key  est  le dernier élément, -1 est renvoyé et errno est positionné sur ENOENT. Les
              autres valeurs possibles de errno sont ENOMEM, EFAULT, EPERM et EINVAL. Cette  méthode  peut  être
              utilisée pour itérer entre tous les éléments d'une mappe.

       close(map_fd)
              Effacer  la  mappe  à  laquelle  se réfère le descripteur de fichier map_fd. Quand le programme de
              l'espace  utilisateur  ayant  créé  la  mappe  se  termine,  toutes  les  mappes   sont   effacées
              automatiquement (mais voir REMARQUES).

   Types de mappe eBPF
       Les types de mappe suivants sont pris en charge :

       BPF_MAP_TYPE_HASH
              Les mappes table de hachage (hash-table) présentent les caractéristiques suivantes :

              -  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.

              -  Le noyau se charge d'allouer et de libérer les paires clé/valeur.

              -  L'aide map_update_elem() échouera si vous insérez un nouvel élément quand la limite max_entries
                 est atteinte (cela garantit que les programmes eBPF ne peuvent pas épuiser la mémoire).

              -  map_update_elem() remplace atomiquement les éléments existants.

              Les mappes table de hachage (hash-table) sont optimisées pour accélérer la recherche.

       BPF_MAP_TYPE_ARRAY
              Les mappes tableau (array) présentent les caractéristiques suivantes :

              -  Elles  sont  optimisées  pour  une  recherche  plus  rapide.  À  l'avenir,  le  compilateur  du
                 vérificateur/JIT  pourrait  reconnaître les opérations lookup() 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 value_size sont
                 constants durant toute la vie des programmes eBPF. En d'autres termes,  array_map_lookup_elem()
                 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.

              -  Tous  les  éléments  du  tableau  sont  préalloués  et  initialisés  à  zéro   au   moment   de
                 l'initialisation

              -  La clé est un indice de tableau et doit être exactement de quatre octets.

              -  map_delete_elem() échoue avec l'erreur EINVAL, car les éléments ne peuvent pas être effacés.

              -  map_update_elem()  remplace  les  éléments  de  manière  non  atomique  ; 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
                 __sync_fetch_and_add() 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.

              Voici quelques cas d'usage des mappes tableau (array) :

              -  Sous  forme de variables eBPF « globales » : un tableau d’un élément dont la clé (indice) est 0
                 et dont la valeur est un ensemble de variables « globales » que  les  programmes  eBPF  peuvent
                 utiliser pour conserver leur état entre les événements.

              -  Agrégation d'événements de traçage dans un ensemble fixe de « buckets ».

              -  Comptabilité des événements réseaux, par exemple le nombre de paquets et leur taille.

       BPF_MAP_TYPE_PROG_ARRAY (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  key_size que value_size doivent être d'exactement quatre octets. Cette mappe est utilisée en
              association avec l'aide bpf_tail_call().

              Cela signifie qu'un programme eBPF auquel est rattaché un tableau de  programmes  (program  array)
              peut appeler à partir du noyau

                  void bpf_tail_call(void *context, void *prog_map,
                                     unsigned int index);

              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.

              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.

              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.

   Programmes eBPF
       La commande BPF_PROG_LOAD 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.

           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));
           }

       prog_type est un des types de programme suivants :

                  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. */
                  };

       Pour plus de détails sur le type de programme eBPF, voir ci-dessous.

       Les autres champs de bpf_attr sont définis comme suit :

       -  insns est un tableau d'instructions struct bpf_insn.

       -  insn_cnt est le nombre d'instructions du programme auquel se rapporte insns.

       -  license est une chaîne de licence, qui doit être compatible GPL  pour  appeler  les  fonctions  d'aide
          marquées  comme  gpl_only  (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).

       -  log_buf 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.

       -  log_size dimensionne le tampon vers lequel pointe log_buf. Si la taille  du  tampon  n'est  pas  assez
          grande  pour  stocker  tous  les  messages du vérificateur, -1 est renvoyé et errno est positionné sur
          ENOSPC.

       -  Le niveau de précisions log_level du vérificateur. Une valeur de zéro signifie que le vérificateur  ne
          génèrera aucun journal ; dans ce cas log_buf doit être un pointeur NULL et log_size doit valoir zéro.

       Le  fait d'appliquer close(2) au descripteur de fichier renvoyé par BPF_PROG_LOAD déchargera le programme
       eBPF (mais voir les REMARQUES).

       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.

   Types de programme eBPF
       Le  type  de  programme eBPF (prog_type) 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 struct bpf_context (qui est le blob de données passé au programme eBPF en tant que premier
       paramètre).

       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.

       Le jeu de fonctions disponibles pour les programmes eBPF d'un type donné pourra augmenter dans le futur.

       Les types de programmes suivants sont pris en charge :

       BPF_PROG_TYPE_SOCKET_FILTER (depuis Linux 3.19)
              Actuellement, le jeu de fonctions pour BPF_PROG_TYPE_SOCKET_FILTER est :

                  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 */

              Le paramètre bpf_context est un pointeur vers une struct __sk_buff.

       BPF_PROG_TYPE_KPROBE (depuis Linux 4.1)
              [À documenter]

       BPF_PROG_TYPE_SCHED_CLS (depuis Linux 4.1)
              [À documenter]

       BPF_PROG_TYPE_SCHED_ACT (depuis Linux 4.1)
              [À documenter]

   É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.

       Depuis Linux 3.19, l'appel  suivant  rattachera  le  programme  prog_fd  au  socket  sockfd,  qui  a  été
       précédemment créé par un appel socket(2) :

           setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF,
                      &prog_fd, sizeof(prog_fd));

       Depuis  Linux  4.1, l'appel suivant peut être utilisé pour rattacher un programme eBPF auquel se rapporte
       le descripteur de fichier prog_fd à un descripteur de fichier d'événement perf,  event_fd,  créé  par  un
       appel précédent à perf_event_open(2) :

           ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);

VALEUR RENVOYÉE

       Pour qu'un appel réussisse, le code de retour dépend de l'opération :

       BPF_MAP_CREATE
              Le nouveau descripteur de fichier associé à la mappe eBPF.

       BPF_PROG_LOAD
              Le nouveau descripteur de fichier associé au programme eBPF.

       Toutes les autres commandes :
              Zéro.

       En cas d'erreur, la valeur de retour est -1 et errno est définie pour préciser l'erreur.

ERREURS

       E2BIG  Le  programme  eBPF  est  trop  grand ou une mappe a atteint la limite max_entries (nombre maximal
              d'éléments).

       EACCES Pour BPF_PROG_LOAD, 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 bpf() à nouveau, avec log_level = 1 et d'examiner  le  log_buf
              pour connaître la raison exacte fournie par le vérificateur.

       EAGAIN Pour BPF_PROG_LOAD, 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 bpf() avec les mêmes paramètres.

       EBADF  fd n'est pas un descripteur de fichier ouvert

       EFAULT Un des pointeurs (key ou value ou log_buf ou insns) dépasse l'espace d'adressage accessible.

       EINVAL La valeur indiquée dans cmd n'est pas reconnue par ce noyau.

       EINVAL Pour BPF_MAP_CREATE, soit map_type, soit les attributs ne sont pas autorisés.

       EINVAL Pour  des  commandes  BPF_MAP_*_ELEM,  certains  champs  de  union bpf_attr non utilisés par cette
              commande n'ont pas été positionnés sur zéro.

       EINVAL Pour BPF_PROG_LOAD, 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.

       ENOENT Pour  BPF_MAP_LOOKUP_ELEM ou BPF_MAP_DELETE_ELEM, indique qu'un élément avec la key donnée n'a pas
              été trouvé.

       ENOMEM Ne peut pas allouer suffisamment de mémoire.

       EPERM  L'appel a été fait sans privilèges suffisants (sans la capacité CAP_SYS_ADMIN).

STANDARDS

       Linux.

HISTORIQUE

       Linux 3.18.

NOTES

       Avant Linux 4.4, toutes les commandes bpf() exigeaient que  l'appelant  ait  la  capacité  CAP_SYS_ADMIN.
       Depuis Linux 4.4 jusqu'à présent, un utilisateur non privilégié peut créer des programmes limités de type
       BPF_PROG_TYPE_SOCKET_FILTER  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 :

       -  get_random
       -  get_smp_processor_id
       -  tail_call
       -  ktime_get_ns

       Un  accès  sans  privilèges  peut   être   bloqué   en   écrivant   la   valeur   1   dans   le   fichier
       /proc/sys/kernel/unprivileged_bpf_disabled.

       Les  objets  eBPF  (les mappes et les programmes) peuvent être partagés entre les processus. Par exemple,
       après fork(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 dup(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.

       Les  programmes  eBPF  peuvent  être  écrits  en  C  restreint  compilé en bytecode eBPF (en utilisant le
       compilateur clang). 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 samples/bpf/*_kern.c de
       l'arborescence des sources du noyau.

       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
       /proc/sys/net/core/bpf_jit_enable :

       0      Désactiver la compilation JIT (par défaut).

       1      Compilation normale.

       2      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 tools/net/bpf_jit_disasm.c  fourni  dans
              l'arborescence des sources du noyau.

       Depuis  Linux  4.15, le noyau peut être configuré avec l'option CONFIG_BPF_JIT_ALWAYS_ON. Dans ce cas, le
       compilateur JIT est toujours activé et bpf_jit_enable est positionné sur 1 et immuable (cette  option  de
       configuration du noyau est fournie pour contrer une des attaques Spectre contre l'interpréteur BPF).

       Le compilateur JIT pour eBPF est actuellement disponible pour les architectures suivantes :

       -  x86-64 (depuis Linux 3.18 ; cBPF depuis Linux 3.0) ;
       -  ARM32 (depuis Linux 3.18 ; cBPF depuis Linux 3.4) ;
       -  SPARC 32 (depuis Linux 3.18 ; cBPF depuis Linux 3.5) ;
       -  ARM-64 (depuis Linux 3.18) ;;
       -  s390 (depuis Linux 4.1 ; cBPF depuis Linux 3.7) ;
       -  PowerPC 64 (depuis Linux 4.8 ; cBPF depuis Linux 3.1) ;
       -  SPARC 64 (depuis Linux 4.12) ;
       -  x86-32 (depuis Linux 4.18) ;
       -  MIPS 64 (depuis Linux 4.18 ; cBPF depuis Linux 3.16) ;
       -  riscv (depuis Linux 5.1).

EXEMPLES

       /* 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 '%s'\n", 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\n", tcp_cnt, udp_cnt);
               sleep(1);
           }

           return 0;
       }

       Vous  pouvez  trouvez  du  code complet opérationnel dans le répertoire samples/bpf de l'arborescence des
       sources du noyau.

VOIR AUSSI

       seccomp(2), bpf-helpers(7), socket(7), tc(8), tc-bpf(8)

       Les BPF classique et étendu  sont  expliqués  dans  le  fichier  Documentation/networking/filter.txt  des
       sources du noyau.

TRADUCTION

       La   traduction   française   de   cette   page   de   manuel   a   été   créée   par  Christophe  Blaess
       <https://www.blaess.fr/christophe/>,   Stéphan   Rafin   <stephan.rafin@laposte.net>,   Thierry   Vignaud
       <tvignaud@mandriva.com>,  François  Micaux,  Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard
       <fevrier@tigreraye.org>,   Jean-Luc   Coulon   (f5ibh)   <jean-luc.coulon@wanadoo.fr>,   Julien   Cristau
       <jcristau@debian.org>,      Thomas      Huriaux      <thomas.huriaux@gmail.com>,     Nicolas     François
       <nicolas.francois@centraliens.net>,    Florentin    Duneau    <fduneau@gmail.com>,     Simon     Paillard
       <simon.paillard@resel.enst-bretagne.fr>,     Denis    Barbier    <barbier@debian.org>,    David    Prévot
       <david@tilapin.org>,    Cédric    Boutillier     <cedric.boutillier@gmail.com>,     Frédéric     Hantrais
       <fhantrais@gmail.com> et Jean-Philippe MENGUAL <jpmengual@debian.org>

       Cette  traduction  est  une  documentation libre ; veuillez vous reporter à la GNU General Public License
       version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

       Si vous découvrez un bogue dans la traduction de cette page de manuel,  veuillez  envoyer  un  message  à
       debian-l10n-french@lists.debian.org.

Pages du manuel de Linux 6.9.1                    15 juin 2024                                            bpf(2)