rust-ebpf
1
总安装量
1
周安装量
#46687
全站排名
安装命令
npx skills add https://github.com/huiali/rust-skills --skill rust-ebpf
Agent 安装分布
trae
1
qoder
1
trae-cn
1
claude-code
1
antigravity
1
Skill 文档
eBPF ä¸å æ ¸ç¼ç¨
æ ¸å¿é®é¢
å¦ä½å¨ä¸ä¿®æ¹å æ ¸çæ åµä¸å®å ¨å°æ©å±å æ ¸åè½ï¼
eBPF æä¾å¨å æ ¸ä¸å®å ¨æ§è¡ç¨æ·æä»£ç çè½åã
eBPF vs å æ ¸æ¨¡å
| ç¹æ§ | eBPF | å æ ¸æ¨¡å |
|---|---|---|
| å®å ¨éªè¯ | ç¼è¯æ¶éªè¯ | éè¦æå¨å®¡æ¥ |
| ç¨³å®æ§ | 稳å®ç API | API å¯è½åå |
| æ§è½ | 峿¶ JIT | é«ä½æé£é© |
| å´©æºé£é© | æé | å¯è½å´©æºå æ ¸ |
| è¯è¨æ¯æ | C, Rust | C, Rust |
Aya åº
// ä½¿ç¨ aya å建 eBPF ç¨åº
use aya::{maps::Map, programs::Xdp, Bpf};
use aya::maps::ArrayMap;
use std::sync::atomic::{AtomicU64, Ordering};
static PACKET_COUNT: AtomicU64 = AtomicU64::new(0);
#[repr(C)]
struct PacketStat {
rx_packets: u64,
tx_packets: u64,
}
#[panic_handler]
fn panic(_info: &std::panic::PanicInfo) -> ! {
unsafe { core::hint::unreachable_unchecked() }
}
eBPF Map
// eBPF å
±äº«æ°æ®æ å°
use aya::maps::HashMap;
use aya::util::online_cpus;
// å叿 å°
let mut hash_map = HashMap::try_from(
(prog.fd().as_ref(), "packet_counts")
)?;
for cpu in online_cpus()? {
hash_map.insert(cpu as u32, 0u64, 0)?;
}
// æ°ç»æ å°
use aya::maps::Array;
let mut array = Array::try_from(
(prog.fd().as_ref(), "config")
)?;
array.insert(0, 64u32, 0)?; // æ¹é大å°
// PERCPU æ å° - æ¯ CPU 计æ°å¨
use aya::maps::PerCpuHashMap;
let mut per_cpu = PerCpuHashMap::try_from(
(prog.fd().as_ref(), "per_cpu_stats")
)?;
for cpu in online_cpus()? {
per_cpu.insert(cpu as u32, &0u64, 0)?;
}
XDP ç¨åº
// XDP (Express Data Path) ç¨åº
use aya::programs::XdpContext;
use aya_bpf::helpers::bpf_redirect;
use aya_bpf::macros::xdp;
use aya_bpf::programs::XdpProgram;
#[xdp]
pub fn xdp_packet_counter(ctx: XdpContext) -> u32 {
let _ = ctx;
// 计æ°
PACKET_COUNT.fetch_add(1, Ordering::SeqCst);
// è¿ååå§æ¥å£
bpf_redirect(ctx.ifindex(), 0)
}
Tracepoint
// è·è¸ªç¹ç¨åº
use aya_bpf::macros::tracepoint;
use aya_bpf::programs::TracepointContext;
#[tracepoint(name = "sys_enter_open")]
pub fn trace_sys_enter_open(ctx: TracepointContext) -> u32 {
let _ = ctx;
0
}
kprobe/kretprobe
// å
æ ¸æ¢é
use aya_bpf::macros::{kprobe, kretprobe};
use aya_bpf::programs::KprobeContext;
#[kprobe(name = "tcp_v4_connect", fn_name = "tcp_v4_connect_enter")]
pub fn tcp_v4_connect_enter(_ctx: KprobeContext) -> u32 {
0
}
#[kretprobe(name = "tcp_v4_connect", fn_name = "tcp_v4_connect_exit")]
pub fn tcp_v4_connect_exit(_ctx: KprobeContext) -> u32 {
0
}
ç¨æ·æå è½½å¨
// 宿´ç eBPF å è½½å¨
use aya::Bpf;
use aya::maps::HashMap;
use std::net::Ipv4Addr;
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
// å è½½ eBPF ç¨åº
let mut bpf = Bpf::load("ebpf.o")?;
// è·åç¨åº
let program: &mut Xdp = bpf.program_mut("xdp_packet_counter")
.unwrap()
.try_into()?;
program.load()?;
program.attach("eth0", XdpFlags::default())?;
// å建æ å°
let mut blocked_ips: HashMap<_, Ipv4Addr, u8> = HashMap::try_from(
(bpf.map("blocked_ips")?.fd().as_ref(), "blocked_ips")
)?;
blocked_ips.insert(Ipv4Addr::new(1, 2, 3, 4), 1, 0)?;
// æç»çæ§
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
// 读åç»è®¡æ°æ®
}
}
Tail Call
// å°¾è°ç¨ - é¾å¼ç¨åºè°ç¨
// ç¨åº 1
#[xdp(name = "packet_parser")]
pub fn packet_parser(ctx: XdpContext) -> u32 {
let _ = ctx;
// è§£æå
头ï¼å³å®ä¸ä¸ä¸ªç¨åº
aya_bpf::helpers::bpf_tail_call(ctx, &JUMP_TABLE, 0)
}
// ç¨åº 2
#[xdp(name = "packet_filter")]
pub fn packet_filter(ctx: XdpContext) -> u32 {
let _ = ctx;
aya_bpf::programs::XdpAction::Pass.as_u32()
}
// ç¨æ·æè®¾ç½®
let mut jump_table: ProgramArray = ProgramArray::try_from(
(bpf.map("jump_table")?.fd().as_ref(), "jump_table")
)?;
jump_table.set(0, bpf.program("packet_filter").unwrap().fd(), 0)?;
æ§è½ä¼å
| ä¼åç¹ | æ¹æ³ |
|---|---|
| Map è®¿é® | æ¹é读åï¼åå°ç³»ç»è°ç¨ |
| å°¾è°ç¨ | æ§å¶é¾é¿åº¦ï¼é¿å è¿å¤è·³è½¬ |
| æ°æ®ç»æ | ä½¿ç¨æ°ç»èéåå¸è¡¨ |
| éç«äº | ä½¿ç¨ PerCPU map |
ä¸å ¶ä»æè½å ³è
rust-ebpf
â
ââ⺠rust-embedded â no_std, å
æ ¸æ¥å£
ââ⺠rust-performance â æ§è½åæ
ââ⺠rust-unsafe â åºå±å
åæä½