Provided by: manpages-fr-dev_4.13-4_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 |--

   Arguments
       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).  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 {    /* Used by 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éfini de façon appropriée.

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.

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

VERSIONS

       L'appel système bpf() est apparu pour la première fois dans Linux 3.18.

CONFORMITÉ

       L'appel système bpf() est spécifique à Linux.

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.  Dans  les  noyaux  antérieurs  à
       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.

COLOPHON

       Cette  page  fait partie de la publication 5.10 du projet man-pages Linux. Une description
       du projet et des instructions pour signaler des anomalies et la dernière version de  cette
       page peuvent être trouvées à l'adresse https://www.kernel.org/doc/man-pages/.

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  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  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 ⟨⟩.