lib.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #![no_std]
  2. use core::{cmp, mem, ptr, slice};
  3. use num_enum::IntoPrimitive;
  4. pub const LOG_BUF_CAPACITY: usize = 8192;
  5. pub const LOG_FIELDS: usize = 6;
  6. #[repr(usize)]
  7. #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
  8. pub enum Level {
  9. /// The "error" level.
  10. ///
  11. /// Designates very serious errors.
  12. Error = 1,
  13. /// The "warn" level.
  14. ///
  15. /// Designates hazardous situations.
  16. Warn,
  17. /// The "info" level.
  18. ///
  19. /// Designates useful information.
  20. Info,
  21. /// The "debug" level.
  22. ///
  23. /// Designates lower priority information.
  24. Debug,
  25. /// The "trace" level.
  26. ///
  27. /// Designates very low priority, often extremely verbose, information.
  28. Trace,
  29. }
  30. #[repr(usize)]
  31. #[derive(Copy, Clone, Debug)]
  32. pub enum RecordField {
  33. Target = 1,
  34. Level,
  35. Module,
  36. File,
  37. Line,
  38. NumArgs,
  39. }
  40. /// Types which are supported by aya-log and can be safely sent from eBPF
  41. /// programs to userspace.
  42. #[repr(usize)]
  43. #[derive(Copy, Clone, Debug)]
  44. pub enum Argument {
  45. DisplayHint,
  46. I8,
  47. I16,
  48. I32,
  49. I64,
  50. Isize,
  51. U8,
  52. U16,
  53. U32,
  54. U64,
  55. Usize,
  56. F32,
  57. F64,
  58. /// `[u8; 6]` array which represents a MAC address.
  59. ArrU8Len6,
  60. /// `[u8; 16]` array which represents an IPv6 address.
  61. ArrU8Len16,
  62. /// `[u16; 8]` array which represents an IPv6 address.
  63. ArrU16Len8,
  64. Str,
  65. }
  66. /// All display hints
  67. #[repr(u8)]
  68. #[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive)]
  69. pub enum DisplayHint {
  70. /// Default string representation.
  71. Default = 1,
  72. /// `:x`
  73. LowerHex,
  74. /// `:X`
  75. UpperHex,
  76. /// `:ipv4`
  77. Ipv4,
  78. /// `:ipv6`
  79. Ipv6,
  80. /// `:mac`
  81. LowerMac,
  82. /// `:MAC`
  83. UpperMac,
  84. }
  85. #[cfg(feature = "userspace")]
  86. mod userspace {
  87. use super::*;
  88. unsafe impl aya::Pod for RecordField {}
  89. unsafe impl aya::Pod for Argument {}
  90. unsafe impl aya::Pod for DisplayHint {}
  91. }
  92. struct TagLenValue<'a, T> {
  93. tag: T,
  94. value: &'a [u8],
  95. }
  96. impl<'a, T> TagLenValue<'a, T>
  97. where
  98. T: Copy,
  99. {
  100. #[inline(always)]
  101. pub(crate) fn new(tag: T, value: &'a [u8]) -> TagLenValue<'a, T> {
  102. TagLenValue { tag, value }
  103. }
  104. pub(crate) fn write(&self, mut buf: &mut [u8]) -> Result<usize, ()> {
  105. let size = mem::size_of::<T>() + mem::size_of::<usize>() + self.value.len();
  106. let remaining = cmp::min(buf.len(), LOG_BUF_CAPACITY);
  107. // Check if the size doesn't exceed the buffer bounds.
  108. if size > remaining {
  109. return Err(());
  110. }
  111. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.tag) };
  112. buf = &mut buf[mem::size_of::<T>()..];
  113. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.value.len()) };
  114. buf = &mut buf[mem::size_of::<usize>()..];
  115. let len = cmp::min(buf.len(), self.value.len());
  116. // The verifier isn't happy with `len` being unbounded, so compare it
  117. // with `LOG_BUF_CAPACITY`.
  118. if len > LOG_BUF_CAPACITY {
  119. return Err(());
  120. }
  121. buf[..len].copy_from_slice(&self.value[..len]);
  122. Ok(size)
  123. }
  124. }
  125. pub trait WriteToBuf {
  126. #[allow(clippy::result_unit_err)]
  127. fn write(&self, buf: &mut [u8]) -> Result<usize, ()>;
  128. }
  129. macro_rules! impl_write_to_buf {
  130. ($type:ident, $arg_type:expr) => {
  131. impl WriteToBuf for $type {
  132. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  133. TagLenValue::<Argument>::new($arg_type, &self.to_ne_bytes()).write(buf)
  134. }
  135. }
  136. };
  137. }
  138. impl_write_to_buf!(i8, Argument::I8);
  139. impl_write_to_buf!(i16, Argument::I16);
  140. impl_write_to_buf!(i32, Argument::I32);
  141. impl_write_to_buf!(i64, Argument::I64);
  142. impl_write_to_buf!(isize, Argument::Isize);
  143. impl_write_to_buf!(u8, Argument::U8);
  144. impl_write_to_buf!(u16, Argument::U16);
  145. impl_write_to_buf!(u32, Argument::U32);
  146. impl_write_to_buf!(u64, Argument::U64);
  147. impl_write_to_buf!(usize, Argument::Usize);
  148. impl_write_to_buf!(f32, Argument::F32);
  149. impl_write_to_buf!(f64, Argument::F64);
  150. impl WriteToBuf for [u8; 16] {
  151. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  152. TagLenValue::<Argument>::new(Argument::ArrU8Len16, self).write(buf)
  153. }
  154. }
  155. impl WriteToBuf for [u16; 8] {
  156. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  157. let ptr = self.as_ptr().cast::<u8>();
  158. let bytes = unsafe { slice::from_raw_parts(ptr, 16) };
  159. TagLenValue::<Argument>::new(Argument::ArrU16Len8, bytes).write(buf)
  160. }
  161. }
  162. impl WriteToBuf for [u8; 6] {
  163. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  164. TagLenValue::<Argument>::new(Argument::ArrU8Len6, self).write(buf)
  165. }
  166. }
  167. impl WriteToBuf for str {
  168. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  169. TagLenValue::<Argument>::new(Argument::Str, self.as_bytes()).write(buf)
  170. }
  171. }
  172. impl WriteToBuf for DisplayHint {
  173. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  174. let v: u8 = (*self).into();
  175. TagLenValue::<Argument>::new(Argument::DisplayHint, &v.to_ne_bytes()).write(buf)
  176. }
  177. }
  178. #[allow(clippy::result_unit_err)]
  179. #[doc(hidden)]
  180. #[inline(always)]
  181. pub fn write_record_header(
  182. buf: &mut [u8],
  183. target: &str,
  184. level: Level,
  185. module: &str,
  186. file: &str,
  187. line: u32,
  188. num_args: usize,
  189. ) -> Result<usize, ()> {
  190. let mut size = 0;
  191. for attr in [
  192. TagLenValue::<RecordField>::new(RecordField::Target, target.as_bytes()),
  193. TagLenValue::<RecordField>::new(RecordField::Level, &(level as usize).to_ne_bytes()),
  194. TagLenValue::<RecordField>::new(RecordField::Module, module.as_bytes()),
  195. TagLenValue::<RecordField>::new(RecordField::File, file.as_bytes()),
  196. TagLenValue::<RecordField>::new(RecordField::Line, &line.to_ne_bytes()),
  197. TagLenValue::<RecordField>::new(RecordField::NumArgs, &num_args.to_ne_bytes()),
  198. ] {
  199. size += attr.write(&mut buf[size..])?;
  200. }
  201. Ok(size)
  202. }