From 2223ab828d6db40a85cff4737f6164ed8ee9e42d Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Mon, 7 Nov 2022 09:45:12 -0800 Subject: [PATCH] aya-log: Add format hints for MAC addresses Add `{:mac}` (for lower-case hex representation) and `{:MAC}` (for upper-case hex representation) format hints for the `[u8; 6]` type, which is the standard one in Linux to store physical addresses in. Tested with: https://github.com/vadorovsky/aya-examples/tree/main/xdp-mac Signed-off-by: Michal Rostecki --- aya-log-common/src/lib.rs | 16 ++++++ aya-log-ebpf-macros/src/expand.rs | 2 + aya-log-parser/src/lib.rs | 2 + aya-log/src/lib.rs | 89 +++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index e1cc8f92..2e162a0f 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -44,6 +44,8 @@ pub enum RecordField { NumArgs, } +/// Types which are supported by aya-log and can be safely sent from eBPF +/// programs to userspace. #[repr(usize)] #[derive(Copy, Clone, Debug)] pub enum Argument { @@ -64,7 +66,11 @@ pub enum Argument { F32, F64, + /// `[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, Str, @@ -84,6 +90,10 @@ pub enum DisplayHint { Ipv4, /// `:ipv6` Ipv6, + /// `:mac` + LowerMac, + /// `:MAC` + UpperMac, } #[cfg(feature = "userspace")] @@ -178,6 +188,12 @@ impl WriteToBuf for [u16; 8] { } } +impl WriteToBuf for [u8; 6] { + fn write(&self, buf: &mut [u8]) -> Result { + TagLenValue::::new(Argument::ArrU8Len6, self).write(buf) + } +} + impl WriteToBuf for str { fn write(&self, buf: &mut [u8]) -> Result { TagLenValue::::new(Argument::Str, self.as_bytes()).write(buf) diff --git a/aya-log-ebpf-macros/src/expand.rs b/aya-log-ebpf-macros/src/expand.rs index 2aeb9ca8..874feb3b 100644 --- a/aya-log-ebpf-macros/src/expand.rs +++ b/aya-log-ebpf-macros/src/expand.rs @@ -81,6 +81,8 @@ fn hint_to_expr(hint: DisplayHint) -> Result { DisplayHint::UpperHex => parse_str("::aya_log_ebpf::macro_support::DisplayHint::UpperHex"), DisplayHint::Ipv4 => parse_str("::aya_log_ebpf::macro_support::DisplayHint::Ipv4"), DisplayHint::Ipv6 => parse_str("::aya_log_ebpf::macro_support::DisplayHint::Ipv6"), + DisplayHint::LowerMac => parse_str("::aya_log_ebpf::macro_support::DisplayHint::LowerMac"), + DisplayHint::UpperMac => parse_str("::aya_log_ebpf::macro_support::DisplayHint::UpperMac"), } } diff --git a/aya-log-parser/src/lib.rs b/aya-log-parser/src/lib.rs index 16ca8ec6..dd2c6944 100644 --- a/aya-log-parser/src/lib.rs +++ b/aya-log-parser/src/lib.rs @@ -59,6 +59,8 @@ fn parse_display_hint(s: &str) -> Result { "X" => DisplayHint::UpperHex, "ipv4" => DisplayHint::Ipv4, "ipv6" => DisplayHint::Ipv6, + "mac" => DisplayHint::LowerMac, + "MAC" => DisplayHint::UpperMac, _ => return Err(format!("unknown display hint: {:?}", s)), }) } diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index a2dd686b..53f693bb 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -171,6 +171,26 @@ where } } +pub struct LowerMacFormatter; +impl Formatter<[u8; 6]> for LowerMacFormatter { + fn format(v: [u8; 6]) -> String { + format!( + "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + v[0], v[1], v[2], v[3], v[4], v[5] + ) + } +} + +pub struct UpperMacFormatter; +impl Formatter<[u8; 6]> for UpperMacFormatter { + fn format(v: [u8; 6]) -> String { + format!( + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + v[0], v[1], v[2], v[3], v[4], v[5] + ) + } +} + trait Format { fn format(&self, last_hint: Option) -> Result; } @@ -183,11 +203,28 @@ impl Format for u32 { Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)), Some(DisplayHint::Ipv4) => Ok(Ipv4Formatter::format(*self)), Some(DisplayHint::Ipv6) => Err(()), + Some(DisplayHint::LowerMac) => Err(()), + Some(DisplayHint::UpperMac) => Err(()), _ => Ok(DefaultFormatter::format(self)), } } } +impl Format for [u8; 6] { + fn format(&self, last_hint: Option) -> Result { + match last_hint { + Some(DisplayHint::Default) => Err(()), + Some(DisplayHint::LowerHex) => Err(()), + Some(DisplayHint::UpperHex) => Err(()), + Some(DisplayHint::Ipv4) => Err(()), + Some(DisplayHint::Ipv6) => Err(()), + Some(DisplayHint::LowerMac) => Ok(LowerMacFormatter::format(*self)), + Some(DisplayHint::UpperMac) => Ok(UpperMacFormatter::format(*self)), + _ => Err(()), + } + } +} + impl Format for [u8; 16] { fn format(&self, last_hint: Option) -> Result { match last_hint { @@ -196,6 +233,8 @@ impl Format for [u8; 16] { Some(DisplayHint::UpperHex) => Err(()), Some(DisplayHint::Ipv4) => Err(()), Some(DisplayHint::Ipv6) => Ok(Ipv6Formatter::format(*self)), + Some(DisplayHint::LowerMac) => Err(()), + Some(DisplayHint::UpperMac) => Err(()), _ => Err(()), } } @@ -209,6 +248,8 @@ impl Format for [u16; 8] { Some(DisplayHint::UpperHex) => Err(()), Some(DisplayHint::Ipv4) => Err(()), Some(DisplayHint::Ipv6) => Ok(Ipv6Formatter::format(*self)), + Some(DisplayHint::LowerMac) => Err(()), + Some(DisplayHint::UpperMac) => Err(()), _ => Err(()), } } @@ -224,6 +265,8 @@ macro_rules! impl_format { Some(DisplayHint::UpperHex) => Ok(UpperHexFormatter::format(self)), Some(DisplayHint::Ipv4) => Err(()), Some(DisplayHint::Ipv6) => Err(()), + Some(DisplayHint::LowerMac) => Err(()), + Some(DisplayHint::UpperMac) => Err(()), _ => Ok(DefaultFormatter::format(self)), } } @@ -252,6 +295,8 @@ macro_rules! impl_format_float { Some(DisplayHint::UpperHex) => Err(()), Some(DisplayHint::Ipv4) => Err(()), Some(DisplayHint::Ipv6) => Err(()), + Some(DisplayHint::LowerMac) => Err(()), + Some(DisplayHint::UpperMac) => Err(()), _ => Ok(DefaultFormatter::format(self)), } } @@ -407,6 +452,10 @@ fn log_buf(mut buf: &[u8], logger: &dyn Log) -> Result<(), ()> { .format(last_hint.take())?, ); } + Argument::ArrU8Len6 => { + let value: [u8; 6] = attr.value.try_into().map_err(|_| ())?; + full_log_msg.push_str(&value.format(last_hint.take())?); + } Argument::ArrU8Len16 => { let value: [u8; 16] = attr.value.try_into().map_err(|_| ())?; full_log_msg.push_str(&value.format(last_hint.take())?); @@ -650,4 +699,44 @@ mod test { assert_eq!(captured_logs[0].level, Level::Info); }); } + + #[test] + fn test_display_hint_lower_mac() { + testing_logger::setup(); + let (mut len, mut input) = new_log(3).unwrap(); + + len += "mac: ".write(&mut input[len..]).unwrap(); + len += DisplayHint::LowerMac.write(&mut input[len..]).unwrap(); + // 00:00:5e:00:53:af as byte array + let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; + mac_arr.write(&mut input[len..]).unwrap(); + + let logger = logger(); + let _ = log_buf(&input, logger); + testing_logger::validate(|captured_logs| { + assert_eq!(captured_logs.len(), 1); + assert_eq!(captured_logs[0].body, "mac: 00:00:5e:00:53:af"); + assert_eq!(captured_logs[0].level, Level::Info); + }); + } + + #[test] + fn test_display_hint_upper_mac() { + testing_logger::setup(); + let (mut len, mut input) = new_log(3).unwrap(); + + len += "mac: ".write(&mut input[len..]).unwrap(); + len += DisplayHint::UpperMac.write(&mut input[len..]).unwrap(); + // 00:00:5E:00:53:AF as byte array + let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; + mac_arr.write(&mut input[len..]).unwrap(); + + let logger = logger(); + let _ = log_buf(&input, logger); + testing_logger::validate(|captured_logs| { + assert_eq!(captured_logs.len(), 1); + assert_eq!(captured_logs[0].body, "mac: 00:00:5E:00:53:AF"); + assert_eq!(captured_logs[0].level, Level::Info); + }); + } }