# eBPF XDP - kernel data-plane _Сеть: L2 / L3 · LinuxLab Knowledge Base_ **TL;DR:** XDP - eBPF-программа на самом раннем RX-hook (до skb_alloc). Actions: DROP, PASS, TX, REDIRECT. Native-mode в драйвере, generic в стеке. AF_XDP - zero-copy в userspace. Use cases - DDoS-фильтр, L4 load balancer, cilium kube-proxy. ## Что такое XDP **XDP (eXpress Data Path)** - наиболее ранний hook для [[ebpf-basics|eBPF]] в receive-pipeline сетевого стека. Программа выполняется **до** того, как ядро аллоцирует `sk_buff` (универсальный буфер пакета) - буквально на raw frame в DMA-области от NIC. Это даёт: - **Минимум CPU/пакет** - 5-10x быстрее чем iptables - **Pre-allocation** - можно дропнуть пакет без аллокации - **Прямой доступ к payload** через указатель Применяется для: - **DDoS filtering** (Cloudflare обрабатывает 10M+ pps на одном CPU) - **L4 load balancer** (Facebook Katran заменил IPVS) - **kube-proxy replacement** в [[cni-plugins|cilium]] - **Sampling/mirroring** для observability ## Где XDP в сетевом стеке ``` NIC → DMA → ┌────────────────┐ │ XDP program │ ← здесь, до skb_alloc │ return ACTION │ └─────┬──────────┘ │ XDP_PASS ▼ ┌────────────────┐ │ skb_alloc │ │ netif_receive │ └─────┬──────────┘ │ ▼ ┌────────────────┐ │ tc-clsact │ ← вторая точка для eBPF (tc/ingress) └─────┬──────────┘ │ ▼ ┌────────────────┐ │ netfilter │ ← iptables / nftables │ (PREROUTING) │ └─────┬──────────┘ │ ▼ routing → socket → app ``` Чем раньше - тем быстрее. XDP < tc-clsact < iptables по latency на пакет. ## XDP actions Программа возвращает один из action-кодов: | Action | Что делает | |--------|------------| | `XDP_DROP` | дропнуть, без аллокации skb (cheapest) | | `XDP_PASS` | передать в обычный сетевой стек | | `XDP_TX` | отправить пакет обратно на тот же интерфейс | | `XDP_REDIRECT` | перенаправить на другой интерфейс или socket | | `XDP_ABORTED` | дроп + tracepoint (debugging) | `REDIRECT` - самое мощное: можно переправить в другой NIC (мост через XDP), в [[veth-pair|veth]] (для container ingress), или в AF_XDP-сокет (kernel bypass). ## Три mode driver-поддержки XDP исполняется быстрее всего, если NIC-драйвер его поддерживает напрямую. Возможные modes: | Mode | Где исполняется | Скорость | |------|-----------------|----------| | **Native (driver)** | в RX hook драйвера, до DMA-completion | максимум | | **Offloaded** | в SmartNIC | ещё быстрее, но редко (Netronome) | | **Generic (skb)** | в `netif_receive_skb` (после skb_alloc) | fallback, медленнее | Native-mode driver'ы (на 2025): mlx5, ixgbe, i40e, ice (Intel), bnxt_en (Broadcom), qede (Marvell), virtio-net (с 5.10+). Если драйвер не поддерживает - грузится в generic mode (`xdpgeneric`), работает но медленнее (skb уже аллоцирован). Проверить: ``` ip -d link show eth0 | grep xdp ``` ## Прицепить XDP-программу Через `bpftool` (libbpf-style): ``` bpftool prog loadall drop_all.bpf.o /sys/fs/bpf/drop type xdp bpftool net attach xdp pinned /sys/fs/bpf/drop dev eth0 ``` Через `ip link` (старее): ``` ip link set dev eth0 xdpdrv obj prog.o sec xdp_prog ``` Снять: ``` ip link set dev eth0 xdpdrv off bpftool net detach xdp dev eth0 ``` Опции `xdpdrv` (driver), `xdpgeneric` (force generic), `xdpoffload` (HW offload). ## Минимальная программа ```c #include #include 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 != bpf_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) return XDP_DROP; return XDP_PASS; } char LICENSE[] SEC("license") = "GPL"; ``` Каждая проверка `> data_end` обязательна - verifier требует доказать, что доступ не выйдет за payload (см. [ebpf-basics](/kb/ebpf-basics.md)). ## tc-clsact - второй hook на уровне TC XDP - только на ingress. Для egress-фильтрации (или если нужен skb, например для conntrack-info) есть **tc-clsact** - eBPF на уровне Traffic Control: ``` tc qdisc add dev eth0 clsact tc filter add dev eth0 ingress bpf da obj prog.o sec ingress tc filter add dev eth0 egress bpf da obj prog.o sec egress ``` Программа в tc видит уже аллоцированный skb, имеет доступ к conntrack-info, но платит skb_alloc cost. Используется в cilium для pod-egress policy. Сравнение: | Hook | Когда | Action | |------|-------|--------| | XDP | до skb | DROP/PASS/TX/REDIRECT | | tc-ingress | после skb_alloc, до netfilter | OK/SHOT/REDIRECT | | tc-egress | перед отправкой | OK/SHOT/REDIRECT | | netfilter (iptables/nft) | в L3 chain | ACCEPT/DROP/MARK/... | ## AF_XDP - zero-copy в userspace XDP может перенаправить пакет в **AF_XDP-сокет** - тогда фрейм приходит userspace **без копирования** через ring-buffer (как DPDK/Netmap, но в kernel-friendly формате). Архитектура: - 4 ring'а: TX, RX, FILL (free buffers), COMPLETION - **UMEM** (User Memory) - shared между app и kernel - kernel пишет packet pointer в RX ring - app читает RX, обрабатывает, кладёт buffer в FILL для повторного использования Throughput: 50+ Mpps на одном ядре, latency меньше микросекунды. Применяется в HFT, telco vRAN, DPI системах. Минусы: - Сложно (нужно управлять UMEM, ring'ами, busy-polling) - Эксклюзивный pinning интерфейса (один app - один queue) - Требует современный driver с zero-copy (mlx5, ice, i40e) ## Real-world use cases ### 1. Cloudflare DDoS-фильтр Cloudflare пишет XDP-программу, которая дропает SYN-flood, UDP amp, malformed-пакеты **до** netfilter'а. На каждом edge-сервере 10M+ pps фильтруется одним CPU. iptables на этом железе = 100% CPU. ### 2. Facebook/Meta Katran - L4 load balancer Katran (open source) принимает все incoming пакеты, делает consistent hash по 5-tuple, выбирает backend, перенаправляет через XDP_TX или XDP_REDIRECT с IP-encapsulation. Заменил IPVS, обрабатывает 10x больше трафика на том же железе. ### 3. Cilium kube-proxy replacement В [[cni-plugins|Cilium]] XDP+tc-eBPF реализуют: - **Service ClusterIP → backend resolution** (заменяет IPVS/iptables) - **NodePort** load balancing - **NetworkPolicy** в eBPF - **Hubble observability** Latency пакета меньше, scale до 10K+ services без iptables-degradation. ## XDP и MTU XDP-программа может **расширить пакет** (`bpf_xdp_adjust_head`, `bpf_xdp_adjust_tail`) - типично для encapsulation (IP-in-IP, VXLAN через XDP). Если расширить за `linkmtu + headroom` - драйвер дропнет. Headroom: 256 байт по умолчанию (можно `bpf_xdp_adjust_head(-N)` чтобы добавить N байт перед пакетом). Связь с [[mtu-and-pmtud|MTU и PMTUD]]: XDP-encap должен учитывать MTU underlay'я, иначе blackhole. ## Pinned maps - shared state между программами XDP-программа держит state в [[ebpf-basics|BPF maps]]. Чтобы карта пережила unload программы и shared'илась между несколькими progs - её **pin** в `/sys/fs/bpf/`: ``` bpftool map pin name allow_list /sys/fs/bpf/allow_list ``` Userspace process читает/обновляет: ``` bpftool map update pinned /sys/fs/bpf/allow_list key 0x01 0x02 0x03 0x04 \ value 0x01 ``` Типичный паттерн: control-plane process поддерживает allow/block list, XDP-программа читает map на каждый пакет. ## Когда что-то пошло не так - **Программа не загружается, "verifier rejected"** - access за `data_end`, или unbounded loop. Запусти с `bpftool prog load ... -L` для verifier-log. - **Native mode не включается** - `ip -d link show` показывает `xdpgeneric` вместо `xdpdrv`. Драйвер не поддерживает - или обновлять kernel + driver, или жить в generic. - **`XDP_TX` шлёт пакет в never-never** - twin-port NIC иногда маршрутизирует TX на тот же физический интерфейс непредсказуемо. Проверь `ethtool -S eth0`. - **Падает throughput при включении XDP** - generic-mode + сложная программа. Профилируй через `perf top -p $(pidof )`. - **AF_XDP socket не получает пакеты** - забыл наполнить FILL ring, или неправильный queue-id (`ethtool -L` для multi-queue). - **Conflict между XDP-программами** - один интерфейс - одна XDP программа. Используй `xdp_dispatcher` (libxdp) для chaining. ## Команды ```bash ip -d link show eth0 | grep -i xdp ``` Показать XDP-режим интерфейса (driver/generic/none) ```bash bpftool net show ``` Все XDP/tc программы прицепленные к интерфейсам ```bash bpftool prog loadall drop.bpf.o /sys/fs/bpf/drop type xdp ``` Загрузить XDP-программу из ELF, pin в /sys/fs/bpf/ ```bash bpftool net attach xdp pinned /sys/fs/bpf/drop dev eth0 ``` Прикрепить загруженную программу к eth0 ```bash ip link set dev eth0 xdpdrv off ``` Снять XDP-программу со всех режимов ```bash tc qdisc add dev eth0 clsact && tc filter add dev eth0 egress bpf da obj e.o sec egress ``` tc-eBPF на egress - альтернативный hook когда XDP мало ```bash perf record -e bpf -p -- sleep 5 ``` Профилировать BPF-программы (cycles, инструкции) ```bash ethtool -G eth0 rx 4096 ``` Увеличить RX-ring - помогает если XDP_DROP не успевает на high-pps ## См. также - [eBPF - программируемый kernel](/kb/ebpf-basics.md) - [CNI plugins - сеть Kubernetes (calico, cilium, flannel)](/kb/cni-plugins.md) - [Linux bridge - программный свитч](/kb/linux-bridge.md) - [veth pair](/kb/veth-pair.md) - [MTU и Path MTU Discovery (PMTUD)](/kb/mtu-and-pmtud.md) - [Conntrack - память Linux о всех сетевых соединениях](/kb/conntrack.md)