mirror of https://github.com/aya-rs/aya
maps: add ProgramArray
ProgramArray is a wrapper around BPF_MAP_TYPE_PROG_ARRAY maps. Can be used to setup jump tables for bpf_tail_call().pull/1/head
parent
f7cdd2e059
commit
a41edbca2c
@ -0,0 +1,128 @@
|
||||
use std::{
|
||||
cell::{Ref, RefMut},
|
||||
convert::TryFrom,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
os::unix::prelude::RawFd,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
generated::bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY,
|
||||
maps::{IterableMap, Map, MapError, MapIter, MapKeys},
|
||||
programs::ProgramFd,
|
||||
syscalls::{
|
||||
bpf_map_delete_elem, bpf_map_lookup_and_delete_elem, bpf_map_lookup_elem,
|
||||
bpf_map_update_elem,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct ProgramArray<T: Deref<Target = Map>> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T: Deref<Target = Map>> ProgramArray<T> {
|
||||
pub fn new(map: T) -> Result<ProgramArray<T>, MapError> {
|
||||
let inner = map.deref();
|
||||
let map_type = inner.obj.def.map_type;
|
||||
if map_type != BPF_MAP_TYPE_PROG_ARRAY {
|
||||
return Err(MapError::InvalidMapType {
|
||||
map_type: map_type as u32,
|
||||
})?;
|
||||
}
|
||||
let expected = mem::size_of::<RawFd>();
|
||||
let size = inner.obj.def.key_size as usize;
|
||||
if size != expected {
|
||||
return Err(MapError::InvalidKeySize { size, expected });
|
||||
}
|
||||
|
||||
let expected = mem::size_of::<RawFd>();
|
||||
let size = inner.obj.def.value_size as usize;
|
||||
if size != expected {
|
||||
return Err(MapError::InvalidValueSize { size, expected });
|
||||
}
|
||||
|
||||
Ok(ProgramArray { inner: map })
|
||||
}
|
||||
|
||||
pub unsafe fn get(&self, key: &u32, flags: u64) -> Result<Option<RawFd>, MapError> {
|
||||
let fd = self.inner.deref().fd_or_err()?;
|
||||
let fd = bpf_map_lookup_elem(fd, key, flags)
|
||||
.map_err(|(code, io_error)| MapError::LookupElementFailed { code, io_error })?;
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
pub unsafe fn iter<'coll>(&'coll self) -> MapIter<'coll, u32, RawFd> {
|
||||
MapIter::new(self)
|
||||
}
|
||||
|
||||
pub unsafe fn keys<'coll>(&'coll self) -> MapKeys<'coll, u32, RawFd> {
|
||||
MapKeys::new(self)
|
||||
}
|
||||
|
||||
fn check_bounds(&self, index: u32) -> Result<(), MapError> {
|
||||
let max_entries = self.inner.deref().obj.def.max_entries;
|
||||
if index >= self.inner.deref().obj.def.max_entries {
|
||||
Err(MapError::OutOfBounds { index, max_entries })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deref<Target = Map> + DerefMut<Target = Map>> ProgramArray<T> {
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
index: u32,
|
||||
program: &dyn ProgramFd,
|
||||
flags: u64,
|
||||
) -> Result<(), MapError> {
|
||||
let fd = self.inner.deref().fd_or_err()?;
|
||||
self.check_bounds(index)?;
|
||||
let prog_fd = program.fd().ok_or(MapError::ProgramNotLoaded)?;
|
||||
|
||||
bpf_map_update_elem(fd, &index, &prog_fd, flags)
|
||||
.map_err(|(code, io_error)| MapError::UpdateElementFailed { code, io_error })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn pop(&mut self, index: &u32) -> Result<Option<RawFd>, MapError> {
|
||||
let fd = self.inner.deref().fd_or_err()?;
|
||||
self.check_bounds(*index)?;
|
||||
bpf_map_lookup_and_delete_elem(fd, index)
|
||||
.map_err(|(code, io_error)| MapError::LookupAndDeleteElementFailed { code, io_error })
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, index: &u32) -> Result<(), MapError> {
|
||||
let fd = self.inner.deref().fd_or_err()?;
|
||||
self.check_bounds(*index)?;
|
||||
bpf_map_delete_elem(fd, index)
|
||||
.map(|_| ())
|
||||
.map_err(|(code, io_error)| MapError::DeleteElementFailed { code, io_error })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deref<Target = Map>> IterableMap<u32, RawFd> for ProgramArray<T> {
|
||||
fn fd(&self) -> Result<RawFd, MapError> {
|
||||
self.inner.deref().fd_or_err()
|
||||
}
|
||||
|
||||
unsafe fn get(&self, index: &u32) -> Result<Option<RawFd>, MapError> {
|
||||
self.get(index, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Ref<'a, Map>> for ProgramArray<Ref<'a, Map>> {
|
||||
type Error = MapError;
|
||||
|
||||
fn try_from(inner: Ref<'a, Map>) -> Result<ProgramArray<Ref<'a, Map>>, MapError> {
|
||||
ProgramArray::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<RefMut<'a, Map>> for ProgramArray<RefMut<'a, Map>> {
|
||||
type Error = MapError;
|
||||
|
||||
fn try_from(inner: RefMut<'a, Map>) -> Result<ProgramArray<RefMut<'a, Map>>, MapError> {
|
||||
ProgramArray::new(inner)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue