Linux eBPF & XDP Networking Primer
data_end. يجب أن يتبع كل عملية حسابية للمؤشر فحص للحدود وإلا فلن يتم تحميل البرنامج.تحميل وإرفاق مع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: تجاوز النواة
AF_XDPهي عائلة مقابس مدمجة مع XDP'sXDP_REDIRECTالحكم، يسلم الحزم مباشرة إلى منطقة ذاكرة مساحة المستخدم (UMEM) دون تدخل kernel لكل حزمة. هذه هي إجابة نظام eBPF البيئي لنموذج تجاوز kernel الخاص بـ DPDK.
المكونات الرئيسية:
- أوميم: منطقة ذاكرة مسجلة في مساحة المستخدم مقسمة إلى إطارات. مشتركة بين kernel ومساحة المستخدم عبر الذاكرة المشتركة.
- خواتم: أربع حلقات خالية من القفل لكل مقبس: ملء (مساحة المستخدم ← نواة مع إطارات مجانية)، إكمال (نواة ← مساحة مستخدم مع إطارات منتهية بـ TX)، حلقة RX (نواة ← مساحة مستخدم مع إطارات مستلمة)، حلقة TX (مساحة مستخدم ← نواة مع إطارات للإرسال).
- وضع النسخ الصفري: إذا كان برنامج التشغيل يدعمه، فسيتم نقل الإطارات دون أي نسخة — مجرد تمرير المؤشر.
يعد AF_XDP مثاليًا لمعالجة الحزم المخصصة بمعدل الخط دون التعقيد التشغيلي لـ DPDK (لا توجد صفحات ضخمة، ولا يلزم تثبيت وحدة المعالجة المركزية للاستخدام الأساسي).
5. tc BPF: تشكيل وتصفية حركة المرور
tc(التحكم في حركة المرور) يتم إرفاق برامج BPF فيclsactqdisc ويمكن تشغيله عند الدخول أو الخروج. على عكس XDP، فإنهم يرون كاملاًsk_buffويمكنه الوصول إلى بيانات تعريف المقبس وشبكات VLAN ورؤوس الأنفاق.
// 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
تتيح خرائط eBPF المعالجة ذات الحالة. يطبق النمط التالي تحديد معدل لكل مصدر IP باستخدام مجموعة الرمز المميز المخزنة في ملف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 & bpftrace الاستبطان
أداتان أساسيتان للعمل مع برامج 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 مقابل DPDK مقابل RDMA
| ميزة | إيببف/XDP | دي بي دي كيه | آر دي إم إيه |
|---|---|---|---|
| تورط النواة | الحد الأدنى (XDP في برنامج التشغيل) | لا شيء (تجاوز كامل) | لا يوجد (RDMA NIC) |
| نموذج الذاكرة | قياسي + AF_XDP UMEM | مطلوب صفحات ضخمة | مناطق الذاكرة المسجلة |
| ماكس الإنتاجية | ~100 جيجابت في الثانية XDP الأصلي | > 100 جيجابت في الثانية | 200+ جيجابت في الثانية (InfiniBand) |
| استخدام وحدة المعالجة المركزية | منخفض (يعتمد على الحدث) | عالية (مراكز الاستطلاع المزدحمة) | بالقرب من الصفر (تفريغ) |
| تعقيد العمليات | منخفض - الأدوات القياسية | عالية - نوى مخصصة، صفحات ضخمة | عالية - إدارة النسيج |
| حالة الاستخدام | تخفيف هجمات DDoS، LB، إمكانية الملاحظة | أجهزة التوجيه الافتراضية، NFV، جنرال الحزم | التخزين (NVMe-oF)، HPC MPI |
| لغة | مقيد ج/ الصدأ | ج/ الصدأ | واجهة برمجة تطبيقات الأفعال (C) |