4 份发布 (2 个重大更改)
0.3.1 | 2021 年 3 月 3 日 |
---|---|
0.3.0 | 2021 年 2 月 22 日 |
0.2.0 | 2021 年 2 月 9 日 |
0.1.0 | 2021 年 1 月 17 日 |
#797 in Unix API
66KB
1.5K SLoC
rxdp
Rust 用于与 XDP 程序和 eBPF 映射交互的绑定。
此库为用户空间与 XDP 程序和 eBPF 映射交互提供了常用基本操作的绑定。它构建在 libbpf-sys 之上。撰写本文时,它只支持所有可能的 eBPF 映射类型的一个子集(请参阅测试目录以了解支持哪些映射)。
先决条件
- Linux 操作系统
- libbpf-sys 依赖关系
示例
从 ELF 文件创建对象
use rxdp;
let obj_path = "/path/to/elf/file";
let obj = match rxdp::XDPObject::new(obj_path) {
Ok(obj) => {
println!("Successfully created object from {}", obj_path);
obj
},
Err(err) => panic!("{:?}", err),
};
设置已固定映射。
已固定映射将从文件系统加载,前提是映射名称与文件系统中的名称匹配。HashSet 中的任何新映射都将设置固定路径,以便在程序加载后自动固定。
let mut pinned_maps = HashSet::new();
pinned_maps.insert("my_map_name".to_string());
obj.pinned_maps(pinned_maps).unwrap();
将对象(程序和映射)加载到内核中。
这将消耗上面创建的 XDPObject
并返回一个 XDPLoadedObject
。
let obj = obj.load().unwrap();
获取 XDP 程序的引用并将其附加到接口
let dev = "eth0";
let flags = rxdp::AttachFlags::SKB_MODE;
let prog = obj.get_program("prog_name").unwrap();
match prog.attach_to_interface(dev, flags) {
Ok(_) => println!("Successfully attached to {}", dev),
Err(e) => panic!("{:?}", e),
}
访问底层 eBPF Map
let m: rxdp::Map<u32, u64> = match rxdp::Map::new(&obj, "map_name") {
Ok(m) => m,
Err(e) => panic!("{:?}", e),
};
注意:键/值大小必须与 eBPF 代码中定义的键/值大小匹配,否则创建映射将失败。
执行映射操作
use rxdp::MapLike;
let key = 0u32;
let value = 1000u64;
m.update(&key, &value, rxdp::MapFlags::BpfAny).unwrap();
let got = m.lookup(&key).unwrap();
assert_eq!(value, got.into_single());
// iterate through all items
for kv in m.items().unwrap() {
println!("key: {}, value: {}", kv.key, kv.value.into_single());
}
对于 per-cpu 映射,使用 PerCpuMap
let m: rxdp::PerCpuMap<u32, u64> = rxdp::PerCpuMap::new(&obj, "map_name").unwrap();
注意:键大小必须与 eBPF 代码中定义的键大小匹配,否则创建映射将失败。
Per CPU 映射操作
Per CPU 映射在查找期间返回 MapValue::Multi(Vec<T>)
变体,每个可能的 CPU 一个
use rxdp::MapLike;
let key = 0u32;
let value = 1000u64;
m.update(&key, &value, rxdp::MapFlags::BpfAny).unwrap();
let got = m.lookup(&key).unwrap();
assert_eq!(got.into_vec(), vec![value; rxdp::num_cpus()]);
// iterate through all items
for kv in m.items().unwrap() {
println!("key: {}", kv.key);
for v in kv.value.into_vec() {
println!("value: {}", v);
}
}
Perf 事件映射
可以通过 PerfMap
获取从 eBPF 发送的 Perf 事件。
let mut perfmap = rxdp::PerfMap::<u32>::new(&obj, "map_name").unwrap();
let r: Receiver<rxdp::PerfEvent<u32>> = perfmap.start_polling(10000);
// Wait for events on the receiver side of the channel
loop {
r.recv().map_or_else(
|e| println!("error: {:?}", e),
|event| println!("event: {:?}", event),
);
}
批处理支持(取决于内核)
如果内核支持,您可以对更新/查找执行批处理操作
if rxdp::is_batching_supported() {
let mut next_key = None;
let r = m.lookup_batch(10u32, next_key).unwrap();
// do something with r.items...
next_key = r.next_key;
}
测试
运行测试需要 root 权限,因此最好在 Docker 容器中运行它们
make docker-test
基准测试
运行基准测试需要root权限,因此最好在Docker容器中运行它们。
make docker-bench
许可
该crate采用MIT许可发布,并具有以下第三方依赖项:
网站 | 许可 | 链接 | |
---|---|---|---|
libbpf-sys | github.com/alexforster/libbpf-sys | BSD-2-条款 |
静态 |
libbpf | github.com/libbpf/libbpf | LGPL-2.1-仅或 BSD-2-条款 |
静态 |
libelf | sourceware.org/elfutils | LGPL-2.1-或-更新的版本或 LGPL-3.0-或-更新的版本 |
动态 |
zlib | zlib.net | Zlib |
动态 |
依赖项
~8MB
~184K SLoC