Linux eBPF & XDP Networking Primer
Linux eBPF 和 XDP 網路入門程式
BPF 程式的實用指導, XDP 勾通, 有網絡工程師用內核- bypass包處理 。
1. 什么是eBPF?
eBPF (Extended Berkeley Packet Filter) 是一款 Linux 內核子系統, 它可以讓您在內核中執行沙盒化的程序而无需修改內核源碼或載入內核模組. 在執行前由內核字元碼驗證人去驗證程序,
就網路而言, EBPF 程式被附加到 在內核的網路堆疊中可以檢查、修改、重定向或放放包。 有相關優勢 或內核模組是性能和可程式性: eBPF 程式由 JIT 編譯成本地代碼并可以通訊相通 (內核和用戶空間相通的金鑰值商店).
| 虎克 | 位置 | 相關 | 使用大小寫 |
|---|---|---|---|
| XDP 通訊錄 | 在 sk buff 分配前的 NIC 驅動程式 | 最低 | DDoS 下放, 載入平衡 |
| tc入室/入室/入室/入室 | sk buff 分配后 | 低 | 交通相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相相相相相相接相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相 |
| 套接字过滤器 | 套接字接收路徑 | 中 | tcpdump 式的滤波 |
| kprobe/ 追蹤點 | 內核函數出入口 | 有變數 | 二.可觀察性、可追蹤性 |
2. XDP 胡克點
XDP (eXpress Data Path) 程式在網路堆栈中最先跑出 : 在 NIC 驅動程式中, 在內核分出一個前 。即:
- 原生 XDP
-
一般 XDP
sk_buff - 已卸下 XDP
XDP 程式回傳了五項判決中的一项:
| 返回代碼 | 動作 |
|---|---|
XDP_DROP |
即時放放包- 最小空間丟棄 |
XDP_PASS |
傳到正常的網路堆栈 |
XDP_TX |
傳出同樣相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相相關相關相通相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相 |
XDP_REDIRECT |
重定向到另一個介面或 AFQQDP 套接字 |
XDP_ABORTED |
出錯路徑- 有追蹤事件放入 |
3. XDP 包放出示例
以下程式從被儲存在 eBPF 地圖中的源碼 IP 中取出所有 UDP 包, 讓用戶空間控制平面在跑取時更新封鎖列表 。
// 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. AFQDP:克能-比帕斯
AF_XDPXDP_REDIRECT
主要元件:
- 穆姆
- 戒指
- 零取出模式
AFQQDP 在沒有 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地圖能有狀態處理 。 以下樣式執行每源碼相關速率限制 : :
// 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相對
| 地貌 | eBPF/XDP | DPDK (德文) | (RDMA) (德語). |
|---|---|---|---|
| C. 核心参与 | 最小 (驅動程式中的 XDP) | 無 (完全绕行) | 無 (RDMA NIC) |
| 記憶模型 | 標準 + AF XDP UMEM | 需要大頁 | 已登入的回憶區域 |
| 最大通量 | ~100 Gbps 本地 XDP | > 100克/秒 | 二百多克( InfiniBand) |
| CPU用法 | 低 (由事件所驱动) | 高 (大便- 通通芯) | 接近零 (已下載) |
| 外觀複雜度 | 低等- 標準工具 | 高 -- -- 有專心的核心,大頁 | 高 -- -- 织物管理 |
| 使用大小寫 | DDoS 缓解、 LB、可觀性 | NFV 虛擬路由器 | 儲存 (NVMe- oF), HPC MPI |
| 語言 | 有限制 C / 有限制 | C / 粗 | 有位數 API (C) |
指指法: