Provided by: manpages-fr-dev_4.18.1-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 |--

   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). 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 {    /* 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é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.

       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.

STANDARDS

       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. 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 à la 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  ⟨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⟩.