İçeriğe geç

(B) Ağ Yönetimi

eBPF XDP ile Linux'de Yuksek Performansli Paket Isleme

6 dk okuma

Linux'un standart ağ yığını paketleri DMA transferinden sonra sk_buff yapısına alır, sonra netfilter, TCP/IP stack ve socket katmanlarından geçirir. Her katman gecikme ve CPU yükü ekler. eBPF tabanlı XDP (eXpress Data Path) paketi NIC sürücüsünde, sk_buff ayrılmadan önce yakalar. Bu erken noktada karar milisaniyeler yerine mikrosaniyelerle alınır.

Linux 4.18 ile gelen bpfilter çekirdek alt sistemi iptables uyumlu kuralları eBPF bayt koduna çevirir. Her paket için sırayla kural zinciri taramak yerine bpfilter kuralları yüklenme sırasında optimize edilmiş bayt koduna derlenir. Paket başına işlem süresi beş ila on kat düşer. Ama bpfilter hâlâ deneysel; NAT, mangle tablosu ve karmaşık eşleştirme uzantıları desteklenmez. Genel amaçlı güvenlik duvarı için nftables ile BPF kombinasyonu daha olgun bir seçenek.

XDP nasil calisiyor

Bir NIC veri çerçevesini DMA ile aldığında sürücü önce descriptor ring'i okur. XDP bu noktada devreye girer. Paket ham tampon bellekte dururken eBPF programı başlar. Çekirdeğin ağ katmanı tarafından ayrıştırılmış meta veri henüz mevcut değildir.

eBPF doğrulayıcısı programı çekirdeğe yüklemeden önce statik analiz yapar. Sonsuz döngüleri, sınır dışı bellek erişimlerini ve geçersiz talimatları reddeder. Bir program sınır denetimi atlarsa doğrulayıcı reddeder ve program yüklenmez.

Üç mod var. Native modda program ağ arabirim kartının kendi sürücüsünde çalışır, en yüksek performansı sunar ama tüm sürücüler desteklemez (ixgbe, i40e, mlx5, virtio_net, veth destekler). Generic modda çekirdeğin ağ yığını XDP programını emüle eder, sk_buff zaten ayrılmıştır ama tüm ağ arabirimleriyle çalışır. Offloaded modda program doğrudan NIC üzerinde çalışır, CPU'ya yük binmez, Netronome NFP ve NVIDIA BlueField gibi SmartNIC'ler destekler.

Dort donus kodu

Bir XDP programı paket üzerinde dört karar verebilir.

XDP_DROP paketi en erken aşamada düşürür. DDoS koruması için temel mekanizma. Yalnızca birkaç yüz CPU çevrimi harcar.

XDP_PASS normal çekirdek ağ yığına gönderir. Program paket içeriğini değiştirdikten sonra bu aksiyonu dönebilir.

XDP_TX paketi aynı NIC üzerinden geri gönderir. ICMP echo-request'i echo-reply'e çevirip aynı arabirimden yollamak gibi senaryolarda kullanılır.

XDP_REDIRECT paketi başka bir NIC'e veya AF_XDP soketine yönlendirir. Load balancer yazılıyorsa bu en iyi seçenektir.

XDP_ABORTED hata durumu, XDP_DROP gibi işlenir ama bir izleme olayı tetikler.

Kod ornegi

XDP programları C dilinde yazılır, clang ile eBPF bayt koduna derlenir. En basit örnek tüm ICMP paketlerini düşürür:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>

struct {
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __uint(key_size, sizeof(__u32));
    __uint(value_size, sizeof(__u64));
    __uint(max_entries, 1);
} icmp_drops SEC(".maps");

SEC("xdp")
int drop_icmp(struct xdp_md *ctx)
{
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;

    if ((void *)(eth + 1) > data_end)
        return XDP_PASS;

    if (eth->h_proto != htons(ETH_P_IP))
        return XDP_PASS;

    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end)
        return XDP_PASS;

    if (ip->protocol == IPPROTO_ICMP) {
        __u32 key = 0;
        __u64 *n = bpf_map_lookup_elem(&icmp_drops, &key);
        if (n)
            __sync_fetch_and_add(n, 1);
        return XDP_DROP;
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

Derleme ve yükleme:

clang -O2 -g -target bpf -c xdp_drop.c -o xdp_drop.o
ip link set dev eth0 xdpgeneric obj xdp_drop.o sec xdp

Geliştirme ortamı için clang, llvm, libbpf, libxdp ve bpftool gerekir. Debian tabanlı sistemlerde:

apt-get install clang llvm libbpf-dev libxdp-dev xdp-tools bpftool

Durumu kontrol etmek için ip link show eth0 çıktısında xdp/id:XXX ibaresi görülür. bpftool prog show çalışan programları listeler.

Rakamlarla performans

Bir sunucu üzerinde test ettiğimde şöyle sonuçlar aldım. İptables aynı koşullarda saniyede 3 milyon paketi zor işliyordu. XDP ile on milyonlarca paketi düşürmek aynı donanımda mümkün. Tabii bu basit drop mantığı için geçerli; karmaşık paket ayrıştırma ekleyince rakamlar düşer.

Modern donanımda native XDP ile saniyede 10 ila 25 milyon paket düşürmek mümkün. Aynı ortamda iptables 0,5 ila 2 milyon paketle sınırlı kalır. XDP bu farkı tamamen erken noktada karar alarak elde ediyor.

Sinirlari

XDP her sorunun çözümü değil. Karmaşık stateful mantık, uygulama katmanı incelemesi veya bağlantı izleme gerektiren senaryolarda nftables veya iptables hâlâ daha uygun. XDP en erken aşamada çalıştığı için bağlantı takibi yapamaz; bağlantı durumu paketlerin sırasını ve durum bilgisini gerektirir ve bu bilgi henüz ayrıştırılmamıştır. Stateful fallback için XDP'yi TC veya netfilter ile kombinasyon kullanmak gerekir.

Üretimde kullanmak için tek başına bpftool yeterli değil. Cilium, Katran, Cloudflare L4Drop gibi projeler bir daemon ile BPF haritasını yönetir. Bu daemon filtre kurallarını haritaya yazar, XDP programı paket başına haritadan okur. Kuralları güncellemek daemon'u yeniden başlatmadan map güncellemesiyle olur.

Bir sunucu yeniden başlattığında XDP programını otomatik yüklemesi gerekiyorsa systemd servisi veya udev kuralı kullanılabilir. Kalıcılık için programı /sys/fs/bpf/ dizinine pinlemek gerekir. Ayrıca her netdev'e yalnızca bir XDP programı bağlanabilir; ikinci bir program yüklenince birincisi sessizce değiştirilir. Birden fazla alt program gerekiyorsa bpf_tail_call ile dağıtım yapılır.

Güvenlik tarafı güçlü. eBPF doğrulayıcısı çekirdeğin kararlılığını tehlikeye atmadan kullanıcı tanımlı kod çalıştırmayı garanti eder. Sınırsız döngü, kontrolsüz bellek erişimi veya geçersiz talimat yüklenmeyi reddeder. Bu mekanizma sayesinde çekirdek modülü yazmadan doğrudan NIC sürücüsüne programlanabilir kanca eklemek mümkün.

Açık kaynak

GitHub projeleri

Tümünü gör
wireguard-server-panel

WireGuard VPN sunucu paneli - İstemci yönetimi, QR kodları ve trafik istatistikleri için kendi sunucunuzda barındırılan web kullanıcı arayüzü (fork, aktif olarak geliştirilmekte)

Go

Laravel-NDFirewall

Rota Kapsamlı Laravel WAF - RCE, SQLi, XSS ve SSRF algılama özelliklerine sahip hafif bir Web Uygulaması Güvenlik Duvarı

PHP

Trustsslroot

Tek komutla çalışan özel PKI oluşturucu - Kendi kendini imzalayan kök CA ve sertifikaları anında oluşturun

Go

node_exporter

Hafif sistem metrikleri aktarıcısı - Güvenli erişim kontrolüne sahip, Linux için durum bilgisi barındırmayan tek ikili dosyalı izleme hizmeti

Rust

ipReconary

IP keşif ve alt ağ analiz aracı - Hızlı ağ taraması ve IP istihbarat toplama

Rust

Cloudfiltred

Cloudflare IP beyaz liste güvenlik duvarı - 80/443 numaralı bağlantı noktalarını yalnızca Cloudflare IP’leriyle sınırlayarak kaynak sunucunuzu doğrudan saldırılara karşı koruyun

Rust

LoadAlertTracker

Hafif sistem yükü izleme arka plan programı - Eşik değerleri aşıldığında Telegram, Discord ve Mattermost üzerinden gerçek zamanlı uyarılar

Rust

ctCertWatch

Sertifika Şeffaflığı günlüğü izleyicisi - Kimlik avı alan adlarını, marka taklitçiliğini ve yetkisiz SSL sertifikalarını gerçek zamanlı olarak tespit eder

Rust

DDNS-FW

Dinamik DNS Güvenlik Duvarı - DDNS aracılığıyla değişen IP adreslerini takip edin ve güvenli erişim kontrolü için güvenlik duvarı kurallarını otomatik olarak güncelleyin

Rust