1. eBPF nedir?

eBPF (genişletilmiş Berkeley Paket Filtresi), çekirdek kaynak kodunu değiştirmeden veya çekirdek modüllerini yüklemeden, çekirdeğin içinde korumalı alana alınmış programları çalıştırmanıza olanak tanıyan bir Linux çekirdek alt sistemidir. Programlar, yürütülmeden önce bir çekirdek bayt kodu doğrulayıcı tarafından doğrulanarak güvenlik sağlanır.

Ağ oluşturmak için eBPF programları aşağıdakilere eklenir:kanca noktalarıçekirdeğin ağ yığınında bulunur ve paketleri inceleyebilir, değiştirebilir, yönlendirebilir veya bırakabilir. Üzerindeki en önemli avantajiptablesveya çekirdek modülleri performans ve programlanabilirliktir: eBPF programları JIT ile yerel koda derlenmiştir ve durumuharitalar(çekirdek ve kullanıcı alanı arasında paylaşılan anahtar/değer depoları).

KancaKonumGecikmeKullanım Örneği
XDPNIC sürücüsü, sk_buff tahsisinden önceEn düşükDDoS düşüşü, yük dengeleme
TC giriş/çıkışSk_buff tahsisinden sonraDüşükTrafik şekillendirme, işaretleme, yönlendirme
soket filtresiSoket alma yoluOrtatcpdump tarzı filtreleme
kprobe/izleme noktasıÇekirdek işlevi girişi/çıkışıDeğişirGözlemlenebilirlik, izleme

2. XDP Kanca Noktaları

XDP (eXpress Veri Yolu) programları, çekirdek bir veri yolu ayırmadan önce ağ yığınında mümkün olan en erken noktada (NIC sürücüsünün içinde) çalışır.sk_buff. Bu şu anlama gelir:

  • Yerel XDP: Sürücü XDP'yi yerel olarak destekler (Intel i40e, Mellanox mlx5, vb.). En hızlı — sürücü bağlamında çalışır.
  • Genel XDP: Yerel desteği olmayan sürücüler için geri dönüş. Sonra çalışırsk_bufftahsis - hala iptables'tan daha hızlı, ancak yerel kadar hızlı değil.
  • Yüklenen XDP: Program NIC ASIC'in kendisinde çalışır. SmartNIC donanımı gerektirir (örn. Netronome). Sıfır CPU maliyeti.

Bir XDP programı beş karardan birini döndürür:

İade KoduAksiyon
XDP_DROPPaketi hemen bırakın — en düşük gecikme süresiyle atma
XDP_PASSNormal ağ yığınına geçin
XDP_TXAynı arayüzü geri gönder (geri dön)
XDP_REDIRECTBaşka bir arayüze veya AF_XDP soketine yönlendir
XDP_ABORTEDHata yolu — izleme olayıyla birlikte bırakın

3. XDP Paket Bırakma Örneği

Aşağıdaki program, bir eBPF haritasında depolanan bir kaynak IP'den tüm UDP paketlerini bırakarak kullanıcı alanı kontrol düzleminin çalışma zamanında engellenenler listesini güncellemesine olanak tanır.

// xdp_drop_udp.c — Drop UDP from IPs in a BPF map
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>

// 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";
Sınır kontrolü zorunludur.eBPF doğrulayıcı, belleğe bunun ötesinde erişen programları reddederdata_end. Her işaretçi aritmetik işleminin ardından bir sınır kontrolü yapılmalıdır, aksi takdirde program yüklenmeyecektir.

Şununla yükleyin ve ekleyin:ip:

# 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: Çekirdek Atlaması

AF_XDPXDP'lerle birleştirilmiş bir soket ailesidirXDP_REDIRECTKarar, paket başına çekirdek katılımı olmadan paketleri doğrudan bir kullanıcı alanı bellek bölgesine (UMEM) iletir. Bu, eBPF ekosisteminin DPDK'nın çekirdek atlama modeline cevabıdır.

Anahtar bileşenler:

  • UMEM: Çerçevelere bölünmüş, kullanıcı alanı kayıtlı bir bellek bölgesi. Paylaşılan bellek aracılığıyla çekirdek ve kullanıcı alanı arasında paylaşılır.
  • Yüzükler: Soket başına dört kilitsiz halka: Doldurma (kullanıcı alanı → serbest çerçeveli çekirdek), Tamamlama (çekirdek → TX yapılan çerçevelerle kullanıcı alanı), RX halkası (çekirdek → alınan çerçevelerle kullanıcı alanı), TX halkası (kullanıcı alanı → gönderilecek çerçevelerle çekirdek).
  • Sıfır kopyalama modu: Sürücü destekliyorsa, çerçeveler herhangi bir kopya olmadan aktarılır; yalnızca bir işaretçi aktarımı.

AF_XDP, DPDK'nın operasyonel karmaşıklığı olmadan hat hızında özel paket işleme için idealdir (büyük sayfalar yoktur, temel kullanım için CPU sabitlemesi gerekmez).

5. tc BPF: Trafik Şekillendirme ve Filtreleme

tc(trafik kontrolü) BPF programlarıclsactqdisc ve giriş veya çıkışta çalışabilir. XDP'den farklı olarak, görüntünün tamamını görüyorlarsk_buffve soket meta verilerine, VLAN'lara ve tünel başlıklarına erişebilir.

// tc_mark.c — Mark packets with DSCP EF (46) for VoIP traffic on port 5060
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>

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. eBPF Haritalarıyla Hız Sınırlaması

eBPF haritaları durum bilgisi olan işlemeyi mümkün kılar. Aşağıdaki model, bir sunucuda depolanan bir belirteç kümesini kullanarak kaynak başına IP hızı sınırlamasını uygular.BPF_MAP_TYPE_LRU_HASH:

// 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. bpftool ve bpftrace İç Gözlemi

Canlı eBPF programlarıyla çalışmak için iki temel araç:

# 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. Karşılaştırma: eBPF/XDP, DPDK ve RDMA

ÖzellikeBPF/XDPDPDKRDMA
Çekirdek katılımıMinimum (sürücüde XDP)Yok (tam bypass)Yok (RDMA NIC)
Bellek modeliStandart + AF_XDP UMEMÇok büyük sayfalar gerekliKayıtlı hafıza bölgeleri
Maksimum verim~100 Gbps yerel XDP>100 Gbps200+ Gb/sn (InfiniBand)
CPU kullanımıDüşük (olay odaklı)Yüksek (meşgul yoklama çekirdekleri)Sıfıra yakın (yüksüz)
Operasyon karmaşıklığıDüşük — standart araçlarYüksek - özel çekirdekler, devasa sayfalarYüksek — yapı yönetimi
Kullanım örneğiDDoS azaltma, LB, gözlemlenebilirlikSanal yönlendiriciler, NFV, paket oluşturmaDepolama (NVMe-oF), HPC MPI
DilKısıtlı C / PasC / PasFiiller API'si (C)
Temel kural:eBPF/XDP ile başlayın; mevcut çekirdek araçlarıyla entegre olur, özel bir donanım veya büyük sayfalar gerektirmez ve 100 Gbps'nin altındaki yüksek performanslı ağ kullanım durumlarının çoğunu yönetir. Yalnızca özel CPU çekirdeklerine ihtiyaç duyduğunuzda ve herhangi bir çekirdek planlama yükünü tolere edemediğinizde DPDK'ya geçin.