Linux eBPF ve XDP Ağ Oluşturma Başlangıç Programı

// 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

Özellik eBPF/XDP DPDK RDMA
Çekirdek katılımı Minimum (sürücüde XDP) Yok (tam bypass) Yok (RDMA NIC)
Bellek modeli Standart + AF_XDP UMEM Çok büyük sayfalar gerekli Kayıtlı hafıza bölgeleri
Maksimum verim ~100 Gbps yerel XDP >100 Gbps 200+ 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çlar Yüksek - özel çekirdekler, devasa sayfalar Yüksek — yapı yönetimi
Kullanım örneği DDoS azaltma, LB, gözlemlenebilirlik Sanal yönlendiriciler, NFV, paket oluşturma Depolama (NVMe-oF), HPC MPI
Dil Kısıtlı C / Pas C / Pas Fiiller 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.