XDP i eBPF: filtracja pakietów nowej generacji dla serwerów gamingowych
Kiedy na twój serwer Minecraft przylatuje DDoS 50 milionów pakietów na sekundę, iptables nie pomoże. Nie dlatego, że jest zły. Tylko dlatego, że działa za wysoko w stosie sieciowym Linuksa, żeby poradzić sobie z takim strumieniem. Każdy pakiet przechodzi przez dziesiątki warstw jądra, zanim iptables w ogóle go zobaczy. Do tego momentu zasoby CPU są już wydane.
Jest inne podejście. XDP (eXpress Data Path) pozwala przechwycić pakiet na poziomie sterownika karty sieciowej, zanim jądro Linux zacznie go obsługiwać. A eBPF (extended Berkeley Packet Filter) pozwala napisać program, który rozstrzygnie los tego pakietu w nanosekundach. Przepuścić, zdropować, przekierować.
Ta technologia jest już używana na produkcji u Cloudflare, Meta, Netflix do ochrony przed DDoS. I właśnie jej używamy w MineGuard do filtracji ruchu do serwerów gamingowych.
Co to jest eBPF
eBPF to technologia pozwalająca uruchamiać programy użytkownika bezpośrednio wewnątrz jądra Linux. Nie moduły jądra (które mogą zabić system przy błędzie), tylko programy w specjalnej piaskownicy. Jądro weryfikuje każdy program eBPF przed załadowaniem: sprawdza, że nie ma nieskończonych pętli, wyjść poza granice pamięci, dzielenia przez zero.
Jeśli program nie przeszedł weryfikacji - nie załaduje się. Jeśli przeszedł - działa z prędkością natywnego kodu jądra, bo kompilator JIT (Just-In-Time) tłumaczy go na instrukcje maszynowe konkretnego procesora.
W zasadzie eBPF zamienił jądro Linux w programowalną platformę. Wcześniej, żeby dodać logikę obsługi pakietów w jądrze, trzeba było pisać kernel module w C, kompilować go pod konkretną wersję jądra i ryzykować kernel panic przy każdym błędzie. Z eBPF piszesz mały program, jądro gwarantuje jego bezpieczeństwo i wykonuje się z minimalnym narzutem.
Kluczowe właściwości eBPF:
- Bezpieczeństwo. Weryfikator jądra sprawdza każdą instrukcję przed załadowaniem
- Szybkość. Kompilacja JIT do natywnego kodu maszynowego
- Elastyczność. Program można zaktualizować bez restartu systemu
- Izolacja. Crash programu eBPF nie powala jądra
Co to jest XDP
XDP (eXpress Data Path) to hook (punkt przechwytywania) w Linux, znajdujący się na najniższym poziomie stosu sieciowego, w sterowniku karty sieciowej. Kiedy karta sieciowa odbiera pakiet, XDP pozwala go obsłużyć ZANIM jądro stworzy strukturę sk_buff, ZANIM netfilter, ZANIM conntrack, ZANIM iptables.
Czemu to zasadnicze? Bo większość kosztów CPU przy obsłudze pakietów przypada właśnie na wyższe warstwy stosu. Tworzenie sk_buff, przechodzenie przez łańcuchy netfilter, aktualizacja tablic conntrack - wszystko to zajmuje setki nanosekund na każdy pakiet. Przy ataku DDoS milionów pakietów na sekundę te "setki nanosekund" zamieniają się w 100% obciążenie CPU.
XDP działa tam, gdzie pakiet to jeszcze po prostu zestaw bajtów w buforze DMA. Żadnej alokacji pamięci, żadnego conntracka. Program XDP dostaje wskaźnik na surowe dane pakietu i podejmuje jedną z czterech decyzji:
- XDP_DROP - odrzucić pakiet. Najszybsze działanie, pakiet nigdy nie trafi do jądra
- XDP_PASS - przekazać pakiet dalej do stosu jądra do zwykłej obsługi
- XDP_TX - wysłać pakiet z powrotem przez ten sam interfejs (przydatne dla SYN cookies)
- XDP_REDIRECT - przekierować pakiet na inny interfejs lub do innego programu
Oto uproszczony przykład programu XDP w C:
SEC("xdp")
int xdp_filter(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_DROP;
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_DROP;
// Sprawdzamy blocklistę
__u32 src_ip = ip->saddr;
if (bpf_map_lookup_elem(&blocklist, &src_ip))
return XDP_DROP;
// Sprawdzamy rate limit
struct rate_info *rate = bpf_map_lookup_elem(&rate_counters, &src_ip);
if (rate && rate->pps > MAX_PPS_PER_IP)
return XDP_DROP;
return XDP_PASS;
}
Ten kod wykona się w 50-100 nanosekund. Dla porównania: przejście pakietu przez pełny stos iptables zajmuje 2000-5000 nanosekund.
Czemu iptables jest za wolny
Żeby zrozumieć przewagę XDP, trzeba spojrzeć na drogę pakietu przy użyciu iptables.
Kiedy pakiet przychodzi na kartę sieciową, dzieje się następujące:
- NIC kładzie pakiet do ring buffera przez DMA
- Jądro dostaje przerwanie, uruchamia NAPI polling
- Tworzy się struktura
sk_buff(alokacja pamięci) - Pakiet przechodzi przez ingress qdisc (traffic control)
- netfilter: tablica raw, łańcuch PREROUTING
- conntrack: wyszukiwanie w tablicy hashowej połączeń, tworzenie nowego wpisu
- netfilter: tablica mangle, łańcuch PREROUTING
- Routing decision (wyznaczenie trasy)
- netfilter: tablica filter, łańcuch INPUT
- iptables: sprawdzenie KAŻDEJ reguły po kolei
Dopiero na kroku 10 iptables decyduje: DROP czy ACCEPT. Ale do tego momentu jądro już wydało CPU na kroki 1-9. Przy ataku DDoS 90% pakietów to śmieci, a wydawanie na każdy z nich pełnej drogi przez stos jest bez sensu.
XDP działa między krokami 1 a 2. Pakiet jest przechwytywany przed utworzeniem sk_buff, przed conntrack, przed netfilter. Jeśli trzeba go zdropować - jest dropowany natychmiast, bez żadnej alokacji pamięci.
Liczby
Prawdziwe testy pokazują różnicę w rzędach wielkości:
| Metoda | Pakietów/s (1 rdzeń) | Opóźnienie |
|---|---|---|
| iptables | ~1 mln | 2-5 μs |
| nftables | ~2 mln | 1-3 μs |
| XDP (generic) | ~5 mln | 0.5-1 μs |
| XDP (native) | ~14 mln | 0.05-0.1 μs |
XDP w trybie native (wspieranym przez sterownik NIC) obsługuje 14 razy więcej pakietów niż iptables. Na serwerze z 8 rdzeniami to teoretycznie 100+ milionów pakietów na sekundę. Dla porównania: większość ataków DDoS na serwery Minecraft generuje od 5 do 50 milionów pps.
BPF maps: stan do filtracji
Sam drop po IP nie wystarczy. Prawdziwa ochrona wymaga stanu: liczników pakietów, blocklist, informacji o sesjach. W eBPF są do tego BPF maps - struktury danych współdzielone między programem eBPF w jądrze a aplikacją user-space.
Główne typy map:
Hash map - klasyczna tablica hashowa. Idealna dla blocklist IP:
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 100000);
__type(key, __u32); // IP address
__type(value, __u64); // timestamp
} blocklist SEC(".maps");
LRU hash - tablica hashowa z automatycznym wypieraniem starych wpisów. Dobrze się nadaje do rate limitingu:
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 1000000);
__type(key, __u32); // IP address
__type(value, struct rate_info); // packets count, timestamp
} rate_counters SEC(".maps");
Per-CPU array - tablica z osobną kopią dla każdego rdzenia CPU. Bez blokad, maksymalna szybkość:
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, struct stats);
} packet_stats SEC(".maps");
Aplikacja user-space może w czasie rzeczywistym aktualizować blocklistę, czytać statystyki, zmieniać progi rate limitingu. Program eBPF w jądrze podchwyca zmiany bez restartu. To kluczowa różnica od iptables, gdzie dodanie 10 000 reguł zajmuje sekundy i blokuje obsługę pakietów.
Tryby pracy XDP
XDP może działać w trzech trybach i różnica między nimi jest znaczna.
Native XDP (XDP_FLAGS_DRV_MODE). Program eBPF wykonuje się wewnątrz sterownika karty sieciowej, przed utworzeniem sk_buff. To najszybszy tryb, dający te 14M+ pps na rdzeń. Ale wymaga wsparcia w sterowniku NIC. Wspierają: Intel i40e/ice, Mellanox mlx4/mlx5, Broadcom bnxt, Amazon ENA, virtio-net. Jeśli twój serwer używa jednego z tych sterowników, dostaniesz maksymalną wydajność.
Generic XDP (XDP_FLAGS_SKB_MODE). Program eBPF wykonuje się po utworzeniu sk_buff, ale przed netfilter. Działa na dowolnym interfejsie sieciowym bez specjalnego wsparcia sterownika. Wydajność jest niższa niż native (około 5M pps), ale wciąż 5 razy wyższa niż iptables. To tryb fallback dla NIC bez natywnego wsparcia.
Offloaded XDP (XDP_FLAGS_HW_MODE). Program eBPF jest ładowany bezpośrednio na SmartNIC i wykonuje się sprzętowo, bez udziału CPU serwera w ogóle. Wspierany przez Netronome NFP i niektóre Mellanox ConnectX-6. Szybkość filtracji jest ograniczona tylko przepustowością portu sieciowego, a CPU jest w pełni wolny do obsługi legalnego ruchu.
Sprawdzić, czy twój NIC wspiera native XDP, można tak:
ethtool -i eth0 | grep driver
# Jeśli driver: i40e, mlx5_core, bnxt_en - native XDP jest dostępny
Jak działa tradycyjna ochrona DDoS
Większość usług ochrony DDoS dla Minecrafta wciąż używa iptables lub nftables jako głównego narzędzia filtracji. Schemat jest prosty: ruch przechodzi przez serwer proxy, na którym zestaw reguł iptables filtruje "złe" pakiety.
Problemy tego podejścia:
Liniowe sprawdzanie reguł. iptables sprawdza reguły po kolei. 1000 reguł w blockliście = 1000 sprawdzeń na każdy pakiet. Z ipset jest lepiej (wyszukiwanie O(1)), ale wciąż przez conntrack i netfilter. A przy ataku DDoS każdy zbędny cykl sprawdzania to stracone mikrosekundy, które sumują się w milisekundy, a potem w stracone pakiety legalnych graczy.
Conntrack overhead. Każde nowe połączenie tworzy wpis w conntrack. Standardowa tablica conntrack mieści 65536 wpisów (można zwiększyć przez nf_conntrack_max), ale przy SYN-floodzie zapełnia się w sekundy i zaczyna dropować legalne połączenia. Jądro pisze w dmesg: "nf_conntrack: table full, dropping packet". Tę mechanikę szczegółowo rozbieraliśmy w artykule o atakach SYN flood na Minecrafta.
Context switches. iptables działa w kontekście softirq, ale każde działanie z regułami (dodanie, usunięcie) wymaga blokad xtables lock. Przy wysokim obciążeniu, kiedy aplikacja user-space próbuje zaktualizować reguły, a jądro równocześnie obsługuje miliony pakietów, powstaje contention. Aktualizacja blocklisty z 10 000 IP przez iptables może zająć kilka sekund, w trakcie których filtracja działa nieprzewidywalnie.
Ograniczona logika. Złożona filtracja (analiza payload pakietów Minecraft, stateful rate limiting, adaptywne progi) w iptables jest albo niemożliwa, albo wymaga protez z modułami u32/string match. Spróbuj napisać regułę iptables, która sprawdza, że przychodzący pakiet TCP zawiera poprawny Minecraft handshake z prawidłową protocol version. To niemożliwe bez dodatkowych modułów jądra.
XDP/eBPF rozwiązuje wszystkie te problemy. Blocklista w BPF hash map to wyszukiwanie O(1) bez conntracka, nawet dla miliona IP. Rate limiting na per-CPU counters to bez blokad, każdy rdzeń CPU pracuje na swojej kopii liczników. Analiza protokołu Minecraft w eBPF to pełny dostęp do danych pakietu na poziomie bajtów. Aktualizacja reguł przez BPF map jest atomowa, bez restartu i bez blokowania obsługi.
Czemu serwery gamingowe potrzebują XDP
Serwery gamingowe, zwłaszcza Minecraft, mają specyficzne wymagania wobec ochrony DDoS.
Niskie opóźnienie. Każda milisekunda opóźnienia jest odczuwalna przez gracza. Jeśli filtr dodaje 5 ms na obsługę pakietu, gracze zauważą lagi. XDP dodaje mniej niż 0.1 ms, co jest niewidoczne nawet przy 100+ online.
Wysokie pps przy atakach. Współczesne ataki DDoS na Minecrafta generują dziesiątki milionów pakietów na sekundę. To nie flood objętościowy (Gbps), tylko packet rate flood, obliczony na przeciążenie CPU serwera. iptables przy takim strumieniu fizycznie nie daje rady. O różnicy między volumetric a packet rate atakami pisaliśmy w artykule o atakach TCP i UDP na Minecrafta.
Ataki botów na protokół. Atakujący imitują Minecraft handshake, wysyłając poprawne SYN, potem pakiety login. iptables nie umie analizować zawartości pakietów Minecrafta. Program eBPF może rozebrać payload na poziomie jądra i zdropować fałszywy handshake zanim dotrze do userspace.
Szybkie przełączanie reguł. W trakcie ataku profil ruchu zmienia się co sekundy. Nowe IP, nowe wzorce, adaptywne botnety. BPF maps pozwalają aktualizować blocklisty i liczniki natychmiast, bez restartu filtru.
W MineGuard używamy XDP/eBPF jako pierwszego poziomu filtracji. Pakiety, które nie przeszły weryfikacji na poziomie XDP, są dropowane jeszcze przed utworzeniem sk_buff. Tylko legalny ruch jest przekazywany wyżej po stosie, gdzie przechodzi dodatkową walidację protokołu Minecraft.
Konkretny przykład: przy ataku 30M pps na jeden z chronionych serwerów filtr XDP dropuje 99.7% pakietów na poziomie sterownika. Do wyższych warstw stosu przechodzi mniej niż 100 000 pakietów na sekundę - zwykły legalny ruch od prawdziwych graczy. CPU serwera przy tym jest obciążony na 15-20%, gracze nie zauważają ataku w ogóle. Przy użyciu iptables ten sam atak wywołałby 100% obciążenie CPU i pełną niedostępność serwera.
Prawdziwe zastosowanie: kto używa eBPF
XDP/eBPF to nie eksperymentalna technologia. Największe firmy używają jej na produkcji.
Cloudflare obsługuje programami eBPF cały ruch przychodzący na swoich edge-serwerach. Ich Magic Firewall jest w pełni zbudowany na XDP, obsługując dziesiątki terabitów na sekundę ataków DDoS.
Meta (Facebook) używa XDP do balansowania obciążenia (Katran) i ochrony DDoS. Ich rozwiązanie obsługuje miliardy pakietów na sekundę na produkcyjnych serwerach.
Netflix stosuje eBPF do analityki sieciowej i ochrony swojej infrastruktury CDN.
Cilium - plugin sieciowy dla Kubernetes, w pełni zbudowany na eBPF. Zastępuje iptables do trasowania i filtracji w środowiskach kontenerowych.
Trend jest oczywisty: eBPF zastępuje iptables wszędzie tam, gdzie potrzebna jest wysoka wydajność. Branża gamingowa nie jest wyjątkiem. Aktualne dane o atakach DDoS na Minecrafta i używanych metodach ochrony zebraliśmy w przeglądzie trendów ataków DDoS na Minecrafta w 2026 roku.
Ograniczenia XDP/eBPF
Byłoby nieuczciwie mówić tylko o plusach. Technologia ma prawdziwe ograniczenia.
Wersja jądra. XDP wymaga Linux 4.8+, a wiele przydatnych funkcji (BPF_MAP_TYPE_LRU_HASH, bpf_fib_lookup) pojawiło się dopiero w 5.x. Większość hostingów VPS dla Minecrafta wciąż używa jąder 4.x, a nawet 3.x. Na takich jądrach XDP albo nie działa, albo działa w ograniczonym trybie generic.
Wsparcie sterownika. Dla pełnej szybkości XDP potrzebne jest wsparcie w sterowniku NIC (native XDP). Nie wszystkie sterowniki to wspierają. Bez trybu native XDP działa w generic mode, który jest szybszy od iptables, ale nie daje maksymalnych 14M+ pps.
Złożoność developmentu. Napisanie programu eBPF do filtracji pakietów to nietrywialne zadanie. Trzeba znać:
- C (programy eBPF są pisane w podzbiorze C)
- Stos sieciowy Linuksa na poziomie jądra
- Struktury pakietów (Ethernet, IP, TCP/UDP)
- Ograniczenia weryfikatora eBPF (brak pętli o dowolnej długości, ograniczony rozmiar stosu)
- Specyfikę BPF maps i ich concurrency model
- Protokoły serwerów gamingowych (Minecraft protocol do analizy payloadu)
Ograniczenia weryfikatora. Weryfikator eBPF jest surowy. Brak nieskończonych pętli, ograniczony rozmiar stosu (512 bajtów), każdy dostęp do pamięci musi być sprawdzony na granicach. To dobre dla bezpieczeństwa, ale utrudnia pisanie złożonej logiki.
Debug. Debugowanie programów eBPF jest znacznie trudniejsze niż zwykłego kodu. printk w eBPF jest ograniczony, a błędy często pojawiają się jako "verifier rejected program" z kryptycznym komunikatem długości 200 linii. Narzędzia typu bpftool i libbpf pomagają, ale krzywa uczenia jest stroma.
Rozmiar programu. Weryfikator ogranicza rozmiar programu eBPF (do 1 miliona instrukcji w jądrach 5.2+, 4096 w starszych). Do złożonej logiki filtracji trzeba dzielić program na kilka części, połączonych przez tail calls.
Czemu nie można po prostu zainstalować XDP samemu
Teoretycznie XDP to otwarta technologia i każdy może napisać program eBPF do filtracji. W praktyce wymaga to:
- Odpowiedniego jądra (5.10+ do komfortowej pracy)
- NIC ze wsparciem native XDP (Intel i40e, Mellanox mlx5, virtio w niektórych konfiguracjach)
- Głębokiej znajomości stosu sieciowego Linuksa
- Zrozumienia protokołu Minecraft (do filtracji application-level)
- Monitoringu i analityki (żeby rozumieć, co filtr robi)
- Ciągłej aktualizacji (ataki ewoluują, filtry muszą się adaptować)
Napisać bazowy XDP rate limiter to pół dnia pracy. Napisać production-ready filtr DDoS z analizą protokołu Minecraft, adaptywnymi progami, BPF map rotation, graceful reload i monitoringiem to miesiące developmentu.
Dla właściciela serwera Minecraft to mniej więcej jak składanie własnego antywirusa zamiast kupowania gotowego. Technicznie możliwe, ale w praktyce bez sensu. Twój czas lepiej poświęcić na rozwój serwera, a nie na walkę z osobliwościami weryfikatora eBPF.
Dużo skuteczniej jest używać ochrony przed DDoS, w której XDP/eBPF jest już skonfigurowany i zoptymalizowany. Bazowa konfiguracja iptables nadal jest potrzebna jako ostatnia linia obrony na twoim serwerze, ale pierwotną filtrację ruchu warto powierzyć wyspecjalizowanym rozwiązaniom.
Przyszłość: sieci programowalne
XDP i eBPF to nie tylko zastąpienie iptables. To fundamentalna zmiana w podejściu do bezpieczeństwa sieciowego. Zamiast statycznych reguł ("blokuj ten IP", "ogranicz rate do N/s") pojawia się możliwość uruchamiania dowolnej logiki bezpośrednio w jądrze z prędkością transmisji danych.
Co to oznacza dla ochrony DDoS:
Adaptywna filtracja. Program eBPF może w czasie rzeczywistym analizować wzorce ruchu i zmieniać strategię filtracji bez udziału userspace. Wykryła wzrost pakietów SYN z określonej podsieci? Automatycznie włączyła stricter rate limit dla niej.
ML na poziomie jądra. Już pojawiają się projekty uruchamiające proste modele uczenia maszynowego w eBPF do klasyfikacji ruchu. To pozwala wykrywać anomalie w pakietach, które nie są łapane statycznymi regułami.
Hardware offload. Niektóre NIC (SmartNIC) pozwalają ładować programy eBPF bezpośrednio na kartę. W tym przypadku pakiety są filtrowane w ogóle bez udziału CPU serwera. Szybkość filtracji - 100+ Gbps na jednym porcie.
Composable datapath. Kilka programów eBPF można łączyć w łańcuch (tail calls), tworząc modułowy system filtracji. Jeden moduł sprawdza IP, drugi analizuje rate, trzeci rozbiera protokół gry.
Dla branży gamingowej to oznacza, że ataki DDoS, które dziś wydają się nieodparte (100M+ pps), za parę lat będą filtrowane przez jedną SmartNIC w dziesiątych częściach mikrosekundy. A złożone ataki application-level będą wykrywane przez modele ML bezpośrednio w jądrze, bez opóźnień na przekazanie danych do userspace.
XDP/eBPF to nie srebrna kula. To narzędzie, które przy kompetentnym użyciu daje o rząd wielkości lepszą wydajność filtracji niż tradycyjne metody. A w ochronie serwerów gamingowych przed DDoS, gdzie każda mikrosekunda opóźnienia i każdy zbędny pakiet mają znaczenie, ten rząd wielkości jest różnicą między padnięciem serwera a stabilnym 20 TPS pod atakiem.
Chroń swój serwer przed atakami DDoS
Darmowa ochrona z konfiguracją w 5 minut. 1 TB ruchu w zestawie.
Wypróbuj za darmoPowiązane artykuły
Jak skonfigurować własną domenę dla serwera Minecraft
Szczegółowy przewodnik po podłączeniu własnej domeny do serwera Minecraft: rekordy DNS, rekordy SRV, integracja z ochroną MineGuard i typowe błędy.
Serwer UHC od zera: Ultra Hardcore bez regeneracji, poradnik
Jak postawić serwer Ultra Hardcore: gamerule naturalRegeneration, pluginy, scenariusze, border, anticheat i pre-generation świata.
Profiler Spark: jak znaleźć przyczynę lagów na serwerze Minecraft (2026)
Spark zastąpił Timings po 1.21. Instalujemy plugin, odpalamy /spark profiler, czytamy flame-graph i szybko znajdujemy winowajcę: chunk gen, GC, słaby plugin albo redstone.