lib.rs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #![no_std]
  2. use core::num::{NonZeroUsize, TryFromIntError};
  3. use num_enum::IntoPrimitive;
  4. pub const LOG_BUF_CAPACITY: usize = 8192;
  5. pub const LOG_FIELDS: usize = 6;
  6. pub type LogValueLength = u16;
  7. #[repr(u8)]
  8. #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, IntoPrimitive)]
  9. pub enum Level {
  10. /// The "error" level.
  11. ///
  12. /// Designates very serious errors.
  13. Error = 1,
  14. /// The "warn" level.
  15. ///
  16. /// Designates hazardous situations.
  17. Warn,
  18. /// The "info" level.
  19. ///
  20. /// Designates useful information.
  21. Info,
  22. /// The "debug" level.
  23. ///
  24. /// Designates lower priority information.
  25. Debug,
  26. /// The "trace" level.
  27. ///
  28. /// Designates very low priority, often extremely verbose, information.
  29. Trace,
  30. }
  31. macro_rules! impl_formatter_for_types {
  32. ($trait:path : { $($type:ty),*}) => {
  33. $(
  34. impl $trait for $type {}
  35. )*
  36. };
  37. }
  38. pub trait DefaultFormatter {}
  39. impl_formatter_for_types!(
  40. DefaultFormatter: {
  41. bool,
  42. i8, i16, i32, i64, isize,
  43. u8, u16, u32, u64, usize,
  44. f32, f64,
  45. char,
  46. str,
  47. &str
  48. }
  49. );
  50. pub trait LowerHexFormatter {}
  51. impl_formatter_for_types!(
  52. LowerHexFormatter: {
  53. i8, i16, i32, i64, isize,
  54. u8, u16, u32, u64, usize,
  55. &[u8]
  56. }
  57. );
  58. pub trait UpperHexFormatter {}
  59. impl_formatter_for_types!(
  60. UpperHexFormatter: {
  61. i8, i16, i32, i64, isize,
  62. u8, u16, u32, u64, usize,
  63. &[u8]
  64. }
  65. );
  66. pub trait IpFormatter {}
  67. impl IpFormatter for u32 {}
  68. impl IpFormatter for [u8; 16] {}
  69. impl IpFormatter for [u16; 8] {}
  70. pub trait LowerMacFormatter {}
  71. impl LowerMacFormatter for [u8; 6] {}
  72. pub trait UpperMacFormatter {}
  73. impl UpperMacFormatter for [u8; 6] {}
  74. #[repr(u8)]
  75. #[derive(Copy, Clone, Debug, IntoPrimitive)]
  76. pub enum RecordField {
  77. Target = 1,
  78. Level,
  79. Module,
  80. File,
  81. Line,
  82. NumArgs,
  83. }
  84. /// Types which are supported by aya-log and can be safely sent from eBPF
  85. /// programs to userspace.
  86. #[repr(u8)]
  87. #[derive(Copy, Clone, Debug, IntoPrimitive)]
  88. pub enum Argument {
  89. DisplayHint,
  90. I8,
  91. I16,
  92. I32,
  93. I64,
  94. Isize,
  95. U8,
  96. U16,
  97. U32,
  98. U64,
  99. Usize,
  100. F32,
  101. F64,
  102. /// `[u8; 6]` array which represents a MAC address.
  103. ArrU8Len6,
  104. /// `[u8; 16]` array which represents an IPv6 address.
  105. ArrU8Len16,
  106. /// `[u16; 8]` array which represents an IPv6 address.
  107. ArrU16Len8,
  108. Bytes,
  109. Str,
  110. }
  111. /// All display hints
  112. #[repr(u8)]
  113. #[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive)]
  114. pub enum DisplayHint {
  115. /// Default string representation.
  116. Default = 1,
  117. /// `:x`
  118. LowerHex,
  119. /// `:X`
  120. UpperHex,
  121. /// `:i`
  122. Ip,
  123. /// `:mac`
  124. LowerMac,
  125. /// `:MAC`
  126. UpperMac,
  127. }
  128. // Must be inlined, else the BPF backend emits:
  129. //
  130. // llvm: <unknown>:0:0: in function _ZN14aya_log_common5write17hc9ed05433e23a663E { i64, i64 } (i8, ptr, i64, ptr, i64): only integer returns supported
  131. #[inline(always)]
  132. pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Option<NonZeroUsize> {
  133. let wire_len: LogValueLength = match value.len().try_into() {
  134. Ok(wire_len) => Some(wire_len),
  135. Err(TryFromIntError { .. }) => None,
  136. }?;
  137. let mut size = 0;
  138. macro_rules! copy_from_slice {
  139. ($value:expr) => {{
  140. let buf = buf.get_mut(size..)?;
  141. let buf = buf.get_mut(..$value.len())?;
  142. buf.copy_from_slice($value);
  143. size += $value.len();
  144. }};
  145. }
  146. copy_from_slice!(&[tag]);
  147. copy_from_slice!(&wire_len.to_ne_bytes());
  148. copy_from_slice!(value);
  149. NonZeroUsize::new(size)
  150. }
  151. pub trait WriteToBuf {
  152. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize>;
  153. }
  154. macro_rules! impl_write_to_buf {
  155. ($type:ident, $arg_type:expr) => {
  156. impl WriteToBuf for $type {
  157. // This need not be inlined because the return value is Option<N> where N is
  158. // mem::size_of<$type>, which is a compile-time constant.
  159. #[inline(never)]
  160. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  161. write($arg_type.into(), &self.to_ne_bytes(), buf)
  162. }
  163. }
  164. };
  165. }
  166. impl_write_to_buf!(i8, Argument::I8);
  167. impl_write_to_buf!(i16, Argument::I16);
  168. impl_write_to_buf!(i32, Argument::I32);
  169. impl_write_to_buf!(i64, Argument::I64);
  170. impl_write_to_buf!(isize, Argument::Isize);
  171. impl_write_to_buf!(u8, Argument::U8);
  172. impl_write_to_buf!(u16, Argument::U16);
  173. impl_write_to_buf!(u32, Argument::U32);
  174. impl_write_to_buf!(u64, Argument::U64);
  175. impl_write_to_buf!(usize, Argument::Usize);
  176. impl_write_to_buf!(f32, Argument::F32);
  177. impl_write_to_buf!(f64, Argument::F64);
  178. impl WriteToBuf for [u8; 16] {
  179. // This need not be inlined because the return value is Option<N> where N is 16, which is a
  180. // compile-time constant.
  181. #[inline(never)]
  182. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  183. write(Argument::ArrU8Len16.into(), &self, buf)
  184. }
  185. }
  186. impl WriteToBuf for [u16; 8] {
  187. // This need not be inlined because the return value is Option<N> where N is 16, which is a
  188. // compile-time constant.
  189. #[inline(never)]
  190. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  191. let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) };
  192. write(Argument::ArrU16Len8.into(), &bytes, buf)
  193. }
  194. }
  195. impl WriteToBuf for [u8; 6] {
  196. // This need not be inlined because the return value is Option<N> where N is 6, which is a
  197. // compile-time constant.
  198. #[inline(never)]
  199. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  200. write(Argument::ArrU8Len6.into(), &self, buf)
  201. }
  202. }
  203. impl WriteToBuf for &[u8] {
  204. // Must be inlined, else the BPF backend emits:
  205. //
  206. // llvm: <unknown>:0:0: in function _ZN63_$LT$$RF$$u5b$u8$u5d$$u20$as$u20$aya_log_common..WriteToBuf$GT$5write17h08f30a45f7b9f09dE { i64, i64 } (ptr, i64, ptr, i64): only integer returns supported
  207. #[inline(always)]
  208. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  209. write(Argument::Bytes.into(), self, buf)
  210. }
  211. }
  212. impl WriteToBuf for &str {
  213. // Must be inlined, else the BPF backend emits:
  214. //
  215. // llvm: <unknown>:0:0: in function _ZN54_$LT$$RF$str$u20$as$u20$aya_log_common..WriteToBuf$GT$5write17h7e2d1ccaa758e2b5E { i64, i64 } (ptr, i64, ptr, i64): only integer returns supported
  216. #[inline(always)]
  217. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  218. write(Argument::Str.into(), self.as_bytes(), buf)
  219. }
  220. }
  221. impl WriteToBuf for DisplayHint {
  222. // This need not be inlined because the return value is Option<N> where N is 1, which is a
  223. // compile-time constant.
  224. #[inline(never)]
  225. fn write(self, buf: &mut [u8]) -> Option<NonZeroUsize> {
  226. let v: u8 = self.into();
  227. write(Argument::DisplayHint.into(), &v.to_ne_bytes(), buf)
  228. }
  229. }
  230. #[doc(hidden)]
  231. #[inline(always)] // This function takes too many arguments to not be inlined.
  232. pub fn write_record_header(
  233. buf: &mut [u8],
  234. target: &str,
  235. level: Level,
  236. module: &str,
  237. file: &str,
  238. line: u32,
  239. num_args: usize,
  240. ) -> Option<NonZeroUsize> {
  241. let level: u8 = level.into();
  242. let mut size = 0;
  243. macro_rules! write {
  244. ($tag:expr, $value:expr) => {{
  245. let buf = buf.get_mut(size..)?;
  246. let len = write($tag.into(), $value, buf)?;
  247. size += len.get();
  248. }};
  249. }
  250. write!(RecordField::Target, target.as_bytes());
  251. write!(RecordField::Level, &level.to_ne_bytes());
  252. write!(RecordField::Module, module.as_bytes());
  253. write!(RecordField::File, file.as_bytes());
  254. write!(RecordField::Line, &line.to_ne_bytes());
  255. write!(RecordField::NumArgs, &num_args.to_ne_bytes());
  256. NonZeroUsize::new(size)
  257. }
  258. #[cfg(test)]
  259. mod test {
  260. use super::*;
  261. #[test]
  262. fn log_value_length_sufficient() {
  263. assert!(
  264. LOG_BUF_CAPACITY <= LogValueLength::MAX.into(),
  265. "{} > {}",
  266. LOG_BUF_CAPACITY,
  267. LogValueLength::MAX
  268. );
  269. }
  270. }