XDP / eBPF

XDP pinning et persistance : survivre aux redémarrages de service

11 octobre 2026 · 10 min de lecture
Illustration immersive du sujet : XDP pinning persistance

Le XDP pinning persistance garantit que vos programmes eBPF chargés en XDP survivent aux redémarrages de l'agent, aux mises à jour du noyau ou aux reconnexions réseau. Sans cette technique, chaque restart d'interface ou de service recharge un nouvel objet BPF, générant de nouveaux file descriptors éphémères et perdant l'état partagé entre processus. En 2026, la persistance par pinning est devenue un pré-requis pour toute stack de protection kernel sérieuse, permettant à la fois la haute disponibilité et l'orchestration centralisée de règles sans coupure de trafic.



Pourquoi un programme XDP classique ne survit pas au restart

Lorsque vous attachez un programme XDP à une interface réseau via ip link set dev eth0 xdp obj mon_prog.bpf.o, le noyau crée un file descriptor (fd) temporaire dans l'espace mémoire du processus appelant. Dès que ce processus se termine ou que l'interface passe en état DOWN puis UP, le fd est fermé et le programme XDP détaché. Toutes les BPF maps associées — tables de règles, compteurs, listes noires — disparaissent avec lui.

Ce comportement pose trois problèmes majeurs en production :

  • Perte de contexte. Un rate-limiter XDP qui comptait 100 000 paquets par seconde sur un port repart de zéro après le restart de l'agent ou un simple systemctl restart networking.
  • Fenêtre de vulnérabilité. Entre le détachement de l'ancien programme et le rattachement du nouveau, le trafic passe sans filtre. Un attaquant peut exploiter cette fenêtre de quelques millisecondes pour inonder la cible.
  • Complexité de l'orchestration. L'agent de supervision doit re-parser la configuration, recompiler ou recharger l'objet BPF, recréer les maps, repeupler les données — alors qu'un simple pointeur suffisait.

Le pinning résout ces trois points en créant une ancre permanente dans le système de fichiers virtuel BPF (/sys/fs/bpf), indépendante du cycle de vie des processus.



Comment fonctionne le pinning de programmes et de maps XDP

Le pinning eBPF consiste à attacher un file descriptor BPF (programme ou map) à un inode dans /sys/fs/bpf. Une fois pinné, n'importe quel processus disposant des permissions appropriées peut rouvrir le même objet BPF en lecture ou écriture, même si le processus d'origine a disparu. Le noyau maintient un compteur de références (refcount) : tant qu'au moins un fd ou un pin existe, l'objet reste chargé en mémoire.

Pinner un programme XDP

# Charger et attacher le programme sans le détacher à la fin du processus
bpftool prog load pakkt_engine.bpf.o /sys/fs/bpf/pakkt_xdp type xdp

# Attacher le programme pinné à l'interface
bpftool net attach xdp pinned /sys/fs/bpf/pakkt_xdp dev eth0

# Vérifier que le programme est bien attaché
bpftool net show dev eth0

Désormais, même si l'agent de supervision crash ou redémarre, le programme XDP reste actif sur eth0. L'agent peut le retrouver via son chemin de pin et continuer à manipuler ses maps sans recharger l'objet.

Pinner les BPF maps pour partager l'état

# Après chargement, identifier l'ID de la map
bpftool map show name pakkt_rules

# Pinner la map
bpftool map pin id 42 /sys/fs/bpf/pakkt_rules_map

# L'agent peut désormais mettre à jour la map depuis n'importe quel processus
bpftool map update pinned /sys/fs/bpf/pakkt_rules_map \
  key 0 0 0 1 value 25 56 0 0 0 0 0 0

Cette approche est au cœur de l'architecture PAKKT.io : l'agent Go léger manipule jusqu'à 256 règles XDP dans une map pinnée, sans jamais recharger le binaire BPF. Les mises à jour de règles — ajout d'un port en rate-limit, modification du seuil max_pps, insertion d'une IP en whitelist — se font en temps réel via la map, et survivent aux redémarrages de l'agent ou même du daemon réseau.



Gérer la persistance du pinning au reboot système

Le montage /sys/fs/bpf est un tmpfs : il se vide au reboot complet de la machine. Pour garantir que vos programmes XDP restent actifs après un redémarrage matériel, vous devez scripter le rechargement dans un service systemd ou un hook réseau.

Service systemd pour restaurer le pinning

[Unit]
Description=PAKKT XDP Pinning Restore
After=network-pre.target
Before=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/pakkt-agent xdp-restore
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Le script xdp-restore vérifie si /sys/fs/bpf/pakkt_xdp existe. Si absent, il charge l'objet BPF depuis /var/lib/pakkt/pakkt_engine.bpf.o (copie locale signée SHA256), le pine, et rattache le programme aux interfaces configurées. Si le pin existe déjà, il se contente de rattacher le programme pinné. Ce pattern évite les duplications d'objets et garantit un état cohérent.

Vérification de l'intégrité du programme pinné

Avant de rattacher un programme XDP pinné, vérifiez son type et sa signature pour prévenir toute corruption ou remplacement malveillant :

bpftool prog show pinned /sys/fs/bpf/pakkt_xdp --json | jq -r '.type'
# Doit retourner "xdp"

sha256sum /var/lib/pakkt/pakkt_engine.bpf.o
# Comparer avec le hash signé stocké dans /var/lib/pakkt/engine.sha256

L'agent PAKKT effectue cette vérification à chaque heartbeat (30 secondes) et déclenche une alerte dans le panel si le hash ne correspond plus. En cas de divergence, l'agent re-télécharge l'objet BPF depuis le registry central (mTLS authentifié), le recharge, le pine et rattache.



Interactions du pinning XDP avec nftables et l'écosystème kernel

Le pinning XDP n'entre jamais en conflit avec nftables, iptables ou conntrack : XDP opère au niveau L2 (avant allocation du skb), tandis que nftables intervient dans Netfilter (L3/L4). En revanche, l'orchestration centralisée de règles XDP et nftables impose une coordination stricte pour éviter les doublons ou les incohérences.

Table nftables isolée et sans conflit

PAKKT déploie une table inet pakkt dédiée, avec priorité filter - 10, garantissant qu'elle s'exécute avant Docker, fail2ban ou toute règle utilisateur. Les règles nftables (rate-limit par connexion, TCP SYN flood, ICMP flood) complètent le filtre XDP stateless en apportant le suivi de connexion et les décisions L4 complexes :

nft add table inet pakkt
nft add chain inet pakkt input { type filter hook input priority -10 \; policy accept \; }
nft add rule inet pakkt input tcp dport 25565 ct state new limit rate 100/second accept
nft add rule inet pakkt input tcp dport 25565 ct state new drop

Les IP en blacklist XDP (drop immédiat avant allocation skb) sont synchronisées avec un set nftables pour bloquer aussi les paquets spoofés ou fragmentés qui échapperaient à XDP. Cette double couche réduit la charge CPU et garantit une protection défensive en profondeur.

Partage d'état entre XDP et nftables via maps

Depuis le noyau 5.13, nftables peut lire des BPF maps via map @my_map et déclencher des actions basées sur des compteurs XDP. Par exemple, si une map XDP nommée port_counters dépasse un seuil, un script userspace peut injecter dynamiquement une règle nftables de rate-limit :

bpftool map lookup pinned /sys/fs/bpf/port_counters key 25 56
# Si pps > 500000, alors :
nft add rule inet pakkt input udp dport 25565 limit rate over 10 mbytes/second drop

Cette orchestration hybride, pilotée par un agent centralisé comme PAKKT, permet d'adapter la stratégie de défense en temps réel sans recompiler le programme XDP ni redémarrer le firewall.



Limitations et pièges du pinning XDP en production

Le pinning n'est pas une solution miracle. Voici les écueils les plus fréquents rencontrés en production, et leurs remèdes.

Permissions et SELinux

Par défaut, seul root peut écrire dans /sys/fs/bpf. Si votre agent tourne sous un utilisateur dédié (ex. pakkt), vous devez ajuster les permissions ou utiliser des capabilities :

setcap cap_sys_admin,cap_net_admin,cap_bpf+epi /usr/local/bin/pakkt-agent

Sous SELinux, créez un module de politique autorisant le contexte pakkt_t à écrire dans bpf_fs_t.

Oubli du unpin avant rechargement

Si vous tentez de charger un nouveau programme avec le même nom de pin sans d'abord supprimer l'ancien, bpftool échoue avec File exists. Toujours unpin avant reload :

rm -f /sys/fs/bpf/pakkt_xdp
bpftool prog load pakkt_engine_v2.bpf.o /sys/fs/bpf/pakkt_xdp type xdp

Verrouillement de version noyau

Un objet BPF compilé pour un noyau 5.15 peut ne pas charger sur un 6.1 si les offsets de structures ont changé. Utilisez CO-RE (Compile Once, Run Everywhere) avec libbpf et vmlinux.h pour garantir la portabilité. L'agent PAKKT embarque un binaire BPF CO-RE universel, testé sur noyaux 5.4 à 6.6.

Limite de nombre de programmes pinnés

Le noyau impose un nombre maximal d'objets BPF chargés (défini par bpf_jit_limit). Sur une machine hébergeant des dizaines de containers, chacun avec son propre programme XDP, cette limite peut être atteinte. Privilégiez un programme XDP unique par interface physique (modèle PAKKT Engine), avec multiplexage des règles via une BPF map, plutôt que N programmes séparés.



Tableau comparatif : pinning XDP vs rechargement à chaud

Critère Pinning XDP Rechargement à chaud (iproute2)
Survie au restart agent Oui Non
Survie au redémarrage interface Oui (avec script systemd) Non
Fenêtre de vulnérabilité Aucune Quelques ms à quelques secondes
Partage de maps entre processus Natif via pinning map Impossible (fd éphémère)
Complexité orchestration Faible (mise à jour map uniquement) Élevée (recompile, recharge, repopule)
Compatibilité CO-RE Oui (libbpf) Oui (libbpf)
Impact sur latence trafic Nul (pas de détachement) Visible (pic latence pendant swap)

Pour une plateforme SaaS comme PAKKT.io, le pinning est un choix d'architecture : il garantit la cohérence multi-agents, la haute disponibilité et l'audit centralisé des règles, sans jamais interrompre le flux de paquets.



Audit et monitoring du pinning : logs et métriques

Un programme XDP pinné est invisible dans ps ou systemctl status. Vous devez donc instrumenter vos scripts de déploiement et votre agent pour tracer l'état du pinning.

Liste des objets BPF pinnés

ls -lah /sys/fs/bpf/
bpftool prog show
bpftool map show

Compteurs de paquets traités

Injectez un compteur global dans votre map XDP :

struct {
  __uint(type, BPF_MAP_TYPE_ARRAY);
  __uint(max_entries, 1);
  __type(key, __u32);
  __type(value, __u64);
} xdp_stats SEC(".maps");

Puis dans le programme XDP :

__u32 key = 0;
__u64 *count = bpf_map_lookup_elem(&xdp_stats, &key);
if (count) __sync_fetch_and_add(count, 1);

L'agent PAKKT lit cette map toutes les 30 secondes et envoie la métrique à TimescaleDB pour affichage temps réel dans le dashboard. Toute divergence brutale (baisse à zéro = programme détaché, explosion = flood) déclenche une alerte Webhook.

Logs kernel dmesg et tracepoints

Activez les tracepoints BPF pour tracer les événements de chargement/détachement :

echo 1 > /sys/kernel/debug/tracing/events/bpf/bpf_prog_load/enable
echo 1 > /sys/kernel/debug/tracing/events/bpf/bpf_map_create/enable
cat /sys/kernel/debug/tracing/trace_pipe

Intégrez ces logs dans votre stack de monitoring (journald, Loki, Elasticsearch) pour corréler les rechargements XDP avec les pics de trafic ou les alertes DDoS.



Cas d'usage réel : update de règle sans détachement

Imaginons un serveur de jeu Minecraft exposé sur le port 25565. Un attaquant lance un flood UDP à 2 millions de pps. Vous souhaitez passer de rate_limit 1M pps à block complet sans redémarrer le programme XDP.

Étape 1 : Modifier la map pinnée

# Structure de clé : rule_id (u32)
# Structure de valeur : port (u16), protocol (u8), rule_type (u8), max_pps (u32), ...
# rule_type : 0 = allow_only, 1 = rate_limit, 2 = block

bpftool map update pinned /sys/fs/bpf/pakkt_rules_map \
  key hex 01 00 00 00 \
  value hex 3d 63 11 02 00 00 00 00 00 00 00 00
# 3d 63 = port 25565 (little-endian), 11 = UDP, 02 = block

Étape 2 : Vérifier l'application

bpftool map dump pinned /sys/fs/bpf/pakkt_rules_map
# La règle ID 1 affiche désormais rule_type = 2 (block)

Instantanément, le programme XDP drop tous les paquets UDP/25565, sans fenêtre de vulnérabilité ni rechargement. Le compteur de paquets droppés (map séparée xdp_drop_stats) s'incrémente, visible dans le panel PAKKT en temps réel.

Étape 3 : Revenir à rate-limit après mitigation

bpftool map update pinned /sys/fs/bpf/pakkt_rules_map \
  key hex 01 00 00 00 \
  value hex 3d 63 11 01 40 42 0f 00 00 00 00 00
# rule_type = 01 (rate_limit), max_pps = 1000000 (0x000f4240 en little-endian)

Ce pattern — update atomique de map sans rechargement — est le cœur de la réactivité PAKKT. L'agent reçoit une instruction API du panel (« bloquer UDP/25565 »), écrit dans la map pinnée, et la règle s'applique en sub-microseconde, sans impacter les 255 autres règles actives sur l'interface.



Conclusion

Le XDP pinning persistance transforme vos programmes eBPF en composants système permanents, capables de survivre aux crashs, aux mises à jour et aux reconnexions réseau. En 2026, toute architecture de protection kernel sérieuse repose sur cette technique pour garantir haute disponibilité, orchestration centralisée et mise à jour à chaud des règles. Associé à nftables pour le suivi de connexion et piloté par un agent léger, le pinning XDP offre une défense kernel complète, transparente et sans coupure de service.



FAQ

Que se passe-t-il si je supprime accidentellement /sys/fs/bpf/pakkt_xdp en production ?

Le programme XDP reste chargé et actif sur l'interface tant qu'aucun processus n'a explicitement détaché le programme. En revanche, vous perdez la référence permanente : un restart de l'agent ou de l'interface détachera le programme. Pour récupérer, identifiez l'ID du programme via bpftool net show dev eth0, puis bpftool prog pin id <ID> /sys/fs/bpf/pakkt_xdp pour recréer le pin avant tout restart.

Peut-on pinner plusieurs programmes XDP sur la même interface ?

Non. Une interface ne peut avoir qu'un seul programme XDP attaché à la fois (en mode natif). Pour gérer plusieurs règles, utilisez une BPF map partagée (comme le modèle PAKKT Engine avec 256 règles dans une map unique) ou chaînez des programmes via bpf_tail_call. Le pinning permet de partager cette map entre plusieurs processus userspace sans dupliquer le programme XDP.

Le pinning XDP fonctionne-t-il avec les drivers en mode generic (SKB) ?

Oui, le pinning est indépendant du mode d'attachement XDP (native, offload, generic). Cependant, en mode generic, le programme s'exécute après allocation du skb, perdant l'avantage performance de XDP. Privilégiez toujours le mode native (driver supportant XDP) pour bénéficier du drop sub-microseconde. Vérifiez la compatibilité de votre NIC via ethtool -i eth0 | grep driver et consultez la liste des drivers XDP sur kernel.org.

Protégez vos serveurs

Déployez PAKKT en 30 secondes

Protection kernel double couche XDP + nftables, pilotable depuis un panel centralisé. Essai gratuit 7 jours.