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

Linux                                            1 novembre 2020                                          BPF(2)