Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Untangle the section id, factories and modules #421

Merged
merged 9 commits into from
Oct 7, 2024
73 changes: 44 additions & 29 deletions retis-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use proc_macro::{self, TokenStream};
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Item, ItemStruct};
use syn::{parse_macro_input, Item, ItemStruct};

#[proc_macro_attribute]
pub fn raw_event_section(
Expand All @@ -24,39 +23,22 @@ pub fn event_section(
let input: ItemStruct = parse_macro_input!(item);
let ident = &input.ident;

let name: syn::LitStr = syn::parse(args).expect("Invalid event name");
let id: syn::Expr = syn::parse(args).expect("Invalid event id");

let output = quote! {
#[derive(Default, crate::EventSection)]
#[derive(Default)]
#[crate::event_type]
#input

impl #ident {
pub(crate) const SECTION_NAME: &'static str = #name;
pub(crate) const SECTION_ID: u8 = #id as u8;
amorenoz marked this conversation as resolved.
Show resolved Hide resolved
}
};
output.into()
}

#[proc_macro_attribute]
pub fn event_type(
_: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input: Item = parse_macro_input!(item);
let output = quote! {
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#input
};
output.into()
}

#[proc_macro_derive(EventSection)]
pub fn derive_event_section(input: TokenStream) -> TokenStream {
let DeriveInput { ident, .. } = parse_macro_input!(input);
let output = quote! {
impl EventSectionInternal for #ident {
fn id(&self) -> u8 {
Self::SECTION_ID
}

fn as_any(&self) -> &dyn std::any::Any
where Self: Sized,
{
Expand All @@ -79,13 +61,46 @@ pub fn derive_event_section(input: TokenStream) -> TokenStream {
output.into()
}

#[proc_macro_derive(EventSectionFactory)]
pub fn derive_event_section_factory(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
#[proc_macro_attribute]
pub fn event_type(
_: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let output = format!(
r#"
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
{item}
"#
);
output
.parse()
.expect("Invalid tokens from event_section macro")
}

#[proc_macro_attribute]
pub fn event_section_factory(
args: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input: ItemStruct = parse_macro_input!(item);
let ident = &input.ident;

let id: syn::Expr = syn::parse(args).expect("Invalid factory id");

let output = quote! {
#input

impl #ident {
pub(crate) const FACTORY_ID: u8 = #id as u8;

}

impl EventSectionFactory for #ident {
fn id(&self) -> u8 {
Self::FACTORY_ID
}

fn as_any_mut(&mut self) -> &mut dyn std::any::Any
where Self: Sized,
{
Expand Down
4 changes: 2 additions & 2 deletions retis-events/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::*;

/// Startup event section. Contains global information about a collection as a
/// whole, with data gathered at collection startup time.
#[event_section("startup")]
#[event_section(SectionId::Startup)]
pub struct StartupEvent {
/// Retis version used while collecting events.
pub retis_version: String,
Expand All @@ -33,7 +33,7 @@ pub struct TaskEvent {
}

/// Common event section.
#[event_section("common")]
#[event_section(SectionId::Common)]
pub struct CommonEvent {
/// Timestamp of when the event was generated.
pub timestamp: u64,
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/ct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub enum CtState {
Untracked,
}
/// Conntrack event
#[event_section("ct")]
#[event_section(SectionId::Ct)]
pub struct CtEvent {
/// Packet's conntrack state
pub state: CtState,
Expand Down
136 changes: 43 additions & 93 deletions retis-events/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#![allow(dead_code)] // FIXME
#![allow(clippy::wrong_self_convention)]

use std::{any::Any, collections::HashMap, fmt, str::FromStr};
use std::{any::Any, collections::HashMap, fmt};

use anyhow::{anyhow, bail, Result};
use log::debug;
Expand All @@ -60,18 +60,15 @@ impl Event {
.map_err(|e| anyhow!("Failed to parse json event at line {line}: {e}"))?;

for (owner, value) in event_js.drain() {
let owner_mod = SectionId::from_str(&owner)?;
let parser = event_sections()?
.get(&owner)
.ok_or_else(|| anyhow!("json contains an unsupported event {}", owner))?;

debug!("Unmarshaling event section {owner}: {value}");
event.insert_section(
owner_mod,
parser(value).map_err(|e| {
anyhow!("Failed to create EventSection for owner {owner} from json: {e}")
})?,
)?;
let section = parser(value).map_err(|e| {
anyhow!("Failed to create EventSection for owner {owner} from json: {e}")
})?;
event.insert_section(SectionId::from_u8(section.id())?, section)?;
}
Ok(event)
}
Expand Down Expand Up @@ -166,7 +163,7 @@ impl EventFmt for Event {
f.conf.inc_level(2);

// Finally show all sections.
(SectionId::Skb.to_u8()..SectionId::_MAX.to_u8())
(SectionId::Skb as u8..SectionId::_MAX as u8)
.collect::<Vec<u8>>()
.iter()
.filter_map(|id| self.0.get(&SectionId::from_u8(*id).unwrap()))
Expand Down Expand Up @@ -198,29 +195,6 @@ pub enum SectionId {
_MAX = 12,
}

impl FromStr for SectionId {
type Err = anyhow::Error;

/// Constructs an SectionId from a section unique str identifier.
fn from_str(val: &str) -> Result<Self> {
use SectionId::*;
Ok(match val {
CommonEvent::SECTION_NAME => Common,
KernelEvent::SECTION_NAME => Kernel,
UserEvent::SECTION_NAME => Userspace,
TrackingInfo::SECTION_NAME => Tracking,
SkbTrackingEvent::SECTION_NAME => SkbTracking,
SkbDropEvent::SECTION_NAME => SkbDrop,
SkbEvent::SECTION_NAME => Skb,
OvsEvent::SECTION_NAME => Ovs,
NftEvent::SECTION_NAME => Nft,
CtEvent::SECTION_NAME => Ct,
StartupEvent::SECTION_NAME => Startup,
x => bail!("Can't construct a SectionId from {}", x),
})
}
}

impl SectionId {
/// Constructs an SectionId from a section unique identifier
pub fn from_u8(val: u8) -> Result<SectionId> {
Expand All @@ -241,41 +215,21 @@ impl SectionId {
})
}

/// Converts an SectionId to a section unique identifier.
#[allow(dead_code)]
pub fn to_u8(self) -> u8 {
use SectionId::*;
match self {
Common => 1,
Kernel => 2,
Userspace => 3,
Tracking => 4,
SkbTracking => 5,
SkbDrop => 6,
Skb => 7,
Ovs => 8,
Nft => 9,
Ct => 10,
Startup => 11,
_MAX => 12,
}
}

/// Converts an SectionId to a section unique str identifier.
pub fn to_str(self) -> &'static str {
use SectionId::*;
match self {
Common => CommonEvent::SECTION_NAME,
Kernel => KernelEvent::SECTION_NAME,
Userspace => UserEvent::SECTION_NAME,
Tracking => TrackingInfo::SECTION_NAME,
SkbTracking => SkbTrackingEvent::SECTION_NAME,
SkbDrop => SkbDropEvent::SECTION_NAME,
Skb => SkbEvent::SECTION_NAME,
Ovs => OvsEvent::SECTION_NAME,
Nft => NftEvent::SECTION_NAME,
Ct => CtEvent::SECTION_NAME,
Startup => StartupEvent::SECTION_NAME,
Common => "common",
Kernel => "kernel",
Userspace => "userspace",
Tracking => "tracking",
SkbTracking => "skb-tracking",
SkbDrop => "skb-drop",
Skb => "skb",
Ovs => "ovs",
Nft => "nft",
Ct => "ct",
Startup => "startup",
_MAX => "_max",
}
}
Expand All @@ -291,39 +245,30 @@ impl fmt::Display for SectionId {
type EventSectionMap = HashMap<String, fn(serde_json::Value) -> Result<Box<dyn EventSection>>>;
static EVENT_SECTIONS: OnceCell<EventSectionMap> = OnceCell::new();

macro_rules! insert_section {
($events: expr, $ty: ty) => {
$events.insert(
SectionId::from_u8(<$ty>::SECTION_ID)?.to_str().to_string(),
|v| Ok(Box::new(serde_json::from_value::<$ty>(v)?)),
);
};
}

fn event_sections() -> Result<&'static EventSectionMap> {
EVENT_SECTIONS.get_or_try_init(|| {
let mut events = EventSectionMap::new();
events.insert(CommonEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<CommonEvent>(v)?))
});
events.insert(KernelEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<KernelEvent>(v)?))
});
events.insert(UserEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<UserEvent>(v)?))
});
events.insert(SkbTrackingEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<SkbTrackingEvent>(v)?))
});
events.insert(SkbDropEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<SkbDropEvent>(v)?))
});
events.insert(SkbEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<SkbEvent>(v)?))
});
events.insert(OvsEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<OvsEvent>(v)?))
});
events.insert(NftEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<NftEvent>(v)?))
});
events.insert(CtEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<CtEvent>(v)?))
});
events.insert(StartupEvent::SECTION_NAME.to_string(), |v| {
Ok(Box::new(serde_json::from_value::<StartupEvent>(v)?))
});

insert_section!(events, CommonEvent);
insert_section!(events, KernelEvent);
insert_section!(events, UserEvent);
insert_section!(events, SkbTrackingEvent);
insert_section!(events, SkbDropEvent);
insert_section!(events, SkbEvent);
insert_section!(events, OvsEvent);
insert_section!(events, NftEvent);
insert_section!(events, CtEvent);
insert_section!(events, StartupEvent);

Ok(events)
})
}
Expand Down Expand Up @@ -358,6 +303,7 @@ impl<T> EventSection for T where T: EventSectionInternal + for<'a> EventDisplay<
///
/// There should not be a need to have per-object implementations for this.
pub trait EventSectionInternal {
fn id(&self) -> u8;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn to_json(&self) -> serde_json::Value;
Expand All @@ -366,6 +312,10 @@ pub trait EventSectionInternal {
// We need this as the value given as the input when deserializing something
// into an event could be mapped to (), e.g. serde_json::Value::Null.
impl EventSectionInternal for () {
fn id(&self) -> u8 {
SectionId::_MAX as u8
}

fn as_any(&self) -> &dyn Any {
self
}
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;
use super::*;
use crate::{event_section, event_type, Formatter};

#[event_section("kernel")]
#[event_section(SectionId::Kernel)]
pub struct KernelEvent {
/// Kernel symbol name associated with the event (i.e. which probe generated
/// the event).
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::*;
use crate::{event_section, Formatter};

/// Nft event section
#[event_section("nft")]
#[event_section(SectionId::Nft)]
pub struct NftEvent {
pub table_name: String,
pub chain_name: String,
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/ovs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{event_section, event_type, Formatter};

///The OVS Event
#[derive(PartialEq)]
#[event_section("ovs")]
#[event_section(SectionId::Ovs)]
pub struct OvsEvent {
/// Event data
#[serde(flatten)]
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/skb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{
use crate::{event_section, event_type, Formatter};

/// Skb event section.
#[event_section("skb")]
#[event_section(SectionId::Skb)]
pub struct SkbEvent {
/// Ethernet fields, if any.
pub eth: Option<SkbEthEvent>,
Expand Down
2 changes: 1 addition & 1 deletion retis-events/src/skb_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::*;
use crate::{event_section, Formatter};

/// Skb drop event section.
#[event_section("skb-drop")]
#[event_section(SectionId::SkbDrop)]
pub struct SkbDropEvent {
/// Sub-system who generated the below drop reason. None for core reasons.
pub subsys: Option<String>,
Expand Down
4 changes: 2 additions & 2 deletions retis-events/src/skb_tracking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{event_section, Formatter};
/// Tl;dr; the tracking unique id is `(timestamp, orig_head)` and `skb` can be
/// used to distinguished between clones.
#[derive(Copy, PartialEq)]
#[event_section("skb-tracking")]
#[event_section(SectionId::SkbTracking)]
#[repr(C)]
pub struct SkbTrackingEvent {
/// Head of buffer (`skb->head`) when the packet was first seen by the
Expand Down Expand Up @@ -54,7 +54,7 @@ impl EventFmt for SkbTrackingEvent {

/// Tracking event section. Generated at postprocessing with combined skb and ovs
/// tracking information.
#[event_section("tracking")]
#[event_section(SectionId::Tracking)]
pub struct TrackingInfo {
/// Tracking information of the original packet.
pub skb: SkbTrackingEvent,
Expand Down
Loading