Linux eBPF & XDP Networking Primer
Linux eBPF & XDP Networking Primer
Практическо ръководство за BPF програми, XDP куки, и ядро-байпас пакет обработка за мрежови инженери.
1. Какво представлява eBPF?
eBPF (разширен Berkeley Packet филтър) е подсистема Linux ядро, която ви позволява да стартирате пясъчни програми вътре в ядрото без промяна на изходния код на ядрото или модули за зареждане ядро. Програмите се проверяват от проверяващ байткод на ядрото преди изпълнението, като се гарантира безопасността.
За работа в мрежа, eBPF програми се прикрепят към в мрежовия стек на ядрото и могат да инспектират, променят, пренасочат, или капка пакети. Ключовото предимство пред или ядро модули е производителност и програмируемост: eBPF програми са JIT-компилирани към родния код и могат да споделят държавата чрез (клавиатура-стойност магазини, споделени между ядрото и потребителското пространство).
| Кук | Местоположение | Latency | Използване на случай |
|---|---|---|---|
| XDP | NIC драйвер, преди разпределяне на sk buff | Най-ниско | DDos капка, балансиране на товара |
| unit synonyms for matching user input | След разпределяне на sk buff | Ниско | Образуване, маркиране, пренасочване |
| филтър за гнездо | Socket приема пътя | Среден | филтриране тип tcpdump |
| kprobe/tracepoint | Вписване/излизане на функцията на обвивката | Varies | Наблюдение, проследяване |
2. XDP точки кука
XDP (eXpress Data Path) програми стартират в най-ранната възможна точка в мрежата стъблото в NIC драйвера, преди ядрото да задели Това означава:
- Native XDP
-
Общ XDP
sk_buff - Разтоварен XDP
Програмата XDP връща една от петте присъди:
| Код за връщане | Действие |
|---|---|
XDP_DROP |
Капка опашчица веднага! Най-ниската латентна маневра |
XDP_PASS |
Преминава се към нормален мрежов стек |
XDP_TX |
Предавам обратно същия интерфейс (отскачам) |
XDP_REDIRECT |
Пренасочване към друг интерфейс или AF XDP гнездо |
XDP_ABORTED |
Грешка на пътя спадане с следа събитие |
3. XDP Packet Drop Пример
Следващата програма пуска всички UDP пакети от източник IP съхраняван в eBPF карта, позволявайки на самолет за контрол на потребителското пространство да актуализира блок списъка по време на изпълнение.
// xdp_drop_udp.c — Drop UDP from IPs in a BPF map
#include
#include
#include
#include
#include
// 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";
data_end
Зареждане и закрепване с :
# 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: Kernel-Bypass
AF_XDPXDP_REDIRECT
Ключови компоненти:
- UMEM
- Пръстени
- Режим "нулакопия"
AF XDP е идеален за обработка на потребителски пакети със скорост на линия без оперативната сложност на DPDK (без огромни страници, без CPU приставка, необходима за основна употреба).
5. tc BPF: Формация на трафика и филтриране
tcclsactsk_buff
// tc_mark.c — Mark packets with DSCP EF (46) for VoIP traffic on port 5060
#include
#include
#include
#include
#include
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 карти
eBPF карти позволяват щатно обработване. Следният модел се прилага за процент източник-IP, ограничаващ използването на символична кофа, съхранявана в :
// 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 & bpftrace Introspection
Два основни инструмента за работа с живи eBPF програми:
# 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. Сравнение: eBPF/XDP срещу DDDK срещу RDMA
| Характеристики | eBPF/XDP | DPDK | RDMA |
|---|---|---|---|
| Участие на kernel | Минимално (XDP в водача) | Няма (пълен байпас) | Няма (RDMA NIC) |
| Модел на памет | Стандарт + AF XDP UMEM | Изискване на подобрения | Регистрирани региони на памет |
| Макс пас | ~100 Gbps роден XDP | > 100 Gbps | 200+ Gbps (InfiniBand) |
| Използване на процесор | Ниско (задвижвано от събитие) | Високи (заети-полови ядра) | Близо до нулата (изнесено) |
| Сложност на операциите | Ниски стандартни инструменти | Високи, посветени ядра, огромни страници | Високо управление на тъкани |
| Използване на случай | DDOS смекчаване, LB, обсерватория | Виртуални рутери, NFV, пакетен ген | Съхранение (NVMe- oF), HPC MPI |
| Език | Ограничено C / Ръст | C / Ръст | Гръбнаци API (C) |