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

CrochetLieuLatenceCas d'utilisation
XDPPilote NIC, avant l'allocation sk buffPlus basDDoS chute, équilibre de charge
tc entrée/sortieAprès l'allocation de sk buffFaibleTrafic, marquage, redirection
filtre socketSocket recevoir le cheminMoyennefiltrage de type tcpdump
kprobe/tracepointEntrée/sortie de la fonction noyauVariantesObservabilité, 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ériquesk_buff
  • XDP déchargé

Un programme XDP renvoie l'un des cinq verdicts :

Code de retourDécision
XDP_DROPDéposer le paquet immédiatement — latence la plus basse
XDP_PASSPasser à la pile réseau normale
XDP_TXTransmettre la même interface (bounce)
XDP_REDIRECTRediriger vers une autre interface ou une socket AF XDP
XDP_ABORTEDChemin 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";
La vérification des plaies est obligatoire.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/XDPDPDKRDMA
Participation du noyauMinimal (XDP dans le pilote)Aucune (passage complet)Aucune (RDMA NIC)
Modèle de mémoireNorme + AF XDP UMEMPages importantes requisesRégions de mémoire enregistrées
Débit maximal~100 Gbps natif XDP> 100 Gbps200+ Gbps (InfiniBand)
Utilisation du processeurFaibleÉlevées (noyaux à forte charge)Près de zéro (déchargement)
Complexité opérationnelleFaible — outils standardHaut — cœurs dédiés, immensespagesHaute — gestion des tissus
Cas d'utilisationAtténuation du DDoS, LB, observabilitéRouteurs virtuels, NFV, paquet genStockage (NVMe-oF), HPC MPI
LangueC / Rouille restreinteC / RouilleAPI Verbes (C)
Règle du pouce :