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.
aya/bpf/aya-bpf-macros/src/expand.rs

247 lines
6.0 KiB
Rust

use proc_macro2::TokenStream;
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
punctuated::{Pair, Punctuated},
token::Eq,
Error, Ident, ItemFn, ItemStatic, LitStr, Result, Token,
};
pub struct NameValue {
name: Ident,
_eq: Eq,
value: LitStr,
}
pub struct Args {
args: Vec<NameValue>,
}
impl Parse for Args {
fn parse(input: ParseStream) -> Result<Args> {
let args = Punctuated::<NameValue, Token![,]>::parse_terminated_with(input, |input| {
Ok(NameValue {
name: input.parse()?,
_eq: input.parse()?,
value: input.parse()?,
})
})?
.into_pairs()
.map(|pair| match pair {
Pair::Punctuated(name_val, _) => name_val,
Pair::End(name_val) => name_val,
})
.collect();
Ok(Args { args })
}
}
pub struct Map {
item: ItemStatic,
name: String,
}
impl Map {
pub fn from_syn(args: Args, item: ItemStatic) -> Result<Map> {
let name = name_arg(&args)?.unwrap_or_else(|| item.ident.to_string());
Ok(Map { item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = format!("maps/{}", self.name);
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
#item
})
}
}
pub struct Probe {
kind: ProbeKind,
item: ItemFn,
name: String,
}
impl Probe {
pub fn from_syn(kind: ProbeKind, args: Args, item: ItemFn) -> Result<Probe> {
let name = name_arg(&args)?.unwrap_or_else(|| item.sig.ident.to_string());
Ok(Probe { kind, item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = format!("{}/{}", self.kind, self.name);
let fn_name = &self.item.sig.ident;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
let _ = #fn_name(::aya_bpf::programs::ProbeContext::new(ctx));
return 0;
#item
}
})
}
}
pub struct SockOps {
item: ItemFn,
name: Option<String>,
}
impl SockOps {
pub fn from_syn(args: Args, item: ItemFn) -> Result<SockOps> {
let name = name_arg(&args)?;
Ok(SockOps { item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = if let Some(name) = &self.name {
format!("sockops/{}", name)
} else {
"sockops".to_owned()
};
let fn_name = &self.item.sig.ident;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock_ops) -> u32 {
return #fn_name(::aya_bpf::programs::SockOpsContext::new(ctx));
#item
}
})
}
}
pub struct SkMsg {
item: ItemFn,
name: String,
}
impl SkMsg {
pub fn from_syn(args: Args, item: ItemFn) -> Result<SkMsg> {
let name = name_arg(&args)?.unwrap_or_else(|| item.sig.ident.to_string());
Ok(SkMsg { item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = format!("sk_msg/{}", self.name);
let fn_name = &self.item.sig.ident;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::aya_bpf::bindings::sk_msg_md) -> u32 {
return #fn_name(::aya_bpf::programs::SkMsgContext::new(ctx));
#item
}
})
}
}
pub struct Xdp {
item: ItemFn,
name: Option<String>,
}
impl Xdp {
pub fn from_syn(args: Args, item: ItemFn) -> Result<Xdp> {
let name = name_arg(&args)?;
Ok(Xdp { item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = if let Some(name) = &self.name {
format!("xdp/{}", name)
} else {
"xdp".to_owned()
};
let fn_name = &self.item.sig.ident;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 {
return #fn_name(::aya_bpf::programs::XdpContext::new(ctx));
#item
}
})
}
}
pub struct SchedClassifier {
item: ItemFn,
name: Option<String>,
}
impl SchedClassifier {
pub fn from_syn(args: Args, item: ItemFn) -> Result<SchedClassifier> {
let name = name_arg(&args)?;
Ok(SchedClassifier { item, name })
}
pub fn expand(&self) -> Result<TokenStream> {
let section_name = if let Some(name) = &self.name {
format!("classifier/{}", name)
} else {
"classifier".to_owned()
};
let fn_name = &self.item.sig.ident;
let item = &self.item;
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i32 {
return #fn_name(::aya_bpf::programs::SkSkbContext::new(ctx));
#item
}
})
}
}
fn name_arg(args: &Args) -> Result<Option<String>> {
for arg in &args.args {
if arg.name == "name" {
return Ok(Some(arg.value.value()));
} else {
return Err(Error::new_spanned(&arg.name, "invalid argument"));
}
}
Ok(None)
}
#[derive(Debug, Copy, Clone)]
pub enum ProbeKind {
KProbe,
KRetProbe,
UProbe,
URetProbe,
}
impl std::fmt::Display for ProbeKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use ProbeKind::*;
match self {
KProbe => write!(f, "kprobe"),
KRetProbe => write!(f, "kretprobe"),
UProbe => write!(f, "uprobe"),
URetProbe => write!(f, "uretprobe"),
}
}
}