diff --git a/aya-bpf-macros/src/expand.rs b/aya-bpf-macros/src/expand.rs index 7c47e579..506cfa89 100644 --- a/aya-bpf-macros/src/expand.rs +++ b/aya-bpf-macros/src/expand.rs @@ -200,20 +200,33 @@ impl SkMsg { pub struct Xdp { item: ItemFn, name: Option, + frags: bool, } impl Xdp { pub fn from_syn(mut args: Args, item: ItemFn) -> Result { - let name = name_arg(&mut args)?; - - Ok(Xdp { item, name }) + let name = pop_arg(&mut args, "name"); + let mut frags = false; + if let Some(s) = pop_arg(&mut args, "frags") { + if let Ok(m) = s.parse() { + frags = m + } else { + return Err(Error::new_spanned( + "mutlibuffer", + "invalid value. should be 'true' or 'false'", + )); + } + } + err_on_unknown_args(&args)?; + Ok(Xdp { item, name, frags }) } pub fn expand(&self) -> Result { + let section_prefix = if self.frags { "xdp.frags" } else { "xdp" }; let section_name = if let Some(name) = &self.name { - format!("xdp/{name}") + format!("{section_prefix}/{name}") } else { - "xdp".to_owned() + section_prefix.to_string() }; let fn_vis = &self.item.vis; let fn_name = &self.item.sig.ident; diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index 72f13ed7..8491709b 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -160,7 +160,6 @@ pub struct Function { /// - `iter+`, `iter.s+` /// - `xdp.frags/cpumap`, `xdp/cpumap` /// - `xdp.frags/devmap`, `xdp/devmap` -/// - `xdp.frags` #[derive(Debug, Clone)] #[allow(missing_docs)] pub enum ProgramSection { @@ -184,6 +183,7 @@ pub enum ProgramSection { }, Xdp { name: String, + frags_supported: bool, }, SkMsg { name: String, @@ -266,7 +266,7 @@ impl ProgramSection { ProgramSection::URetProbe { name } => name, ProgramSection::TracePoint { name } => name, ProgramSection::SocketFilter { name } => name, - ProgramSection::Xdp { name } => name, + ProgramSection::Xdp { name, .. } => name, ProgramSection::SkMsg { name } => name, ProgramSection::SkSkbStreamParser { name } => name, ProgramSection::SkSkbStreamVerdict { name } => name, @@ -313,7 +313,14 @@ impl FromStr for ProgramSection { "kretprobe" => KRetProbe { name }, "uprobe" => UProbe { name }, "uretprobe" => URetProbe { name }, - "xdp" => Xdp { name }, + "xdp" => Xdp { + name, + frags_supported: false, + }, + "xdp.frags" => Xdp { + name, + frags_supported: true, + }, "tp_btf" => BtfTracePoint { name }, _ if kind.starts_with("tracepoint") || kind.starts_with("tp") => { // tracepoint sections are named `tracepoint/category/event_name`, @@ -1837,6 +1844,30 @@ mod tests { ); } + #[test] + fn test_parse_section_xdp_frags() { + let mut obj = fake_obj(); + + assert_matches!( + obj.parse_section(fake_section( + BpfSectionKind::Program, + "xdp.frags/foo", + bytes_of(&fake_ins()) + )), + Ok(()) + ); + assert_matches!( + obj.programs.get("foo"), + Some(Program { + section: ProgramSection::Xdp { + frags_supported: true, + .. + }, + .. + }) + ); + } + #[test] fn test_parse_section_raw_tp() { let mut obj = fake_obj(); diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 2a751f36..d3e8059f 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -9,6 +9,7 @@ use std::{ use aya_obj::{ btf::{BtfFeatures, BtfRelocationError}, + generated::BPF_F_XDP_HAS_FRAGS, relocation::BpfRelocationError, }; use log::debug; @@ -485,9 +486,16 @@ impl<'a> BpfLoader<'a> { data: ProgramData::new(prog_name, obj, btf_fd, verifier_log_level), }) } - ProgramSection::Xdp { .. } => Program::Xdp(Xdp { - data: ProgramData::new(prog_name, obj, btf_fd, verifier_log_level), - }), + ProgramSection::Xdp { + frags_supported, .. + } => { + let mut data = + ProgramData::new(prog_name, obj, btf_fd, verifier_log_level); + if *frags_supported { + data.flags = BPF_F_XDP_HAS_FRAGS; + } + Program::Xdp(Xdp { data }) + } ProgramSection::SkMsg { .. } => Program::SkMsg(SkMsg { data: ProgramData::new(prog_name, obj, btf_fd, verifier_log_level), }), diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 479d61e4..2050f8a7 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -415,6 +415,7 @@ pub(crate) struct ProgramData { pub(crate) btf_fd: Option, pub(crate) verifier_log_level: u32, pub(crate) path: Option, + pub(crate) flags: u32, } impl ProgramData { @@ -436,6 +437,7 @@ impl ProgramData { btf_fd, verifier_log_level, path: None, + flags: 0, } } @@ -474,6 +476,7 @@ impl ProgramData { btf_fd: None, verifier_log_level: 0, path: Some(path.to_path_buf()), + flags: 0, }) } @@ -606,6 +609,7 @@ fn load_program( func_info: func_info.clone(), line_info_rec_size: *line_info_rec_size, line_info: line_info.clone(), + flags: data.flags, }; let verifier_log_level = data.verifier_log_level; diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index e7384976..ec3890d0 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -115,6 +115,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> { pub(crate) func_info: FuncSecInfo, pub(crate) line_info_rec_size: usize, pub(crate) line_info: LineSecInfo, + pub(crate) flags: u32, } pub(crate) fn bpf_load_program( @@ -136,6 +137,7 @@ pub(crate) fn bpf_load_program( u.prog_name = name; } + u.prog_flags = aya_attr.flags; u.prog_type = aya_attr.ty as u32; if let Some(v) = aya_attr.expected_attach_type { u.expected_attach_type = v as u32; @@ -179,7 +181,6 @@ pub(crate) fn bpf_load_program( if let Some(v) = aya_attr.attach_btf_id { u.attach_btf_id = v; } - sys_bpf(bpf_cmd::BPF_PROG_LOAD, &attr) } diff --git a/test/integration-ebpf/src/map_test.rs b/test/integration-ebpf/src/map_test.rs index fc17d1f9..87c07557 100644 --- a/test/integration-ebpf/src/map_test.rs +++ b/test/integration-ebpf/src/map_test.rs @@ -14,7 +14,7 @@ static FOO: Array = Array::::with_max_entries(10, 0); #[map(name = "BAR")] static BAZ: Array = Array::::with_max_entries(10, 0); -#[xdp] +#[xdp(frags = "true")] pub fn pass(ctx: XdpContext) -> u32 { match unsafe { try_pass(ctx) } { Ok(ret) => ret, diff --git a/test/integration-ebpf/src/pass.rs b/test/integration-ebpf/src/pass.rs index 0979d557..b1bdde99 100644 --- a/test/integration-ebpf/src/pass.rs +++ b/test/integration-ebpf/src/pass.rs @@ -3,7 +3,7 @@ use aya_bpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; -#[xdp(name = "pass")] +#[xdp(name = "pass", frags = "true")] pub fn pass(ctx: XdpContext) -> u32 { match unsafe { try_pass(ctx) } { Ok(ret) => ret,