mirror of https://github.com/aya-rs/aya
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
8.2 KiB
Rust
363 lines
8.2 KiB
Rust
#![no_std]
|
|
|
|
use core::{
|
|
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
|
num::TryFromIntError,
|
|
};
|
|
|
|
use num_enum::IntoPrimitive;
|
|
|
|
pub type LogValueLength = u16;
|
|
|
|
#[repr(u8)]
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, IntoPrimitive)]
|
|
pub enum Level {
|
|
/// The "error" level.
|
|
///
|
|
/// Designates very serious errors.
|
|
Error = 1,
|
|
/// The "warn" level.
|
|
///
|
|
/// Designates hazardous situations.
|
|
Warn,
|
|
/// The "info" level.
|
|
///
|
|
/// Designates useful information.
|
|
Info,
|
|
/// The "debug" level.
|
|
///
|
|
/// Designates lower priority information.
|
|
Debug,
|
|
/// The "trace" level.
|
|
///
|
|
/// Designates very low priority, often extremely verbose, information.
|
|
Trace,
|
|
}
|
|
|
|
macro_rules! impl_formatter_for_types {
|
|
($trait:path : { $($type:ty),*}) => {
|
|
$(
|
|
impl $trait for $type {}
|
|
)*
|
|
};
|
|
}
|
|
|
|
pub trait DefaultFormatter {}
|
|
impl_formatter_for_types!(
|
|
DefaultFormatter: {
|
|
bool,
|
|
i8, i16, i32, i64, isize,
|
|
u8, u16, u32, u64, usize,
|
|
f32, f64,
|
|
char,
|
|
str,
|
|
&str,
|
|
IpAddr, Ipv4Addr, Ipv6Addr
|
|
}
|
|
);
|
|
|
|
pub trait LowerHexFormatter {}
|
|
impl_formatter_for_types!(
|
|
LowerHexFormatter: {
|
|
i8, i16, i32, i64, isize,
|
|
u8, u16, u32, u64, usize,
|
|
&[u8]
|
|
}
|
|
);
|
|
|
|
pub trait UpperHexFormatter {}
|
|
impl_formatter_for_types!(
|
|
UpperHexFormatter: {
|
|
i8, i16, i32, i64, isize,
|
|
u8, u16, u32, u64, usize,
|
|
&[u8]
|
|
}
|
|
);
|
|
|
|
pub trait IpFormatter {}
|
|
impl IpFormatter for IpAddr {}
|
|
impl IpFormatter for Ipv4Addr {}
|
|
impl IpFormatter for Ipv6Addr {}
|
|
impl IpFormatter for u32 {}
|
|
impl IpFormatter for [u8; 4] {}
|
|
impl IpFormatter for [u8; 16] {}
|
|
impl IpFormatter for [u16; 8] {}
|
|
|
|
pub trait LowerMacFormatter {}
|
|
impl LowerMacFormatter for [u8; 6] {}
|
|
|
|
pub trait UpperMacFormatter {}
|
|
impl UpperMacFormatter for [u8; 6] {}
|
|
|
|
#[repr(u8)]
|
|
#[derive(Copy, Clone, Debug, IntoPrimitive)]
|
|
pub enum RecordFieldKind {
|
|
Target,
|
|
Level,
|
|
Module,
|
|
File,
|
|
Line,
|
|
NumArgs,
|
|
}
|
|
|
|
/// Types which are supported by aya-log and can be safely sent from eBPF
|
|
/// programs to userspace.
|
|
#[repr(u8)]
|
|
#[derive(Copy, Clone, Debug, IntoPrimitive)]
|
|
pub enum ArgumentKind {
|
|
DisplayHint,
|
|
|
|
I8,
|
|
I16,
|
|
I32,
|
|
I64,
|
|
Isize,
|
|
|
|
U8,
|
|
U16,
|
|
U32,
|
|
U64,
|
|
Usize,
|
|
|
|
F32,
|
|
F64,
|
|
|
|
Ipv4Addr,
|
|
Ipv6Addr,
|
|
|
|
/// `[u8; 4]` array which represents an IPv4 address.
|
|
ArrU8Len4,
|
|
/// `[u8; 6]` array which represents a MAC address.
|
|
ArrU8Len6,
|
|
/// `[u8; 16]` array which represents an IPv6 address.
|
|
ArrU8Len16,
|
|
/// `[u16; 8]` array which represents an IPv6 address.
|
|
ArrU16Len8,
|
|
|
|
Bytes,
|
|
Str,
|
|
}
|
|
|
|
/// All display hints
|
|
#[repr(u8)]
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive)]
|
|
pub enum DisplayHint {
|
|
/// Default string representation.
|
|
Default = 1,
|
|
/// `:x`
|
|
LowerHex,
|
|
/// `:X`
|
|
UpperHex,
|
|
/// `:i`
|
|
Ip,
|
|
/// `:mac`
|
|
LowerMac,
|
|
/// `:MAC`
|
|
UpperMac,
|
|
}
|
|
|
|
pub trait Argument {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>);
|
|
}
|
|
|
|
macro_rules! impl_argument {
|
|
($self:ident, $arg_type:expr) => {
|
|
impl Argument for $self {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
($arg_type, self.to_ne_bytes())
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_argument!(i8, ArgumentKind::I8);
|
|
impl_argument!(i16, ArgumentKind::I16);
|
|
impl_argument!(i32, ArgumentKind::I32);
|
|
impl_argument!(i64, ArgumentKind::I64);
|
|
impl_argument!(isize, ArgumentKind::Isize);
|
|
|
|
impl_argument!(u8, ArgumentKind::U8);
|
|
impl_argument!(u16, ArgumentKind::U16);
|
|
impl_argument!(u32, ArgumentKind::U32);
|
|
impl_argument!(u64, ArgumentKind::U64);
|
|
impl_argument!(usize, ArgumentKind::Usize);
|
|
|
|
impl_argument!(f32, ArgumentKind::F32);
|
|
impl_argument!(f64, ArgumentKind::F64);
|
|
|
|
enum Either<L, R> {
|
|
Left(L),
|
|
Right(R),
|
|
}
|
|
|
|
impl<L, R> AsRef<[u8]> for Either<L, R>
|
|
where
|
|
L: AsRef<[u8]>,
|
|
R: AsRef<[u8]>,
|
|
{
|
|
fn as_ref(&self) -> &[u8] {
|
|
match self {
|
|
Either::Left(l) => l.as_ref(),
|
|
Either::Right(r) => r.as_ref(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Argument for IpAddr {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
match self {
|
|
IpAddr::V4(ipv4_addr) => {
|
|
let (kind, value) = ipv4_addr.as_argument();
|
|
(kind, Either::Left(value))
|
|
}
|
|
IpAddr::V6(ipv6_addr) => {
|
|
let (kind, value) = ipv6_addr.as_argument();
|
|
(kind, Either::Right(value))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Argument for Ipv4Addr {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::Ipv4Addr, self.octets())
|
|
}
|
|
}
|
|
|
|
impl Argument for [u8; 4] {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::ArrU8Len4, self)
|
|
}
|
|
}
|
|
|
|
impl Argument for Ipv6Addr {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::Ipv6Addr, self.octets())
|
|
}
|
|
}
|
|
|
|
impl Argument for [u8; 16] {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::ArrU8Len16, self)
|
|
}
|
|
}
|
|
|
|
impl Argument for [u16; 8] {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
let bytes = unsafe { core::mem::transmute::<&[u16; 8], &[u8; 16]>(self) };
|
|
(ArgumentKind::ArrU16Len8, bytes)
|
|
}
|
|
}
|
|
|
|
impl Argument for [u8; 6] {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::ArrU8Len6, self)
|
|
}
|
|
}
|
|
|
|
impl Argument for &[u8] {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::Bytes, self)
|
|
}
|
|
}
|
|
|
|
impl Argument for &str {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
(ArgumentKind::Str, self.as_bytes())
|
|
}
|
|
}
|
|
|
|
impl Argument for DisplayHint {
|
|
fn as_argument(&self) -> (ArgumentKind, impl AsRef<[u8]>) {
|
|
let v: u8 = (*self).into();
|
|
(ArgumentKind::DisplayHint, v.to_ne_bytes())
|
|
}
|
|
}
|
|
|
|
fn wire_len(value: &[u8]) -> Option<[u8; 2]> {
|
|
match LogValueLength::try_from(value.len()) {
|
|
Ok(wire_len) => Some(wire_len.to_ne_bytes()),
|
|
Err(TryFromIntError { .. }) => None,
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct Field<T>([u8; 1], [u8; 2], T);
|
|
|
|
impl<T: AsRef<[u8]>> Field<T> {
|
|
pub fn new(kind: impl Into<u8>, value: T) -> Option<Self> {
|
|
let wire_len = wire_len(value.as_ref())?;
|
|
Some(Self([kind.into()], wire_len, value))
|
|
}
|
|
|
|
pub fn with_bytes(&self, op: &mut impl FnMut(&[u8]) -> Option<()>) -> Option<()> {
|
|
let Self(kind, wire_len, value) = self;
|
|
op(&kind[..])?;
|
|
op(&wire_len[..])?;
|
|
op(value.as_ref())?;
|
|
Some(())
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct Header<'a> {
|
|
target: Field<&'a [u8]>,
|
|
level: Field<[u8; 1]>,
|
|
module: Field<&'a [u8]>,
|
|
file: Field<&'a [u8]>,
|
|
line: Field<[u8; 4]>,
|
|
num_args: Field<[u8; 4]>,
|
|
}
|
|
|
|
impl<'a> Header<'a> {
|
|
pub fn new(
|
|
target: &'a str,
|
|
level: Level,
|
|
module: &'a str,
|
|
file: &'a str,
|
|
line: u32,
|
|
num_args: u32,
|
|
) -> Option<Self> {
|
|
let target = target.as_bytes();
|
|
let level: u8 = level.into();
|
|
let level = level.to_ne_bytes();
|
|
let module = module.as_bytes();
|
|
let file = file.as_bytes();
|
|
let line = line.to_ne_bytes();
|
|
let num_args = num_args.to_ne_bytes();
|
|
let target = Field::new(RecordFieldKind::Target, target)?;
|
|
let level = Field::new(RecordFieldKind::Level, level)?;
|
|
let module = Field::new(RecordFieldKind::Module, module)?;
|
|
let file = Field::new(RecordFieldKind::File, file)?;
|
|
let line = Field::new(RecordFieldKind::Line, line)?;
|
|
let num_args = Field::new(RecordFieldKind::NumArgs, num_args)?;
|
|
|
|
Some(Self {
|
|
target,
|
|
level,
|
|
module,
|
|
file,
|
|
line,
|
|
num_args,
|
|
})
|
|
}
|
|
|
|
pub fn with_bytes(&self, op: &mut impl FnMut(&[u8]) -> Option<()>) -> Option<()> {
|
|
let Self {
|
|
target,
|
|
level,
|
|
module,
|
|
file,
|
|
line,
|
|
num_args,
|
|
} = self;
|
|
target.with_bytes(op)?;
|
|
level.with_bytes(op)?;
|
|
module.with_bytes(op)?;
|
|
file.with_bytes(op)?;
|
|
line.with_bytes(op)?;
|
|
num_args.with_bytes(op)?;
|
|
Some(())
|
|
}
|
|
}
|