Retour à l'accueil

Surveillance du trafic eBPF NetFlow bare metal K8s

L'article décrit l'implémentation d'un système de collecte de statistiques NetFlow utilisant eBPF/XDP pour bare metal, virtualisation et Kubernetes. Il couvre la sélection des cartes BPF (PERCPU_HASH), le sharding, l'échantillonnage avec timers. Des benchmarks et du code sont fournis.

eBPF + NetFlow : télémétrie des serveurs à Kubernetes
Advertisement 728x90

eBPF et NetFlow pour la surveillance du trafic : du matériel physique au Kubernetes

Un système fondé sur eBPF/XDP et NetFlow fournit une télémétrie réseau granulaire à tous les niveaux, des serveurs physiques aux clusters Kubernetes. Il surmonte les limites des solutions traditionnelles comme sFlow/NetFlow, notamment le surcoût matériel élevé, l'échantillonnage et l'absence de champs personnalisés. Le trafic est traité via une interface routeur-on-a-stick unifiée, permettant à XDP de capturer les paquets entrants sans modifier le noyau.

eBPF exécute des programmes directement dans le noyau du système d’exploitation, de manière sécurisée et avec une latence minimale, ce qui en fait un outil idéal pour la surveillance en temps réel. Les statistiques sont collectées par 5-tuple (adresses IP, ports, protocole), octets et paquets, puis exportées au format NetFlow vers les collecteurs.

Choisir les cartes BPF pour des performances optimales

Les cartes BPF stockent les statistiques sous forme de tables clé-valeur : la clé est le 5-tuple, la valeur correspond aux compteurs. Des tests ont révélé des problèmes avec BPF_MAP_TYPE_HASH :

Google AdInline article slot
  • Contention de verrous lors d’un accès multithreadé depuis plusieurs cœurs.
  • Conditions de course entraînant des compteurs inexactes.

Les opérations atomiques (__sync_fetch_and_add) éliminent les erreurs mais réduisent les performances à cause de la surcharge de synchronisation.

Passer à BPF_MAP_TYPE_PERCPU_HASH crée une carte distincte par cœur CPU, éliminant ainsi les verrous. L’agrégation se fait côté utilisateur. Des benchmarks sur 100 cœurs sous charges variables confirment que les cartes PERCPU surpassent les autres.

Lorsqu’elles sont pleines (600K 5-tuples dans une carte de 60K entrées), BPF_MAP_TYPE_LRU_PERCPU_HASH supprime les anciennes entrées — mais au prix d’une complexité accrue. La version standard PERCPU_HASH reste préférée pour des lectures rapides et ponctuelles.

Google AdInline article slot
// Déterminer quelle carte écrire
#define SHARD_COUNT 25 // nombre de partitions
map_hash_idx = ctx->rx_queue_index % SHARD_COUNT + shard_offset;

Partitionnement des cartes et exportation multithreadée

Une seule carte contenant 10 millions d’enregistrements était bloquée par un exportateur monothread. En la divisant en 25 cartes (basées sur rx_queue_index via RSS), il a été possible de lire en parallèle, accélérant le traitement jusqu’à 3 fois.

Avantages du partitionnement :

  • Scalabilité : ajout de cartes sans redémarrage.
  • Parallélisme : les capteurs lisent plusieurs cartes simultanément.
  • Efficacité du cache : les petites cartes tiennent dans les caches L1/L2.

Le capteur écrit en Go (utilisant les bibliothèques Cilium) exploite BPF_MAP_LOOKUP_AND_DELETE_BATCH pour lire et vider les cartes toutes les minutes — minimisant ainsi la perte de données en cas de saturation.

Google AdInline article slot

Échantillonnage et adaptation dynamique de charge

Pour équilibrer performance de transfert et besoins de télémétrie, l’échantillonnage est mis en œuvre. Une deuxième carte stats_map (BPF_MAP_TYPE_HASH, max_entries=128) suit le décompte des paquets par partition :

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 128);  // Nombre maximal de partitions
    __type(key, __u32);        // ID de partition
    __type(value, __u64);      // Compteurs de paquets/octets
    __uint(pinning, LIBBPF_PIN_BY_NAME);
} stats_map SEC(".maps");

Des temporisateurs eBPF calculent périodiquement le débit (paquets/sec) et déclenchent l’échantillonnage lorsque les seuils sont dépassés par partition. Ces temporisateurs exécutent des tâches en arrière-plan, en dehors du contexte des paquets — agrégant les données et réinitialisant les compteurs.

Cela maintient la stabilité pendant les pics de trafic (comme les attaques DDoS) tout en préservant la visibilité au niveau des sessions.

Adaptation aux environnements virtualisés et Kubernetes

L’architecture matérielle physique s’adapte naturellement aux environnements virtualisés et aux clusters Kubernetes. Dans K8s, eBPF/XDP fonctionne en tant que DaemonSet, capturant le trafic des pods via le CNI. Le partitionnement s’ajuste à l’affinité des nœuds ; PERCPU_HASH correspond parfaitement aux vCPUs.

L’export NetFlow agrège des métadonnées (espace de noms, IP du pod), améliorant l’observabilité des microservices.

Points clés :

  • PERCPU_HASH élimine la contention de verrous, augmentant le débit de 2 à 3 fois par rapport à HASH.
  • Le partitionnement accélère l’exportation de 3 fois grâce au parallélisme.
  • Les temporisateurs eBPF + échantillonnage équilibrent la charge sans sacrifier le transfert.
  • La variante LRU convient aux scénarios dynamiques avec saturation.
  • Le capteur Go avec bibliothèques Cilium excelle dans l’analyse à haut débit.

— Editorial Team

Advertisement 728x90

Lire ensuite