Rate-limiter une IP au niveau kernel avec XDP et eBPF : tutoriel complet
Pour rate-limiter une IP avec XDP eBPF, il faut comprendre que XDP (eXpress Data Path) opère au niveau le plus bas du kernel Linux, directement dans le driver réseau, avant même la construction du sk_buff. Ce tutoriel 2026 vous montre comment combiner XDP pour du rate-limiting stateless ultra-rapide (par paquet) et nftables pour du rate-limiting stateful par connexion, deux approches complémentaires pour maîtriser le trafic entrant d'une adresse IP ciblée.
Pourquoi rate-limiter une IP au niveau XDP/eBPF plutôt qu'avec un firewall classique ?
Les firewalls traditionnels (iptables, ufw) opèrent dans la pile réseau du kernel après l'allocation mémoire du paquet (sk_buff). Sous une attaque volumétrique ciblant une seule IP source, des millions de paquets par seconde saturent le CPU avant même que les règles netfilter ne s'appliquent. XDP eBPF contourne ce goulet en exécutant un programme BPF directement dans le driver réseau, avant toute allocation mémoire coûteuse.
L'avantage : un verdict XDP_DROP consomme quelques dizaines de nanosecondes par paquet. Un serveur avec une carte réseau 10 Gbps peut rejeter plusieurs millions de pps sans impacter les connexions légitimes. C'est exactement ce que fait PAKKT.io en déployant un programme XDP unique par interface (le PAKKT Engine), capable de gérer jusqu'à 256 règles simultanées pilotées par des BPF maps en espace utilisateur.
Limites du rate-limiting XDP stateless
XDP est stateless : chaque paquet est jugé individuellement, sans mémoire de la connexion TCP ni du flux UDP. Le rate-limiting XDP repose donc sur un compteur de paquets par seconde (pps), pas sur un débit en bytes. Si vous devez limiter 1 Mbps pour une IP donnée, XDP seul ne suffit pas : il faudra compléter avec nftables pour du rate-limiting stateful ou du byte-based limiting avec des meters.
En revanche, bloquer une IP qui envoie 500 000 pps vers le port 80 alors que le seuil autorisé est 1 000 pps ? XDP est imbattable. La règle PAKKT rule_type: rate_limit avec max_pps ou max_port_pps applique ce compteur directement dans la BPF map, mise à jour toutes les secondes par l'agent Go.

Méthode 1 : Rate-limiter une IP avec XDP (PAKKT Engine ou programme BPF custom)
Si vous utilisez PAKKT, la configuration d'une règle de rate-limit IP se fait via le panel web ou l'API publique. Voici la logique interne :
- L'agent PAKKT déploie un programme XDP unique (
pakkt_engine.bpf.o) attaché à l'interface réseau (par exemple eth0). - Une BPF map nommée
pakkt_rulesstocke jusqu'à 256 règles indexées. Chaque règle contient : port_range (min/max), protocole (TCP/UDP/ICMP/any), rule_type (block / rate_limit / allow_only), max_pps global, max_port_pps, min/max packet size. - Une seconde BPF map
pakkt_pps_countersmaintient un compteur de paquets par seconde pour chaque combinaison (IP source, port destination). - Toutes les secondes, l'agent réinitialise les compteurs via
bpf_map_update_elem, permettant un rate-limit glissant.
Exemple de règle PAKKT pour rate-limiter le trafic TCP vers le port 25565 à 2 000 pps maximum, toutes IPs confondues :
{
"port_min": 25565,
"port_max": 25565,
"protocol": "TCP",
"rule_type": "rate_limit",
"max_port_pps": 2000,
"enabled": true
}
Si une IP source dépasse ce seuil, les paquets excédentaires reçoivent un verdict XDP_DROP instantané. Aucun CPU gaspillé, aucun sk_buff alloué. L'impact mesuré sur un serveur de production : < 1% CPU, < 5 MB RAM pour l'agent Go complet (mTLS, heartbeat 30s, métriques TimescaleDB).
Déployer un programme XDP custom pour rate-limiter une IP spécifique
Si vous souhaitez écrire votre propre programme BPF (hors PAKKT), voici un exemple simplifié en C (kernel headers requis) :
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <bpf/bpf_helpers.h>
struct pps_key {
__u32 saddr;
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__type(key, struct pps_key);
__type(value, __u64);
__uint(max_entries, 10000);
} pps_map SEC(".maps");
SEC("xdp")
int xdp_rate_limit(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return XDP_PASS;
struct iphdr *iph = (void *)(eth + 1);
if ((void *)(iph + 1) > data_end) return XDP_PASS;
struct pps_key key = { .saddr = iph->saddr };
__u64 *counter = bpf_map_lookup_elem(&pps_map, &key);
if (!counter) {
__u64 init = 1;
bpf_map_update_elem(&pps_map, &key, &init, BPF_ANY);
return XDP_PASS;
}
__sync_fetch_and_add(counter, 1);
if (*counter > 10000) { // seuil 10k pps par IP
return XDP_DROP;
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
Compilez avec clang -O2 -target bpf -c xdp_ratelimit.c -o xdp_ratelimit.o, puis chargez avec ip link set dev eth0 xdp obj xdp_ratelimit.o sec xdp. Attention : ce code est stateless, le compteur ne se réinitialise pas automatiquement. Il faudra un userspace daemon pour vider la map toutes les secondes (via bpftool map update ou libbpf). C'est exactement ce que l'agent PAKKT automatise.

Méthode 2 : Rate-limiter une IP avec nftables (couche stateful complémentaire)
Pour du rate-limiting basé sur les connexions TCP ou pour limiter en bytes (débit), nftables est l'outil idéal. PAKKT déploie automatiquement une table inet pakkt isolée, zéro conflit avec Docker, fail2ban ou iptables-persistent.
Rate-limit par nouvelle connexion (ct state new)
Exemple pour limiter l'IP 203.0.113.42 à 10 nouvelles connexions TCP par seconde vers le port 443 :
nft add table inet pakkt
nft add chain inet pakkt input { type filter hook input priority filter \; policy accept \; }
nft add rule inet pakkt input ip saddr 203.0.113.42 tcp dport 443 ct state new limit rate 10/second accept
nft add rule inet pakkt input ip saddr 203.0.113.42 tcp dport 443 ct state new drop
Les 10 premières nouvelles connexions par seconde passent (accept), les suivantes sont droppées. Les connexions déjà établies (ct state established) ne sont pas comptabilisées, évitant de couper des sessions légitimes.
Rate-limit global avec meter et burst
Pour partager un quota entre plusieurs IPs (par exemple, limiter un sous-réseau /24 à 1 000 pps global), utilisez un meter :
nft add rule inet pakkt input ip saddr 203.0.113.0/24 meter flood_meter { ip saddr timeout 1s limit rate 1000/second burst 50 packets } accept
nft add rule inet pakkt input ip saddr 203.0.113.0/24 drop
Le paramètre burst autorise un pic court (50 paquets) avant d'appliquer le rate strictement. Utile pour absorber les micro-rafales TCP (SYN handshake, retransmissions).
Intégration PAKKT : blacklist/whitelist double couche
PAKKT synchronise automatiquement les listes IP entre XDP BPF map et règles nftables. Quand vous ajoutez 203.0.113.42 à la blacklist via le panel, l'agent :
- Insère l'IP dans la BPF map
pakkt_blacklist(verdict XDP_DROP ultra-rapide). - Ajoute une règle nft
ip saddr 203.0.113.42 dropdans la chaîne pakkt input (couche de secours stateful).
Double garantie : même si le programme XDP est temporairement déchargé (mise à jour kernel, rechargement interface), la règle nftables continue de bloquer. Voir la documentation complète sur les intégrations PAKKT pour l'API publique (clé API) permettant d'automatiser ces opérations via scripts ou webhooks.
Monitoring et métriques : observer le rate-limiting en temps réel
Un rate-limit efficace ne se configure pas à l'aveugle. PAKKT centralise les métriques dans TimescaleDB (extension PostgreSQL pour séries temporelles) :
- Graphiques par port/règle : paquets acceptés vs droppés, tendance horaire, top IPs sources.
- GeoIP : carte monde interactive, top pays sources, détection d'attaques géo-distribuées (botnet).
- Audit log : chaque modification de règle, ajout IP blacklist/whitelist, tracée avec timestamp et utilisateur.
- Logs internes agent : rechargement XDP, erreurs BPF (verifier rejects), stats mémoire maps.
Pour une stack custom, utilisez bpftool map dump name pakkt_pps_counters pour lire les compteurs en direct, ou nft list ruleset pour vérifier les counters nftables (counter packets X bytes Y). Exportez vers Prometheus avec node_exporter + textfile collector, ou vers Grafana via telegraf + exec plugin.
Alertes automatiques sur dépassement de seuil
PAKKT permet de configurer des webhooks (Discord, Slack, API custom) déclenchés quand une règle rate-limit bloque > X paquets sur une fenêtre de Y minutes. Exemple : alerte si > 100 000 paquets droppés en 5 min sur le port 22 (scan SSH brute-force). L'équipe SRE reçoit l'alerte avec l'IP source top 1, le pays GeoIP, et peut décider de blacklister définitivement ou d'ajuster le seuil max_port_pps.
Pour approfondir les concepts XDP et eBPF, consultez la documentation officielle du kernel Linux sur kernel.org/bpf, référence d'autorité pour les développeurs de programmes BPF custom.
Combiner XDP et nftables : architecture hybride recommandée
La meilleure pratique 2026 consiste à empiler XDP (rate-limit stateless ultra-rapide par paquet) et nftables (rate-limit stateful par connexion, tracking TCP) dans une architecture hybride :
| Couche | Technologie | Cas d'usage rate-limit | Performance |
| L2 (driver réseau) | XDP eBPF | Bloquer IP à > 10k pps, rejeter paquets < 64 bytes (attaque fragmentation) | Sub-microseconde par paquet |
| L3/L4 (netfilter) | nftables | Limiter nouvelles connexions TCP/s, rate-limit par tuple (IP+port), meter partagé | Quelques microsecondes par paquet (conntrack) |
Avec PAKKT, cette architecture est déployée automatiquement par l'agent en < 30 secondes. L'agent Go (compilé avec obfuscation garble, mTLS obligatoire, self-update SHA256) configure le programme XDP, crée la table nftables isolée, et maintient la cohérence entre les deux couches via heartbeat 30s vers le panel centralisé. Impact mesuré : < 1% CPU, < 5 MB RAM, latence ajoutée négligeable (< 0.1 ms sur un serveur i9-13900K 10 Gbps sous charge 2 Mpps).
Cette double couche protège efficacement contre les attaques DDoS L3/L4 (SYN flood, UDP amplification, ICMP flood) directement sur le serveur. Pour des attaques volumétriques > 50 Gbps, PAKKT est complémentaire aux solutions de scrubbing cloud (Cloudflare Magic Transit, OVH VAC, Arbor Networks) : le scrubbing nettoie en amont, PAKKT affine la protection au niveau kernel pour les flux résiduels ou les attaques applicatives ciblées.
Conclusion
Rate-limiter une IP avec XDP eBPF et nftables combine la rapidité sub-microseconde du traitement au niveau driver (XDP stateless) et la finesse du suivi de connexion (nftables stateful). Cette approche hybride offre une protection kernel-level efficace contre les attaques volumétriques, tout en préservant les ressources CPU pour les connexions légitimes. Que vous écriviez vos propres programmes BPF ou que vous déployiez une plateforme SaaS comme PAKKT, l'enjeu reste le même : filtrer au plus tôt, monitorer en continu, ajuster les seuils en fonction des métriques réelles.
FAQ
Puis-je rate-limiter une IP en bytes par seconde (Mbps) uniquement avec XDP ?
Non, XDP est stateless et ne peut pas tracker le débit en bytes de manière fiable sans état de connexion. Utilisez nftables avec des meters ou des règles limit pour du rate-limiting basé sur le volume de données (ex. : limit rate 10 mbytes/second). XDP excelle pour limiter en paquets par seconde (pps), idéal contre les attaques par volume de paquets (SYN flood, UDP flood).
Comment réinitialiser automatiquement les compteurs de paquets dans une BPF map XDP ?
Un programme XDP seul ne peut pas gérer le temps : il faut un daemon userspace (agent Go, script Python avec libbpf, ou service systemd timer) qui parcourt la BPF map toutes les secondes et réinitialise les compteurs via bpf_map_update_elem. PAKKT automatise cette logique dans son agent, garantissant un rate-limit glissant précis sans intervention manuelle.
Peut-on combiner rate-limit XDP et whitelist IP dans la même règle ?
Oui, la logique du programme XDP peut vérifier d'abord si l'IP source est dans une BPF map whitelist (verdict XDP_PASS immédiat), puis appliquer le compteur de rate-limit uniquement aux IPs non whitelistées. PAKKT implémente cette double couche : la whitelist IP (BPF map + règle nft) court-circuite toutes les règles de rate-limit ou de blocage, garantissant un accès sans restriction pour les IPs de confiance (monitoring, backup, admin).
Déployez PAKKT en 30 secondes
Protection kernel double couche XDP + nftables, pilotable depuis un panel centralisé. Essai gratuit 7 jours.