Linux eBPF & XDP Networking Primer
Linux eBPF & XDP Networking Primer
Un guide pratique pour les programmes BPF, les crochets XDP et le traitement des paquets de contournement pour les ingénieurs réseau.
1. Qu'est-ce que l'eBPF?
eBPF (extension Berkeley Packet Filter) est un sous-système de noyau Linux qui vous permet d'exécuter des programmes sandboxed à l'intérieur du noyau sans modifier le code source du noyau ou charger des modules du noyau. Les programmes sont vérifiés par un vérificateur d'octets du noyau avant l'exécution, assurant la sécurité.
Pour la mise en réseau, les programmes du FBP e s'attachent à dans la pile réseau du noyau et peut inspecter, modifier, rediriger ou déposer des paquets. L'avantage clé sur ou modules du noyau est performance et programmabilité: les programmes eBPF sont compilés en code natif et peuvent partager l'état via (stockages à valeur clé partagés entre le noyau et l'espace utilisateur).
| Crochet | Lieu | Latence | Cas d'utilisation |
|---|---|---|---|
| XDP | Pilote NIC, avant l'allocation sk buff | Plus bas | DDoS chute, équilibre de charge |
| tc entrée/sortie | Après l'allocation de sk buff | Faible | Trafic, marquage, redirection |
| filtre socket | Socket recevoir le chemin | Moyenne | filtrage de type tcpdump |
| kprobe/tracepoint | Entrée/sortie de la fonction noyau | Variantes | Observabilité, traçage |
2. Points de crochet XDP
Les programmes XDP (eXpress Data Path) fonctionnent au plus tôt dans la pile réseau — à l'intérieur du pilote NIC, avant que le noyau ne attribue un . Cela signifie:
- Native XDP
-
XDP générique
sk_buff - XDP déchargé
Un programme XDP renvoie l'un des cinq verdicts :
| Code de retour | Décision |
|---|---|
XDP_DROP |
Déposer le paquet immédiatement — latence la plus basse |
XDP_PASS |
Passer à la pile réseau normale |
XDP_TX |
Transmettre la même interface (bounce) |
XDP_REDIRECT |
Rediriger vers une autre interface ou une socket AF XDP |
XDP_ABORTED |
Chemin d'erreur — goutte avec l'événement de trace |
3. Exemple de chute de paquets XDP
Le programme suivant supprime tous les paquets UDP d'une IP source stockée dans une carte eBPF, permettant à un plan de contrôle de l'espace utilisateur de mettre à jour la liste de blocs à l'exécution.
// xdp_drop_udp.c — Drop UDP from IPs in a BPF map
#include
#include
#include
#include
#include
// BPF map: src IP → drop flag (1 = drop)
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, __u32); // source IPv4 address
__type(value, __u32); // 1 = block
} blocklist SEC(".maps");
SEC("xdp")
int xdp_drop_udp(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
// Parse Ethernet header
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;
// Parse IPv4 header
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end) return XDP_PASS;
if (ip->protocol != IPPROTO_UDP) return XDP_PASS;
// Check blocklist map
__u32 src = ip->saddr;
__u32 *val = bpf_map_lookup_elem(&blocklist, &src);
if (val && *val == 1) return XDP_DROP;
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
data_end
Charger et attacher avec :
# Compile
clang -O2 -target bpf -c xdp_drop_udp.c -o xdp_drop_udp.o
# Attach to interface (native XDP)
ip link set eth0 xdp obj xdp_drop_udp.o sec xdp
# Add an IP to the blocklist via bpftool
bpftool map update name blocklist key 0x01 0x02 0x03 0x04 value 0x01 0x00 0x00 0x00
# Remove XDP program
ip link set eth0 xdp off
4. AF XDP : Dépassement du noyau
AF_XDPXDP_REDIRECT
Composantes clés:
- UMEM
- Anneaux
- Mode de copie zéro
AF XDP est idéal pour le traitement personnalisé de paquets au taux de ligne sans la complexité opérationnelle de DPDK (pas de pages énormes, pas de pinning CPU nécessaire pour une utilisation de base).
5. tc BPF: Configuration et filtrage du trafic
tcclsactsk_buff
// tc_mark.c — Mark packets with DSCP EF (46) for VoIP traffic on port 5060
#include
#include
#include
#include
#include
SEC("classifier")
int tc_mark_voip(struct __sk_buff *skb) {
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
if ((void *)(eth + 1) > data_end) return TC_ACT_OK;
if (eth->h_proto != __constant_htons(ETH_P_IP)) return TC_ACT_OK;
struct iphdr *ip = (void *)(eth + 1);
if ((void *)(ip + 1) > data_end) return TC_ACT_OK;
if (ip->protocol != IPPROTO_UDP) return TC_ACT_OK;
struct udphdr *udp = (void *)(ip + 1);
if ((void *)(udp + 1) > data_end) return TC_ACT_OK;
// Mark SIP traffic (port 5060) with DSCP EF (46 = 0xB8 in TOS byte)
if (udp->dest == __constant_htons(5060) || udp->source == __constant_htons(5060)) {
// DSCP EF = 46, shifted left 2 bits in TOS field = 184 (0xB8)
bpf_skb_store_bytes(skb, offsetof(struct iphdr, tos) + sizeof(struct ethhdr),
&((__u8){184}), 1, BPF_F_RECOMPUTE_CSUM);
}
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";
# Attach tc BPF program
tc qdisc add dev eth0 clsact
tc filter add dev eth0 egress bpf da obj tc_mark.o sec classifier
6. Limites tarifaires avec les cartes eBPF
Les cartes eBPF permettent un traitement de qualité. Le modèle suivant implémente par source-IP limite le taux en utilisant un seau de jeton stocké dans un :
// Conceptual token bucket per source IP — checks tokens, drops if exceeded
struct ratelimit_entry {
__u64 tokens; // current token count
__u64 last_update; // nanoseconds timestamp
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 65536);
__type(key, __u32); // source IP
__type(value, struct ratelimit_entry);
} rate_map SEC(".maps");
// In XDP program:
// 1. bpf_ktime_get_ns() — get current time
// 2. Lookup entry for src IP
// 3. Refill tokens: tokens += (elapsed_ns / 1e9) * rate_pps
// 4. If tokens >= 1: decrement and XDP_PASS
// 5. Else: XDP_DROP
7. introspection bpftool & bpftrace
Deux outils essentiels pour travailler avec les programmes eBPF en direct :
# bpftool — inspect loaded programs and maps
bpftool prog list # list all loaded eBPF programs
bpftool prog show id 42 # details for program ID 42
bpftool prog dump xlated id 42 # disassemble to eBPF bytecode
bpftool prog dump jited id 42 # dump JIT-compiled native code
bpftool map list # list all BPF maps
bpftool map dump name blocklist # dump all entries in map "blocklist"
bpftool map update name blocklist \
key 192 168 1 100 value 1 0 0 0 # add entry (network byte order)
# bpftrace — DTrace-style one-liners for kernel tracing
# Count XDP drops per second
bpftrace -e 'tracepoint:xdp:xdp_exception { @drops[args->action] = count(); } interval:s:1 { print(@drops); clear(@drops); }'
# Trace tcp_retransmit_skb — show retransmit events with comm name
bpftrace -e 'kprobe:tcp_retransmit_skb { printf("%s retransmit\n", comm); }'
# Histogram of packet sizes on eth0
bpftrace -e 'tracepoint:net:netif_receive_skb /args->name == "eth0"/ { @size = hist(args->len); }'
8. Comparaison : eBPF/XDP vs DPDK vs RDMA
| Fonctionnalité | eBPF/XDP | DPDK | RDMA |
|---|---|---|---|
| Participation du noyau | Minimal (XDP dans le pilote) | Aucune (passage complet) | Aucune (RDMA NIC) |
| Modèle de mémoire | Norme + AF XDP UMEM | Pages importantes requises | Régions de mémoire enregistrées |
| Débit maximal | ~100 Gbps natif XDP | > 100 Gbps | 200+ Gbps (InfiniBand) |
| Utilisation du processeur | Faible | Élevées (noyaux à forte charge) | Près de zéro (déchargement) |
| Complexité opérationnelle | Faible — outils standard | Haut — cœurs dédiés, immensespages | Haute — gestion des tissus |
| Cas d'utilisation | Atténuation du DDoS, LB, observabilité | Routeurs virtuels, NFV, paquet gen | Stockage (NVMe-oF), HPC MPI |
| Langue | C / Rouille restreinte | C / Rouille | API Verbes (C) |