mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
* feat(kprobe): Add basic kprobe support for x86_64 * feat: add ebpf support (#912) - 实现bpf()一部分命令,包括几种基本map,相关的helper函数 - 实现部分perf相关的数据结构 - 暂时为文件实现简单mmap - 实现一个使用kprobe统计syscall 调用次数的ebpf程序 对eBPF支持程度(基本): - 简单的eBPF程序(没有指定特殊的Map) - 使用内核已经实现的Map的eBPF程序 - 可以和kprobe配合使用 - 内核Map相关的接口定义已经实现,添加新的Map较为简单 不支持的功能: - 区分不同的eBPF程序类型(Network/Cgroup)并限定可调用的helper函数集 - 与内核其它跟踪机制配合(tracepoint) - 其它helper和Map todo - [ ] 修改mmap,需要讨论,因为这个和块缓存层相关 - [x] 添加文档 - [x] 修复可能的错误 - [x] 增加rbpf版本信息 * feat: add /sys/devices/system/cpu/possible file * feat: add /sys/devices/system/cpu/online
155 lines
5.2 KiB
Rust
155 lines
5.2 KiB
Rust
use super::{BpfMapCommonOps, Result};
|
|
use crate::bpf::map::util::{BpfMapMeta, BpfMapUpdateElemFlags};
|
|
use alloc::vec::Vec;
|
|
use core::fmt::Debug;
|
|
use core::ops::Deref;
|
|
use core::ops::DerefMut;
|
|
use system_error::SystemError;
|
|
|
|
type BpfQueueValue = Vec<u8>;
|
|
/// BPF_MAP_TYPE_QUEUE provides FIFO storage and BPF_MAP_TYPE_STACK provides LIFO storage for BPF programs.
|
|
/// These maps support peek, pop and push operations that are exposed to BPF programs through the respective helpers.
|
|
/// These operations are exposed to userspace applications using the existing bpf syscall in the following way:
|
|
/// - `BPF_MAP_LOOKUP_ELEM` -> `peek`
|
|
/// - `BPF_MAP_UPDATE_ELEM` -> `push`
|
|
/// - `BPF_MAP_LOOKUP_AND_DELETE_ELEM ` -> `pop`
|
|
///
|
|
/// See https://docs.kernel.org/bpf/map_queue_stack.html
|
|
pub trait SpecialMap: Debug + Send + Sync + 'static {
|
|
/// Returns the number of elements the queue can hold.
|
|
fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()>;
|
|
/// Removes the first element and returns it.
|
|
fn pop(&mut self) -> Option<BpfQueueValue>;
|
|
/// Returns the first element without removing it.
|
|
fn peek(&self) -> Option<&BpfQueueValue>;
|
|
}
|
|
|
|
/// The queue map type is a generic map type, resembling a FIFO (First-In First-Out) queue.
|
|
///
|
|
/// This map type has no keys, only values. The size and type of the values can be specified by the user
|
|
/// to fit a large variety of use cases. The typical use-case for this map type is to keep track of
|
|
/// a pool of elements such as available network ports when implementing NAT (network address translation).
|
|
///
|
|
/// As apposed to most map types, this map type uses a custom set of helpers to pop, peek and push elements.
|
|
///
|
|
/// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_QUEUE/
|
|
#[derive(Debug)]
|
|
pub struct QueueMap {
|
|
max_entries: u32,
|
|
data: Vec<BpfQueueValue>,
|
|
}
|
|
|
|
impl QueueMap {
|
|
pub fn new(attr: &BpfMapMeta) -> Result<Self> {
|
|
if attr.value_size == 0 || attr.max_entries == 0 || attr.key_size != 0 {
|
|
return Err(SystemError::EINVAL);
|
|
}
|
|
let data = Vec::with_capacity(attr.max_entries as usize);
|
|
Ok(Self {
|
|
max_entries: attr.max_entries,
|
|
data,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl SpecialMap for QueueMap {
|
|
fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()> {
|
|
if self.data.len() == self.max_entries as usize {
|
|
if flags.contains(BpfMapUpdateElemFlags::BPF_EXIST) {
|
|
// remove the first element
|
|
self.data.remove(0);
|
|
} else {
|
|
return Err(SystemError::ENOSPC);
|
|
}
|
|
}
|
|
self.data.push(value);
|
|
Ok(())
|
|
}
|
|
fn pop(&mut self) -> Option<BpfQueueValue> {
|
|
if self.data.is_empty() {
|
|
return None;
|
|
}
|
|
Some(self.data.remove(0))
|
|
}
|
|
fn peek(&self) -> Option<&BpfQueueValue> {
|
|
self.data.first()
|
|
}
|
|
}
|
|
/// The stack map type is a generic map type, resembling a stack data structure.
|
|
///
|
|
/// See https://ebpf-docs.dylanreimerink.nl/linux/map-type/BPF_MAP_TYPE_STACK/
|
|
#[derive(Debug)]
|
|
pub struct StackMap(QueueMap);
|
|
|
|
impl StackMap {
|
|
pub fn new(attr: &BpfMapMeta) -> Result<Self> {
|
|
QueueMap::new(attr).map(StackMap)
|
|
}
|
|
}
|
|
|
|
impl Deref for StackMap {
|
|
type Target = QueueMap;
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for StackMap {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
impl SpecialMap for StackMap {
|
|
fn push(&mut self, value: BpfQueueValue, flags: BpfMapUpdateElemFlags) -> Result<()> {
|
|
if self.data.len() == self.max_entries as usize {
|
|
if flags.contains(BpfMapUpdateElemFlags::BPF_EXIST) {
|
|
// remove the last element
|
|
self.data.pop();
|
|
} else {
|
|
return Err(SystemError::ENOSPC);
|
|
}
|
|
}
|
|
self.data.push(value);
|
|
Ok(())
|
|
}
|
|
fn pop(&mut self) -> Option<BpfQueueValue> {
|
|
self.data.pop()
|
|
}
|
|
fn peek(&self) -> Option<&BpfQueueValue> {
|
|
self.data.last()
|
|
}
|
|
}
|
|
|
|
impl<T: SpecialMap> BpfMapCommonOps for T {
|
|
/// Equal to [QueueMap::peek]
|
|
fn lookup_elem(&mut self, _key: &[u8]) -> Result<Option<&[u8]>> {
|
|
Ok(self.peek().map(|v| v.as_slice()))
|
|
}
|
|
/// Equal to [QueueMap::push]
|
|
fn update_elem(&mut self, _key: &[u8], value: &[u8], flags: u64) -> Result<()> {
|
|
let flag = BpfMapUpdateElemFlags::from_bits_truncate(flags);
|
|
self.push(value.to_vec(), flag)
|
|
}
|
|
/// Equal to [QueueMap::pop]
|
|
fn lookup_and_delete_elem(&mut self, _key: &[u8], value: &mut [u8]) -> Result<()> {
|
|
if let Some(v) = self.pop() {
|
|
value.copy_from_slice(&v);
|
|
Ok(())
|
|
} else {
|
|
Err(SystemError::ENOENT)
|
|
}
|
|
}
|
|
fn push_elem(&mut self, value: &[u8], flags: u64) -> Result<()> {
|
|
self.update_elem(&[], value, flags)
|
|
}
|
|
fn pop_elem(&mut self, value: &mut [u8]) -> Result<()> {
|
|
self.lookup_and_delete_elem(&[], value)
|
|
}
|
|
fn peek_elem(&self, value: &mut [u8]) -> Result<()> {
|
|
self.peek()
|
|
.map(|v| value.copy_from_slice(v))
|
|
.ok_or(SystemError::ENOENT)
|
|
}
|
|
}
|