use bcc_sys::bccapi::*;
use libc::{c_int, size_t};
use crate::types::MutPointer;
use crate::BccError;
use std::ffi::CStr;
use std::io::Error;
#[derive(Clone, Debug)]
pub struct Table {
id: size_t,
p: MutPointer,
}
impl Table {
pub(crate) fn new(id: usize, p: MutPointer) -> Table {
Table { id, p }
}
pub fn key_size(&mut self) -> usize {
unsafe { bpf_table_key_size_id(self.p, self.id) }
}
pub fn fd(&mut self) -> c_int {
unsafe { bpf_table_fd_id(self.p, self.id) }
}
pub fn leaf_size(&mut self) -> usize {
unsafe { bpf_table_leaf_size_id(self.p, self.id) }
}
pub fn name(&mut self) -> String {
unsafe {
let cs = bpf_table_name(self.p, self.id);
CStr::from_ptr(cs).to_str().unwrap().to_string()
}
}
pub fn delete(&mut self, key: &mut [u8]) -> Result<(), BccError> {
let fd = self.fd();
let res = unsafe { bpf_delete_elem(fd, key.as_mut_ptr() as MutPointer) };
match res {
0 => Ok(()),
_ => Err(BccError::DeleteTableValue {
message: Error::last_os_error().to_string(),
}),
}
}
pub fn delete_all(&mut self) -> Result<(), BccError> {
for mut e in self.iter() {
self.delete(&mut e.key)?;
}
Ok(())
}
pub fn get(&mut self, key: &mut [u8]) -> Result<Vec<u8>, BccError> {
let mut leaf = vec![0; self.leaf_size()];
let res = unsafe {
bpf_lookup_elem(
self.fd(),
key.as_mut_ptr() as MutPointer,
leaf.as_mut_ptr() as MutPointer,
)
};
match res {
0 => Ok(leaf),
_ => Err(BccError::GetTableValue {
message: Error::last_os_error().to_string(),
}),
}
}
pub fn set(&mut self, key: &mut [u8], leaf: &mut [u8]) -> Result<(), BccError> {
let res = unsafe {
bpf_update_elem(
self.fd(),
key.as_mut_ptr() as MutPointer,
leaf.as_mut_ptr() as MutPointer,
0,
)
};
match res {
0 => Ok(()),
_ => Err(BccError::SetTableValue {
message: Error::last_os_error().to_string(),
}),
}
}
pub fn iter(&self) -> EntryIter {
EntryIter {
current: None,
table: self.clone(),
fd: None,
}
}
}
impl IntoIterator for Table {
type Item = Entry;
type IntoIter = EntryIter;
fn into_iter(self) -> Self::IntoIter {
EntryIter {
current: None,
table: self,
fd: None,
}
}
}
impl<'a> IntoIterator for &'a Table {
type Item = Entry;
type IntoIter = EntryIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone)]
pub struct Entry {
pub key: Vec<u8>,
pub value: Vec<u8>,
}
pub struct EntryIter {
current: Option<Entry>,
fd: Option<c_int>,
table: Table,
}
impl EntryIter {
pub fn entry_ptrs(&mut self) -> Option<(MutPointer, MutPointer)> {
match self.current.as_mut() {
Some(&mut Entry {
ref mut key,
ref mut value,
}) => Some((
key.as_mut_ptr() as MutPointer,
value.as_mut_ptr() as MutPointer,
)),
None => None,
}
}
pub fn start(&mut self) -> Option<Entry> {
self.fd = Some(self.table.fd());
let key_size = self.table.key_size();
let leaf_size = self.table.leaf_size();
let entry = Entry {
key: vec![0; key_size],
value: vec![0; leaf_size],
};
self.current = Some(entry);
unsafe {
let (k, v) = self.entry_ptrs().unwrap();
if bpf_get_first_key(self.fd.unwrap(), k, key_size) < 0 {
self.current = None;
} else {
bpf_lookup_elem(self.fd.unwrap(), k, v);
}
}
self.current.clone()
}
}
impl Iterator for EntryIter {
type Item = Entry;
fn next(&mut self) -> Option<Entry> {
if let Some((k, l)) = self.entry_ptrs() {
let fd = self.fd.expect("oh no");
match unsafe { bpf_get_next_key(fd, k, k) } {
-1 => None,
_ => {
unsafe { bpf_lookup_elem(fd, k, l) };
self.current.clone()
}
}
} else {
self.start()
}
}
}