From bcbb7e08fad18cfcd34fcb69d009cdf8417afffb Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 09:24:30 -0400 Subject: [PATCH 01/42] Cargo.toml: Remove default-features settings These are all set to false at the root. --- test/integration-test/Cargo.toml | 7 ++----- xtask/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/test/integration-test/Cargo.toml b/test/integration-test/Cargo.toml index 876a9a86..4d1a466b 100644 --- a/test/integration-test/Cargo.toml +++ b/test/integration-test/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -anyhow = { workspace = true, default-features = true } +anyhow = { workspace = true, features = ["std"] } assert_matches = { workspace = true } aya = { workspace = true } aya-log = { workspace = true } @@ -16,10 +16,7 @@ netns-rs = { workspace = true } object = { workspace = true } rbpf = { workspace = true } test-case = { workspace = true } -tokio = { workspace = true, default-features = false, features = [ - "macros", - "time", -] } +tokio = { workspace = true, features = ["macros", "time"] } [build-dependencies] cargo_metadata = { workspace = true } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0349e022..1a2ae931 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" publish = false [dependencies] -anyhow = { workspace = true, default-features = true } +anyhow = { workspace = true, features = ["std"] } aya-tool = { workspace = true } cargo_metadata = { workspace = true } -clap = { workspace = true, default-features = true, features = ["derive"] } +clap = { workspace = true, features = ["derive"] } dialoguer = { workspace = true } diff = { workspace = true } indoc = { workspace = true } From 72afd877b54b0ceb24944d573ddfe676d8adc5ae Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 09:25:37 -0400 Subject: [PATCH 02/42] integration-test: clang-format C files --- test/integration-test/bpf/ext.bpf.c | 7 ++-- test/integration-test/bpf/main.bpf.c | 7 ++-- test/integration-test/bpf/multimap-btf.bpf.c | 34 ++++++++++---------- test/integration-test/bpf/text_64_64_reloc.c | 29 ++++++++--------- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/test/integration-test/bpf/ext.bpf.c b/test/integration-test/bpf/ext.bpf.c index dc82f5cf..6ec95229 100644 --- a/test/integration-test/bpf/ext.bpf.c +++ b/test/integration-test/bpf/ext.bpf.c @@ -1,10 +1,9 @@ +// clang-format off #include #include +// clang-format on SEC("xdp") -int xdp_drop(struct xdp_md *ctx) -{ - return XDP_DROP; -} +int xdp_drop(struct xdp_md *ctx) { return XDP_DROP; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/main.bpf.c b/test/integration-test/bpf/main.bpf.c index 2a30577f..f60e42a9 100644 --- a/test/integration-test/bpf/main.bpf.c +++ b/test/integration-test/bpf/main.bpf.c @@ -1,10 +1,9 @@ +// clang-format off #include #include +// clang-format on SEC("xdp") -int xdp_pass(struct xdp_md *ctx) -{ - return XDP_PASS; -} +int xdp_pass(struct xdp_md *ctx) { return XDP_PASS; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/multimap-btf.bpf.c b/test/integration-test/bpf/multimap-btf.bpf.c index 955a91d3..07fcc60f 100644 --- a/test/integration-test/bpf/multimap-btf.bpf.c +++ b/test/integration-test/bpf/multimap-btf.bpf.c @@ -1,30 +1,30 @@ +// clang-format off #include #include +// clang-format on struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); } map_1 SEC(".maps"); struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); } map_2 SEC(".maps"); - SEC("tracepoint") -int bpf_prog(void *ctx) -{ - __u32 key = 0; - __u64 twenty_four = 24; - __u64 forty_two = 42; - bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); - bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); - return 0; +int bpf_prog(void *ctx) { + __u32 key = 0; + __u64 twenty_four = 24; + __u64 forty_two = 42; + bpf_map_update_elem(&map_1, &key, &twenty_four, BPF_ANY); + bpf_map_update_elem(&map_2, &key, &forty_two, BPF_ANY); + return 0; } char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/bpf/text_64_64_reloc.c b/test/integration-test/bpf/text_64_64_reloc.c index 877c7628..cd273a35 100644 --- a/test/integration-test/bpf/text_64_64_reloc.c +++ b/test/integration-test/bpf/text_64_64_reloc.c @@ -1,28 +1,25 @@ +// clang-format off #include #include +// clang-format on char _license[] SEC("license") = "GPL"; struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 2); + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 2); } RESULTS SEC(".maps"); -static __u64 -inc_cb(void *map, __u32 *key, void *val, - void *data) -{ - __u64 *value = val; - *value += 1; - return 0; +static __u64 inc_cb(void *map, __u32 *key, void *val, void *data) { + __u64 *value = val; + *value += 1; + return 0; } SEC("uprobe/test_text_64_64_reloc") -int test_text_64_64_reloc(struct pt_regs *ctx) -{ - bpf_for_each_map_elem(&RESULTS, inc_cb, NULL, 0); - return 0; +int test_text_64_64_reloc(struct pt_regs *ctx) { + bpf_for_each_map_elem(&RESULTS, inc_cb, NULL, 0); + return 0; } - From 098d4364bd0fb8551f0515cb84afda6aff23ed7f Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Wed, 9 Aug 2023 12:19:01 +0100 Subject: [PATCH 03/42] aya-obj: Mutate BTF in-place without clone The BTF we're working on is Cow anyway so modifying in-place is fine. All we need to do is store some information before we start our mutable iteration to avoid concurrently borrowing types both mutably and immutably. Signed-off-by: Dave Tucker --- aya-obj/src/btf/btf.rs | 77 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 88d43e82..59f8e3cb 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -475,7 +475,7 @@ impl Btf { ) -> Result<(), BtfError> { let mut types = mem::take(&mut self.types); for i in 0..types.types.len() { - let t = &types.types[i]; + let t = &mut types.types[i]; let kind = t.kind(); match t { // Fixup PTR for Rust @@ -483,9 +483,7 @@ impl Btf { // While I figure out if this needs fixing in the Kernel or LLVM, we'll // do a fixup here BtfType::Ptr(ptr) => { - let mut fixed_ty = ptr.clone(); - fixed_ty.name_offset = 0; - types.types[i] = BtfType::Ptr(fixed_ty) + ptr.name_offset = 0; } // Sanitize VAR if they are not supported BtfType::Var(v) if !features.btf_datasec => { @@ -496,7 +494,7 @@ impl Btf { debug!("{}: not supported. replacing with STRUCT", kind); // STRUCT aren't allowed to have "." in their name, fixup this if needed. - let mut name_offset = t.name_offset(); + let mut name_offset = d.name_offset; let name = self.string_at(name_offset)?; // Handle any "." characters in struct names @@ -506,18 +504,22 @@ impl Btf { name_offset = self.add_string(&fixed_name); } - let mut members = vec![]; - for member in d.entries.iter() { - let mt = types.type_by_id(member.btf_type).unwrap(); - members.push(BtfMember { - name_offset: mt.name_offset(), - btf_type: member.btf_type, - offset: member.offset * 8, + let entries = std::mem::take(&mut d.entries); + + let members = entries + .iter() + .map(|e| { + let mt = types.type_by_id(e.btf_type).unwrap(); + BtfMember { + name_offset: mt.name_offset(), + btf_type: e.btf_type, + offset: e.offset * 8, + } }) - } + .collect(); types.types[i] = - BtfType::Struct(Struct::new(name_offset, members, d.entries.len() as u32)); + BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32)); } // Fixup DATASEC // DATASEC sizes aren't always set by LLVM @@ -527,18 +529,16 @@ impl Btf { let name = self.string_at(d.name_offset)?; let name = name.into_owned(); - let mut fixed_ty = d.clone(); - // Handle any "/" characters in section names // Example: "maps/hashmap" let fixed_name = name.replace('/', "."); if fixed_name != name { - fixed_ty.name_offset = self.add_string(&fixed_name); + d.name_offset = self.add_string(&fixed_name); } // There are some cases when the compiler does indeed populate the // size - if t.size().unwrap() > 0 { + if d.size > 0 { debug!("{} {}: size fixup not required", kind, name); } else { // We need to get the size of the section from the ELF file @@ -551,22 +551,23 @@ impl Btf { } }; debug!("{} {}: fixup size to {}", kind, name, size); - fixed_ty.size = *size as u32; + d.size = *size as u32; // The Vec contains BTF_KIND_VAR sections // that need to have their offsets adjusted. To do this, // we need to get the offset from the ELF file. // This was also cached during initial parsing and // we can query by name in symbol_offsets - for d in &mut fixed_ty.entries.iter_mut() { - let var_type = types.type_by_id(d.btf_type)?; - let var_kind = var_type.kind(); - if let BtfType::Var(var) = var_type { + let mut entries = mem::take(&mut d.entries); + let mut fixed_section = d.clone(); + + for e in entries.iter_mut() { + if let BtfType::Var(var) = types.type_by_id(e.btf_type)? { let var_name = self.string_at(var.name_offset)?; if var.linkage == VarLinkage::Static { debug!( - "{} {}: {} {}: fixup not required", - kind, name, var_kind, var_name + "{} {}: VAR {}: fixup not required", + kind, name, var_name ); continue; } @@ -579,27 +580,26 @@ impl Btf { }); } }; - d.offset = *offset as u32; + e.offset = *offset as u32; debug!( - "{} {}: {} {}: fixup offset {}", - kind, name, var_kind, var_name, offset + "{} {}: VAR {}: fixup offset {}", + kind, name, var_name, offset ); } else { return Err(BtfError::InvalidDatasec); } } + fixed_section.entries = entries; + types.types[i] = BtfType::DataSec(fixed_section); } - types.types[i] = BtfType::DataSec(fixed_ty); } // Fixup FUNC_PROTO BtfType::FuncProto(ty) if features.btf_func => { - let mut ty = ty.clone(); for (i, param) in ty.params.iter_mut().enumerate() { if param.name_offset == 0 && param.btf_type != 0 { param.name_offset = self.add_string(&format!("param{i}")); } } - types.types[i] = BtfType::FuncProto(ty); } // Sanitize FUNC_PROTO BtfType::FuncProto(ty) if !features.btf_func => { @@ -635,7 +635,6 @@ impl Btf { // and verified separately from their callers, while instead we // want tracking info (eg bound checks) to be propagated to the // memory builtins. - let mut fixed_ty = ty.clone(); if ty.linkage() == FuncLinkage::Global { if !features.btf_func_global { debug!( @@ -645,9 +644,8 @@ impl Btf { } else { debug!("changing FUNC {name} linkage to BTF_FUNC_STATIC"); } - fixed_ty.set_linkage(FuncLinkage::Static); + ty.set_linkage(FuncLinkage::Static); } - types.types[i] = BtfType::Func(fixed_ty); } } // Sanitize FLOAT @@ -1244,9 +1242,9 @@ mod tests { 0, ))); - let name_offset = btf.add_string("foo"); + let var_name_offset = btf.add_string("foo"); let var_type_id = btf.add_type(BtfType::Var(Var::new( - name_offset, + var_name_offset, int_type_id, VarLinkage::Static, ))); @@ -1271,11 +1269,14 @@ mod tests { assert_eq!(fixed.name_offset , name_offset); assert_matches!(*fixed.members, [ BtfMember { - name_offset: _, + name_offset: name_offset1, btf_type, offset: 0, }, - ] => assert_eq!(btf_type, var_type_id)); + ] => { + assert_eq!(name_offset1, var_name_offset); + assert_eq!(btf_type, var_type_id); + }) }); // Ensure we can convert to bytes and back again let raw = btf.to_bytes(); From dc9f72adf0e88238ea172668d8e9bc368b07b560 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 3 Aug 2023 11:28:32 -0400 Subject: [PATCH 04/42] test,xtask: Simplify ExitStatus handling --- test/integration-test/build.rs | 23 ++++++----------------- xtask/src/lib.rs | 11 ++++------- xtask/src/public_api.rs | 2 +- xtask/src/run.rs | 27 ++++++++------------------- 4 files changed, 19 insertions(+), 44 deletions(-) diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index cd816164..2e3bef84 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -4,7 +4,7 @@ use std::{ fs, io::{BufRead as _, BufReader}, path::PathBuf, - process::{Child, Command, Stdio}, + process::{Child, Command, Output, Stdio}, }; use cargo_metadata::{ @@ -166,16 +166,11 @@ fn main() { ) .unwrap(); - let status = child - .wait() + let output = child + .wait_with_output() .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - match status.code() { - Some(code) => match code { - 0 => {} - code => panic!("{cmd:?} exited with status code {code}"), - }, - None => panic!("{cmd:?} terminated by signal"), - } + let Output { status, .. } = &output; + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); } let target = format!("{target}-unknown-none"); @@ -257,13 +252,7 @@ fn main() { let status = child .wait() .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - match status.code() { - Some(code) => match code { - 0 => {} - code => panic!("{cmd:?} exited with status code {code}"), - }, - None => panic!("{cmd:?} terminated by signal"), - } + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {status:?}"); stderr.join().map_err(std::panic::resume_unwind).unwrap(); diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 09db4cbc..9e5c8737 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context as _, Result}; +use anyhow::{bail, Context as _, Result}; use std::{ fs, path::{Path, PathBuf}, @@ -13,13 +13,10 @@ pub fn exec(cmd: &mut Command) -> Result<()> { let status = cmd .status() .with_context(|| format!("failed to run {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => Ok(()), - code => Err(anyhow!("{cmd:?} exited with code {code}")), - }, - None => Err(anyhow!("{cmd:?} terminated by signal")), + if status.code() != Some(0) { + bail!("{cmd:?} failed: {status:?}") } + Ok(()) } // Create a symlink in the out directory to work around the fact that cargo ignores anything diff --git a/xtask/src/public_api.rs b/xtask/src/public_api.rs index 56db350b..b5b58f07 100644 --- a/xtask/src/public_api.rs +++ b/xtask/src/public_api.rs @@ -62,7 +62,7 @@ pub fn public_api(options: Options, metadata: Metadata) -> Result<()> { }); if !errors.is_empty() { - bail!("public API errors:\n{errors}"); + bail!("public API errors:\n{errors}") } Ok(()) } diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 7a29ad5f..6742a26b 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -6,7 +6,7 @@ use std::{ process::{Child, Command, Stdio}, }; -use anyhow::{bail, Context as _, Result}; +use anyhow::{anyhow, bail, Context as _, Result}; use cargo_metadata::{Artifact, CompilerMessage, Message, Target}; use clap::Parser; use xtask::AYA_BUILD_INTEGRATION_BPF; @@ -77,14 +77,9 @@ pub fn build(opts: BuildOptions) -> Result> { let status = child .wait() .with_context(|| format!("failed to wait for {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => {} - code => bail!("{cmd:?} exited with status code {code}"), - }, - None => bail!("{cmd:?} terminated by signal"), + if status.code() != Some(0) { + bail!("{cmd:?} failed: {status:?}") } - Ok(executables) } @@ -98,7 +93,7 @@ pub fn run(opts: Options) -> Result<()> { let binaries = build(build_options).context("error while building userspace application")?; let mut args = runner.trim().split_terminator(' '); - let runner = args.next().ok_or(anyhow::anyhow!("no first argument"))?; + let runner = args.next().ok_or(anyhow!("no first argument"))?; let args = args.collect::>(); let mut failures = String::new(); @@ -110,24 +105,18 @@ pub fn run(opts: Options) -> Result<()> { .args(run_args.iter()) .arg("--test-threads=1"); - println!("{} running {cmd:?}", name); + println!("{name} running {cmd:?}"); let status = cmd .status() .with_context(|| format!("failed to run {cmd:?}"))?; - match status.code() { - Some(code) => match code { - 0 => {} - code => writeln!(&mut failures, "{} exited with status code {code}", name) - .context("String write failed")?, - }, - None => writeln!(&mut failures, "{} terminated by signal", name) - .context("String write failed")?, + if status.code() != Some(0) { + writeln!(&mut failures, "{name} failed: {status:?}").context("String write failed")? } } if failures.is_empty() { Ok(()) } else { - Err(anyhow::anyhow!("failures:\n{}", failures)) + Err(anyhow!("failures:\n{}", failures)) } } From 0904cd089ed70d71393fb03b7641daf3d9711358 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 11:53:13 -0400 Subject: [PATCH 05/42] integration-test: DRY clang setup --- test/integration-test/build.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index 2e3bef84..bf4a0234 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -116,36 +116,30 @@ fn main() { target_arch.push(arch); }; + let clang = || { + let mut cmd = Command::new("clang"); + cmd.arg("-I") + .arg(&libbpf_headers_dir) + .args(["-g", "-O2", "-target", target, "-c"]) + .arg(&target_arch); + cmd + }; + for (src, dst) in c_bpf { let src = bpf_dir.join(src); println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - exec( - Command::new("clang") - .arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-O2", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .arg("-o") - .arg(dst), - ) - .unwrap(); + exec(clang().arg(src).arg("-o").arg(dst)).unwrap(); } for (src, dst) in c_btf { let src = bpf_dir.join(src); println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - let mut cmd = Command::new("clang"); - cmd.arg("-I") - .arg(&libbpf_headers_dir) - .args(["-g", "-target", target, "-c"]) - .arg(&target_arch) - .arg(src) - .args(["-o", "-"]); - + let mut cmd = clang(); let mut child = cmd + .arg(src) + .args(["-o", "-"]) .stdout(Stdio::piped()) .spawn() .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); From b46fb616beb205cd5686d06dbf3238cf4b4a5c94 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 12:00:36 -0400 Subject: [PATCH 06/42] integration-test: fix BTF relocation test The struct_flavors test previously expected the same thing with and without relocations. It now expects different values. Also rename an enum variant "u64" to "S64". This was a typo. Turns out that U32 is a type that exists in kernel headers, so all enum values are suffixed with "_VAL". Remove stdlib.h and the call to exit(). This alone makes the test fail with a poisoned relocation. Bringing over the map definition makes the test work again. --- test/integration-test/bpf/reloc.bpf.c | 22 +++++++----- test/integration-test/bpf/reloc.btf.c | 34 +++++++++++++------ .../src/tests/btf_relocations.rs | 18 +++++----- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/test/integration-test/bpf/reloc.bpf.c b/test/integration-test/bpf/reloc.bpf.c index dbc464a4..f426874f 100644 --- a/test/integration-test/bpf/reloc.bpf.c +++ b/test/integration-test/bpf/reloc.bpf.c @@ -51,44 +51,48 @@ __attribute__((noinline)) int struct_flavors_global() { if (bpf_core_field_exists(s.a)) { return set_output(__builtin_preserve_access_index(s.a)); } else { - return set_output(__builtin_preserve_access_index(s.b)); + return set_output(__builtin_preserve_access_index(s.c)); } } SEC("uprobe") int struct_flavors(void *ctx) { return struct_flavors_global(); } -enum relocated_enum_unsigned_32 { U32 = 0xAAAAAAAA }; +enum relocated_enum_unsigned_32 { U32_VAL = 0xAAAAAAAA }; __attribute__((noinline)) int enum_unsigned_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); } SEC("uprobe") int enum_unsigned_32(void *ctx) { return enum_unsigned_32_global(); } -enum relocated_enum_signed_32 { S32 = -0x7AAAAAAA }; +enum relocated_enum_signed_32 { S32_VAL = -0x7AAAAAAA }; __attribute__((noinline)) int enum_signed_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL)); } SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); } -enum relocated_enum_unsigned_64 { U64 = 0xAAAAAAAABBBBBBBB }; +enum relocated_enum_unsigned_64 { U64_VAL = 0xAAAAAAAABBBBBBBB }; __attribute__((noinline)) int enum_unsigned_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); } SEC("uprobe") int enum_unsigned_64(void *ctx) { return enum_unsigned_64_global(); } -enum relocated_enum_signed_64 { u64 = -0xAAAAAAABBBBBBBB }; +enum relocated_enum_signed_64 { S64_VAL = -0xAAAAAAABBBBBBBB }; __attribute__((noinline)) int enum_signed_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL)); } SEC("uprobe") int enum_signed_64(void *ctx) { return enum_signed_64_global(); } diff --git a/test/integration-test/bpf/reloc.btf.c b/test/integration-test/bpf/reloc.btf.c index 86801061..ec396552 100644 --- a/test/integration-test/bpf/reloc.btf.c +++ b/test/integration-test/bpf/reloc.btf.c @@ -4,9 +4,17 @@ #include // clang-format on -#include - -long set_output(__u64 value) { exit((int)value); } +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, 1); +} output_map SEC(".maps"); + +long set_output(__u64 value) { + __u32 key = 0; + return bpf_map_update_elem(&output_map, &key, &value, BPF_ANY); +} struct relocated_struct_with_scalars { __u8 b; @@ -41,28 +49,32 @@ __attribute__((noinline)) int struct_flavors_global() { } } -enum relocated_enum_unsigned_32 { U32 = 0xBBBBBBBB }; +enum relocated_enum_unsigned_32 { U32_VAL = 0xBBBBBBBB }; __attribute__((noinline)) int enum_unsigned_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_32, U32)); + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); } -enum relocated_enum_signed_32 { S32 = -0x7BBBBBBB }; +enum relocated_enum_signed_32 { S32_VAL = -0x7BBBBBBB }; __attribute__((noinline)) int enum_signed_32_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_32, S32)); + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL)); } -enum relocated_enum_unsigned_64 { U64 = 0xCCCCCCCCDDDDDDDD }; +enum relocated_enum_unsigned_64 { U64_VAL = 0xCCCCCCCCDDDDDDDD }; __attribute__((noinline)) int enum_unsigned_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_unsigned_64, U64)); + return set_output( + bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); } -enum relocated_enum_signed_64 { u64 = -0xCCCCCCCDDDDDDDD }; +enum relocated_enum_signed_64 { S64_VAL = -0xCCCCCCCDDDDDDDD }; __attribute__((noinline)) int enum_signed_64_global() { - return set_output(bpf_core_enum_value(enum relocated_enum_signed_64, u64)); + return set_output( + bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL)); } // Avoids dead code elimination by the compiler. diff --git a/test/integration-test/src/tests/btf_relocations.rs b/test/integration-test/src/tests/btf_relocations.rs index 7e1020ba..79eb3e52 100644 --- a/test/integration-test/src/tests/btf_relocations.rs +++ b/test/integration-test/src/tests/btf_relocations.rs @@ -2,20 +2,20 @@ use test_case::test_case; use aya::{maps::Array, programs::UProbe, util::KernelVersion, BpfLoader, Btf, Endianness}; -#[test_case("field", false, None, 2)] -#[test_case("field", true, None, 1)] +#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)] +#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)] +#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)] +#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)] #[test_case("enum_unsigned_32", false, None, 0xAAAAAAAA)] #[test_case("enum_unsigned_32", true, None, 0xBBBBBBBB)] +#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)] +#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)] +#[test_case("field", false, None, 2)] +#[test_case("field", true, None, 1)] #[test_case("pointer", false, None, 42)] #[test_case("pointer", true, None, 21)] #[test_case("struct_flavors", false, None, 1)] -#[test_case("struct_flavors", true, None, 1)] -#[test_case("enum_signed_32", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7AAAAAAAi32 as u64)] -#[test_case("enum_signed_32", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0x7BBBBBBBi32 as u64)] -#[test_case("enum_unsigned_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xAAAAAAAABBBBBBBB)] -#[test_case("enum_unsigned_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), 0xCCCCCCCCDDDDDDDD)] -#[test_case("enum_signed_64", false, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xAAAAAAABBBBBBBBi64 as u64)] -#[test_case("enum_signed_64", true, Some((KernelVersion::new(6, 0, 0), "https://github.com/torvalds/linux/commit/6089fb3")), -0xCCCCCCCDDDDDDDDi64 as u64)] +#[test_case("struct_flavors", true, None, 2)] fn relocation_tests( program: &str, with_relocations: bool, From 71bc3ea0b5af95d9a6c6585d6be2dfa505acf43e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 7 Aug 2023 13:30:09 -0400 Subject: [PATCH 07/42] integration-test: avoid reliance on kernel headers This should allow us to build on any system. --- test/integration-test/bpf/ext.bpf.c | 2 +- test/integration-test/bpf/main.bpf.c | 2 +- test/integration-test/bpf/multimap-btf.bpf.c | 2 +- test/integration-test/bpf/reloc.bpf.c | 2 +- test/integration-test/bpf/reloc.btf.c | 2 +- test/integration-test/bpf/text_64_64_reloc.c | 2 +- test/integration-test/build.rs | 14 +++++++++++++- 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/test/integration-test/bpf/ext.bpf.c b/test/integration-test/bpf/ext.bpf.c index 6ec95229..2996fcf7 100644 --- a/test/integration-test/bpf/ext.bpf.c +++ b/test/integration-test/bpf/ext.bpf.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include // clang-format on diff --git a/test/integration-test/bpf/main.bpf.c b/test/integration-test/bpf/main.bpf.c index f60e42a9..b9365622 100644 --- a/test/integration-test/bpf/main.bpf.c +++ b/test/integration-test/bpf/main.bpf.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include // clang-format on diff --git a/test/integration-test/bpf/multimap-btf.bpf.c b/test/integration-test/bpf/multimap-btf.bpf.c index 07fcc60f..2bd7978b 100644 --- a/test/integration-test/bpf/multimap-btf.bpf.c +++ b/test/integration-test/bpf/multimap-btf.bpf.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include // clang-format on diff --git a/test/integration-test/bpf/reloc.bpf.c b/test/integration-test/bpf/reloc.bpf.c index f426874f..cb15dfc3 100644 --- a/test/integration-test/bpf/reloc.bpf.c +++ b/test/integration-test/bpf/reloc.bpf.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include #include // clang-format on diff --git a/test/integration-test/bpf/reloc.btf.c b/test/integration-test/bpf/reloc.btf.c index ec396552..d50cd943 100644 --- a/test/integration-test/bpf/reloc.btf.c +++ b/test/integration-test/bpf/reloc.btf.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include #include // clang-format on diff --git a/test/integration-test/bpf/text_64_64_reloc.c b/test/integration-test/bpf/text_64_64_reloc.c index cd273a35..067350cc 100644 --- a/test/integration-test/bpf/text_64_64_reloc.c +++ b/test/integration-test/bpf/text_64_64_reloc.c @@ -1,5 +1,5 @@ // clang-format off -#include +#include #include // clang-format on diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index bf4a0234..c1a8992f 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -116,10 +116,22 @@ fn main() { target_arch.push(arch); }; + // NB: libbpf's documentation suggests that vmlinux.h be generated by running `bpftool btf + // dump file /sys/kernel/btf/vmlinux format c`; this allows CO-RE to work. + // + // However in our tests we do not make use of kernel data structures, and so any vmlinux.h + // which defines the constants we need (e.g. `__u8`, `__u64`, `BPF_MAP_TYPE_ARRAY`, + // `BPF_ANY`, `XDP_PASS`, `XDP_DROP`, etc.) will suffice. Since we already have a libbpf + // submodule which happens to include such a file, we use it. + let libbpf_vmlinux_dir = libbpf_dir.join(".github/actions/build-selftests"); + let clang = || { let mut cmd = Command::new("clang"); - cmd.arg("-I") + cmd.arg("-nostdlibinc") + .arg("-I") .arg(&libbpf_headers_dir) + .arg("-I") + .arg(&libbpf_vmlinux_dir) .args(["-g", "-O2", "-target", target, "-c"]) .arg(&target_arch); cmd From 54c90ec72c6ed47a325c43ff2c34c27ae903524a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 4 Aug 2023 10:53:19 -0400 Subject: [PATCH 08/42] integration-test: De-duplicate BTF relocation test --- test/integration-test/bpf/reloc.bpf.c | 67 +++++++++++++---- test/integration-test/bpf/reloc.btf.c | 89 ----------------------- test/integration-test/build.rs | 100 +++++++++++++------------- test/integration-test/src/lib.rs | 3 +- 4 files changed, 107 insertions(+), 152 deletions(-) delete mode 100644 test/integration-test/bpf/reloc.btf.c diff --git a/test/integration-test/bpf/reloc.bpf.c b/test/integration-test/bpf/reloc.bpf.c index cb15dfc3..609e504b 100644 --- a/test/integration-test/bpf/reloc.bpf.c +++ b/test/integration-test/bpf/reloc.bpf.c @@ -4,7 +4,7 @@ #include // clang-format on -char _license[] __attribute__((section("license"), used)) = "GPL"; +char _license[] SEC("license") = "GPL"; struct { __uint(type, BPF_MAP_TYPE_ARRAY); @@ -19,12 +19,17 @@ long set_output(__u64 value) { } struct relocated_struct_with_scalars { +#ifndef TARGET __u8 a; +#endif __u8 b; __u8 c; +#ifdef TARGET + __u8 d; +#endif }; -__attribute__((noinline)) int field_global() { +__noinline int field_global() { struct relocated_struct_with_scalars s = {1, 2, 3}; return set_output(__builtin_preserve_access_index(s.b)); } @@ -32,11 +37,16 @@ __attribute__((noinline)) int field_global() { SEC("uprobe") int field(void *ctx) { return field_global(); } struct relocated_struct_with_pointer { +#ifndef TARGET struct relocated_struct_with_pointer *first; +#endif struct relocated_struct_with_pointer *second; +#ifdef TARGET + struct relocated_struct_with_pointer *first; +#endif }; -__attribute__((noinline)) int pointer_global() { +__noinline int pointer_global() { struct relocated_struct_with_pointer s = { (struct relocated_struct_with_pointer *)42, (struct relocated_struct_with_pointer *)21, @@ -46,10 +56,15 @@ __attribute__((noinline)) int pointer_global() { SEC("uprobe") int pointer(void *ctx) { return pointer_global(); } -__attribute__((noinline)) int struct_flavors_global() { +__noinline int struct_flavors_global() { struct relocated_struct_with_scalars s = {1, 2, 3}; +#ifndef TARGET if (bpf_core_field_exists(s.a)) { return set_output(__builtin_preserve_access_index(s.a)); +#else + if (bpf_core_field_exists(s.d)) { + return set_output(__builtin_preserve_access_index(s.d)); +#endif } else { return set_output(__builtin_preserve_access_index(s.c)); } @@ -57,9 +72,16 @@ __attribute__((noinline)) int struct_flavors_global() { SEC("uprobe") int struct_flavors(void *ctx) { return struct_flavors_global(); } -enum relocated_enum_unsigned_32 { U32_VAL = 0xAAAAAAAA }; +enum relocated_enum_unsigned_32 { + U32_VAL = +#ifndef TARGET + 0xAAAAAAAA +#else + 0xBBBBBBBB +#endif +}; -__attribute__((noinline)) int enum_unsigned_32_global() { +__noinline int enum_unsigned_32_global() { return set_output( bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); } @@ -68,18 +90,32 @@ SEC("uprobe") int enum_unsigned_32(void *ctx) { return enum_unsigned_32_global(); } -enum relocated_enum_signed_32 { S32_VAL = -0x7AAAAAAA }; +enum relocated_enum_signed_32 { + S32_VAL = +#ifndef TARGET + -0x7AAAAAAA +#else + -0x7BBBBBBB +#endif +}; -__attribute__((noinline)) int enum_signed_32_global() { +__noinline int enum_signed_32_global() { return set_output( bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL)); } SEC("uprobe") int enum_signed_32(void *ctx) { return enum_signed_32_global(); } -enum relocated_enum_unsigned_64 { U64_VAL = 0xAAAAAAAABBBBBBBB }; +enum relocated_enum_unsigned_64 { + U64_VAL = +#ifndef TARGET + 0xAAAAAAAABBBBBBBB +#else + 0xCCCCCCCCDDDDDDDD +#endif +}; -__attribute__((noinline)) int enum_unsigned_64_global() { +__noinline int enum_unsigned_64_global() { return set_output( bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); } @@ -88,9 +124,16 @@ SEC("uprobe") int enum_unsigned_64(void *ctx) { return enum_unsigned_64_global(); } -enum relocated_enum_signed_64 { S64_VAL = -0xAAAAAAABBBBBBBB }; +enum relocated_enum_signed_64 { + S64_VAL = +#ifndef TARGET + -0xAAAAAAABBBBBBBB +#else + -0xCCCCCCCDDDDDDDD +#endif +}; -__attribute__((noinline)) int enum_signed_64_global() { +__noinline int enum_signed_64_global() { return set_output( bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL)); } diff --git a/test/integration-test/bpf/reloc.btf.c b/test/integration-test/bpf/reloc.btf.c deleted file mode 100644 index d50cd943..00000000 --- a/test/integration-test/bpf/reloc.btf.c +++ /dev/null @@ -1,89 +0,0 @@ -// clang-format off -#include -#include -#include -// clang-format on - -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); -} output_map SEC(".maps"); - -long set_output(__u64 value) { - __u32 key = 0; - return bpf_map_update_elem(&output_map, &key, &value, BPF_ANY); -} - -struct relocated_struct_with_scalars { - __u8 b; - __u8 c; - __u8 d; -}; - -__attribute__((noinline)) int field_global() { - struct relocated_struct_with_scalars s = {1, 2, 3}; - return set_output(__builtin_preserve_access_index(s.b)); -} - -struct relocated_struct_with_pointer { - struct relocated_struct_with_pointer *second; - struct relocated_struct_with_pointer *first; -}; - -__attribute__((noinline)) int pointer_global() { - struct relocated_struct_with_pointer s = { - (struct relocated_struct_with_pointer *)42, - (struct relocated_struct_with_pointer *)21, - }; - return set_output((__u64)__builtin_preserve_access_index(s.first)); -} - -__attribute__((noinline)) int struct_flavors_global() { - struct relocated_struct_with_scalars s = {1, 2, 3}; - if (bpf_core_field_exists(s.b)) { - return set_output(__builtin_preserve_access_index(s.b)); - } else { - return set_output(__builtin_preserve_access_index(s.c)); - } -} - -enum relocated_enum_unsigned_32 { U32_VAL = 0xBBBBBBBB }; - -__attribute__((noinline)) int enum_unsigned_32_global() { - return set_output( - bpf_core_enum_value(enum relocated_enum_unsigned_32, U32_VAL)); -} - -enum relocated_enum_signed_32 { S32_VAL = -0x7BBBBBBB }; - -__attribute__((noinline)) int enum_signed_32_global() { - return set_output( - bpf_core_enum_value(enum relocated_enum_signed_32, S32_VAL)); -} - -enum relocated_enum_unsigned_64 { U64_VAL = 0xCCCCCCCCDDDDDDDD }; - -__attribute__((noinline)) int enum_unsigned_64_global() { - return set_output( - bpf_core_enum_value(enum relocated_enum_unsigned_64, U64_VAL)); -} - -enum relocated_enum_signed_64 { S64_VAL = -0xCCCCCCCDDDDDDDD }; - -__attribute__((noinline)) int enum_signed_64_global() { - return set_output( - bpf_core_enum_value(enum relocated_enum_signed_64, S64_VAL)); -} - -// Avoids dead code elimination by the compiler. -int main() { - field_global(); - pointer_global(); - struct_flavors_global(); - enum_unsigned_32_global(); - enum_signed_32_global(); - enum_unsigned_64_global(); - enum_signed_64_global(); -} diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index c1a8992f..fec40483 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -64,20 +64,14 @@ fn main() { panic!("unsupported endian={:?}", endian) }; - const C_BPF: &[(&str, &str)] = &[ - ("ext.bpf.c", "ext.bpf.o"), - ("main.bpf.c", "main.bpf.o"), - ("multimap-btf.bpf.c", "multimap-btf.bpf.o"), - ("reloc.bpf.c", "reloc.bpf.o"), - ("text_64_64_reloc.c", "text_64_64_reloc.o"), + const C_BPF: &[(&str, bool)] = &[ + ("ext.bpf.c", false), + ("main.bpf.c", false), + ("multimap-btf.bpf.c", false), + ("reloc.bpf.c", true), + ("text_64_64_reloc.c", false), ]; - let c_bpf = C_BPF.iter().map(|(src, dst)| (src, out_dir.join(dst))); - - const C_BTF: &[(&str, &str)] = &[("reloc.btf.c", "reloc.btf.o")]; - - let c_btf = C_BTF.iter().map(|(src, dst)| (src, out_dir.join(dst))); - if build_integration_bpf { let libbpf_dir = manifest_dir .parent() @@ -137,46 +131,47 @@ fn main() { cmd }; - for (src, dst) in c_bpf { - let src = bpf_dir.join(src); - println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - - exec(clang().arg(src).arg("-o").arg(dst)).unwrap(); - } - - for (src, dst) in c_btf { + for (src, build_btf) in C_BPF { + let dst = out_dir.join(src).with_extension("o"); let src = bpf_dir.join(src); println!("cargo:rerun-if-changed={}", src.to_str().unwrap()); - let mut cmd = clang(); - let mut child = cmd - .arg(src) - .args(["-o", "-"]) - .stdout(Stdio::piped()) - .spawn() - .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); - - let Child { stdout, .. } = &mut child; - let stdout = stdout.take().unwrap(); - - let mut output = OsString::new(); - output.push(".BTF="); - output.push(dst); - exec( - // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. - Command::new("llvm-objcopy") - .arg("--dump-section") - .arg(output) - .arg("-") - .stdin(stdout), - ) - .unwrap(); - - let output = child - .wait_with_output() - .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); - let Output { status, .. } = &output; - assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); + exec(clang().arg(&src).arg("-o").arg(&dst)).unwrap(); + + if *build_btf { + let mut cmd = clang(); + let mut child = cmd + .arg("-DTARGET") + .arg(&src) + .args(["-o", "-"]) + .stdout(Stdio::piped()) + .spawn() + .unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); + + let Child { stdout, .. } = &mut child; + let stdout = stdout.take().unwrap(); + + let dst = dst.with_extension("target.o"); + + let mut output = OsString::new(); + output.push(".BTF="); + output.push(dst); + exec( + // NB: objcopy doesn't support reading from stdin, so we have to use llvm-objcopy. + Command::new("llvm-objcopy") + .arg("--dump-section") + .arg(output) + .arg("-") + .stdin(stdout), + ) + .unwrap(); + + let output = child + .wait_with_output() + .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); + let Output { status, .. } = &output; + assert_eq!(status.code(), Some(0), "{cmd:?} failed: {output:?}"); + } } let target = format!("{target}-unknown-none"); @@ -268,8 +263,13 @@ fn main() { .unwrap_or_else(|err| panic!("failed to copy {binary:?} to {dst:?}: {err}")); } } else { - for (_src, dst) in c_bpf.chain(c_btf) { + for (src, build_btf) in C_BPF { + let dst = out_dir.join(src).with_extension("o"); fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); + if *build_btf { + let dst = dst.with_extension("target.o"); + fs::write(&dst, []).unwrap_or_else(|err| panic!("failed to create {dst:?}: {err}")); + } } let Package { targets, .. } = integration_ebpf_package; diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 80cd0b1d..08911a4e 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -5,7 +5,8 @@ pub const MAIN: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.b pub const MULTIMAP_BTF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/multimap-btf.bpf.o")); pub const RELOC_BPF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.o")); -pub const RELOC_BTF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.btf.o")); +pub const RELOC_BTF: &[u8] = + include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.target.o")); pub const TEXT_64_64_RELOC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o")); From fe047d79a3f501631ae6406444769f6d5f6fed24 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 9 Aug 2023 09:58:39 -0400 Subject: [PATCH 09/42] aya-log-common: Simplify - Remove `TagLenValue`; this type has a single method, which is now a function. - Remove generics from `TagLenValue::write` (now `write`). The tag is always `u8`, and the value is always a sequence of bytes. - Replace slicing operations which can panic with calls to `get` which explicit check bounds. --- aya-log-common/src/lib.rs | 107 +++++++++++----------------- xtask/public-api/aya-log-common.txt | 4 ++ 2 files changed, 44 insertions(+), 67 deletions(-) diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index 0d789e3b..c634c51e 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::{mem, num, ptr}; +use core::num; use num_enum::IntoPrimitive; @@ -86,7 +86,7 @@ pub trait UpperMacFormatter {} impl UpperMacFormatter for [u8; 6] {} #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, IntoPrimitive)] pub enum RecordField { Target = 1, Level, @@ -99,7 +99,7 @@ pub enum RecordField { /// Types which are supported by aya-log and can be safely sent from eBPF /// programs to userspace. #[repr(u8)] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, IntoPrimitive)] pub enum Argument { DisplayHint, @@ -147,53 +147,24 @@ pub enum DisplayHint { UpperMac, } -struct TagLenValue { - pub tag: T, - pub value: V, -} - -impl TagLenValue -where - V: IntoIterator, - ::IntoIter: ExactSizeIterator, -{ - pub(crate) fn write(self, mut buf: &mut [u8]) -> Result { - // Break the abstraction to please the verifier. - if buf.len() > LOG_BUF_CAPACITY { - buf = &mut buf[..LOG_BUF_CAPACITY]; - } - let Self { tag, value } = self; - let value = value.into_iter(); - let len = value.len(); - let wire_len: LogValueLength = value - .len() - .try_into() - .map_err(|num::TryFromIntError { .. }| ())?; - let size = mem::size_of_val(&tag) + mem::size_of_val(&wire_len) + len; - if size > buf.len() { - return Err(()); - } - - let tag_size = mem::size_of_val(&tag); - unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, tag) }; - buf = &mut buf[tag_size..]; - - unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, wire_len) }; - buf = &mut buf[mem::size_of_val(&wire_len)..]; - - buf.iter_mut().zip(value).for_each(|(dst, src)| { - *dst = src; - }); - - Ok(size) - } -} - -impl TagLenValue { - #[inline(always)] - pub(crate) fn new(tag: T, value: V) -> TagLenValue { - TagLenValue { tag, value } +pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Result { + let wire_len: LogValueLength = value + .len() + .try_into() + .map_err(|num::TryFromIntError { .. }| ())?; + let mut size = 0; + macro_rules! copy_from_slice { + ($value:expr) => {{ + let buf = buf.get_mut(size..).ok_or(())?; + let buf = buf.get_mut(..$value.len()).ok_or(())?; + buf.copy_from_slice($value); + size += $value.len(); + }}; } + copy_from_slice!(&[tag]); + copy_from_slice!(&wire_len.to_ne_bytes()); + copy_from_slice!(value); + Ok(size) } pub trait WriteToBuf { @@ -205,7 +176,7 @@ macro_rules! impl_write_to_buf { ($type:ident, $arg_type:expr) => { impl WriteToBuf for $type { fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new($arg_type, self.to_ne_bytes()).write(buf) + write($arg_type.into(), &self.to_ne_bytes(), buf) } } }; @@ -228,45 +199,45 @@ impl_write_to_buf!(f64, Argument::F64); impl WriteToBuf for [u8; 16] { fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::ArrU8Len16, self).write(buf) + write(Argument::ArrU8Len16.into(), &self, buf) } } impl WriteToBuf for [u16; 8] { fn write(self, buf: &mut [u8]) -> Result { let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) }; - TagLenValue::new(Argument::ArrU16Len8, bytes).write(buf) + write(Argument::ArrU16Len8.into(), &bytes, buf) } } impl WriteToBuf for [u8; 6] { fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::ArrU8Len6, self).write(buf) + write(Argument::ArrU8Len6.into(), &self, buf) } } impl WriteToBuf for &[u8] { fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::Bytes, self.iter().copied()).write(buf) + write(Argument::Bytes.into(), self, buf) } } impl WriteToBuf for &str { fn write(self, buf: &mut [u8]) -> Result { - TagLenValue::new(Argument::Str, self.as_bytes().iter().copied()).write(buf) + write(Argument::Str.into(), self.as_bytes(), buf) } } impl WriteToBuf for DisplayHint { fn write(self, buf: &mut [u8]) -> Result { let v: u8 = self.into(); - TagLenValue::new(Argument::DisplayHint, v.to_ne_bytes()).write(buf) + write(Argument::DisplayHint.into(), &v.to_ne_bytes(), buf) } } #[allow(clippy::result_unit_err)] #[doc(hidden)] -#[inline(always)] +#[inline(always)] // This function takes too many arguments to not be inlined. pub fn write_record_header( buf: &mut [u8], target: &str, @@ -278,16 +249,18 @@ pub fn write_record_header( ) -> Result { let level: u8 = level.into(); let mut size = 0; - size += TagLenValue::new(RecordField::Target, target.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Level, level.to_ne_bytes()).write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Module, module.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::File, file.as_bytes().iter().copied()) - .write(&mut buf[size..])?; - size += TagLenValue::new(RecordField::Line, line.to_ne_bytes()).write(&mut buf[size..])?; - size += - TagLenValue::new(RecordField::NumArgs, num_args.to_ne_bytes()).write(&mut buf[size..])?; + macro_rules! write { + ($tag:expr, $value:expr) => {{ + let buf = buf.get_mut(size..).ok_or(())?; + size += write($tag.into(), $value, buf)?; + }}; + } + write!(RecordField::Target, target.as_bytes()); + write!(RecordField::Level, &level.to_ne_bytes()); + write!(RecordField::Module, module.as_bytes()); + write!(RecordField::File, file.as_bytes()); + write!(RecordField::Line, &line.to_ne_bytes()); + write!(RecordField::NumArgs, &num_args.to_ne_bytes()); Ok(size) } diff --git a/xtask/public-api/aya-log-common.txt b/xtask/public-api/aya-log-common.txt index 7e28268a..1b3e48c1 100644 --- a/xtask/public-api/aya-log-common.txt +++ b/xtask/public-api/aya-log-common.txt @@ -18,6 +18,8 @@ pub aya_log_common::Argument::U32 pub aya_log_common::Argument::U64 pub aya_log_common::Argument::U8 pub aya_log_common::Argument::Usize +impl core::convert::From for u8 +pub fn u8::from(enum_value: aya_log_common::Argument) -> Self impl core::clone::Clone for aya_log_common::Argument pub fn aya_log_common::Argument::clone(&self) -> aya_log_common::Argument impl core::fmt::Debug for aya_log_common::Argument @@ -134,6 +136,8 @@ pub aya_log_common::RecordField::Line pub aya_log_common::RecordField::Module pub aya_log_common::RecordField::NumArgs pub aya_log_common::RecordField::Target = 1 +impl core::convert::From for u8 +pub fn u8::from(enum_value: aya_log_common::RecordField) -> Self impl core::clone::Clone for aya_log_common::RecordField pub fn aya_log_common::RecordField::clone(&self) -> aya_log_common::RecordField impl core::fmt::Debug for aya_log_common::RecordField From 3cfd886dc512872fd3948cdf3baa8c99fe27ef0f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 18:48:51 -0400 Subject: [PATCH 10/42] log: annotate logging functions inlining Some of these functions fail to compile when not inlined, so we should be explicit. Before deciding on this approach I tried various ways of making all these functions #[inline(never)] to save instructions but I ran into blockers: - These functions currently return Result, which is a structure. This is not permitted in BPF. - I tried inventing a newtype that is a #[repr(transparent)] wrapper of u16, and having these functions return that; however it seems that even if the object code is legal, the verifier will reject such functions because the BTF (if present, and it was in my local experiments) would indicate that the return is a structure. - I tried having these functions return a plain u16 where 0 means error, but the verifier still rejected the BTF because the receiver (even if made into &self) is considered a structure, and forbidden. We can eventually overcome these problems by "lying" in our BTF once support for it matures in the bpf-linker repo (e.g. Option should be perfectly legal as it is guaranteed to be word-sized), but we aren't there yet, and this is the safest thing we can do for now. --- aya-log-common/src/lib.rs | 27 ++++++++++++++++++++++++++ test/integration-ebpf/src/log.rs | 9 ++++++++- test/integration-test/src/tests/log.rs | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index c634c51e..ba20876f 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -147,6 +147,10 @@ pub enum DisplayHint { UpperMac, } +// Must be inlined, else the BPF backend emits: +// +// llvm: :0:0: in function _ZN14aya_log_common5write17hc9ed05433e23a663E { i64, i64 } (i8, ptr, i64, ptr, i64): only integer returns supported +#[inline(always)] pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Result { let wire_len: LogValueLength = value .len() @@ -175,6 +179,9 @@ pub trait WriteToBuf { macro_rules! impl_write_to_buf { ($type:ident, $arg_type:expr) => { impl WriteToBuf for $type { + // This need not be inlined because the return value is Result where N is + // mem::size_of<$type>, which is a compile-time constant. + #[inline(never)] fn write(self, buf: &mut [u8]) -> Result { write($arg_type.into(), &self.to_ne_bytes(), buf) } @@ -198,12 +205,18 @@ impl_write_to_buf!(f32, Argument::F32); impl_write_to_buf!(f64, Argument::F64); impl WriteToBuf for [u8; 16] { + // This need not be inlined because the return value is Result where N is 16, which is a + // compile-time constant. + #[inline(never)] fn write(self, buf: &mut [u8]) -> Result { write(Argument::ArrU8Len16.into(), &self, buf) } } impl WriteToBuf for [u16; 8] { + // This need not be inlined because the return value is Result where N is 16, which is a + // compile-time constant. + #[inline(never)] fn write(self, buf: &mut [u8]) -> Result { let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) }; write(Argument::ArrU16Len8.into(), &bytes, buf) @@ -211,24 +224,38 @@ impl WriteToBuf for [u16; 8] { } impl WriteToBuf for [u8; 6] { + // This need not be inlined because the return value is Result where N is 6, which is a + // compile-time constant. + #[inline(never)] fn write(self, buf: &mut [u8]) -> Result { write(Argument::ArrU8Len6.into(), &self, buf) } } impl WriteToBuf for &[u8] { + // Must be inlined, else the BPF backend emits: + // + // llvm: :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 + #[inline(always)] fn write(self, buf: &mut [u8]) -> Result { write(Argument::Bytes.into(), self, buf) } } impl WriteToBuf for &str { + // Must be inlined, else the BPF backend emits: + // + // llvm: :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 + #[inline(always)] fn write(self, buf: &mut [u8]) -> Result { write(Argument::Str.into(), self.as_bytes(), buf) } } impl WriteToBuf for DisplayHint { + // This need not be inlined because the return value is Result where N is 1, which is a + // compile-time constant. + #[inline(never)] fn write(self, buf: &mut [u8]) -> Result { let v: u8 = self.into(); write(Argument::DisplayHint.into(), &v.to_ne_bytes(), buf) diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs index 03cdde76..51c1a46d 100644 --- a/test/integration-ebpf/src/log.rs +++ b/test/integration-ebpf/src/log.rs @@ -7,7 +7,14 @@ use aya_log_ebpf::{debug, error, info, trace, warn}; #[uprobe] pub fn test_log(ctx: ProbeContext) { debug!(&ctx, "Hello from eBPF!"); - error!(&ctx, "{}, {}, {}", 69, 420i32, "wao"); + error!( + &ctx, + "{}, {}, {}, {:x}", + 69, + 420i32, + "wao", + "wao".as_bytes() + ); let ipv4 = 167772161u32; // 10.0.0.1 let ipv6 = [ 32u8, 1u8, 13u8, 184u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, diff --git a/test/integration-test/src/tests/log.rs b/test/integration-test/src/tests/log.rs index 8645762b..65ad34eb 100644 --- a/test/integration-test/src/tests/log.rs +++ b/test/integration-test/src/tests/log.rs @@ -92,7 +92,7 @@ async fn log() { assert_eq!( records.next(), Some(&CapturedLog { - body: "69, 420, wao".into(), + body: "69, 420, wao, 77616f".into(), level: Level::Error, target: "log".into(), }) From e38e2566e3393034b37c299e50c6a4b70d51ad1d Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Mon, 7 Aug 2023 14:07:46 +0100 Subject: [PATCH 11/42] aya, aya-obj: Implement ENUM64 fixups This commit adds: - A probe to see if the ENUM64 feature is supported - Fixups for the use of signed enums, or enum64 types on systems where enum64 is not supported Signed-off-by: Dave Tucker --- aya-obj/src/btf/btf.rs | 198 ++++++++++++++++++++++++++++++----- aya-obj/src/btf/types.rs | 76 +++++++++++++- aya/src/bpf.rs | 5 +- aya/src/sys/bpf.rs | 17 +++ xtask/public-api/aya-obj.txt | 9 +- 5 files changed, 275 insertions(+), 30 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 59f8e3cb..8c8469a5 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -17,7 +17,7 @@ use crate::{ info::{FuncSecInfo, LineSecInfo}, relocation::Relocation, Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int, - IntEncoding, LineInfo, Struct, Typedef, VarLinkage, + IntEncoding, LineInfo, Struct, Typedef, Union, VarLinkage, }, generated::{btf_ext_header, btf_header}, util::{bytes_of, HashMap}, @@ -171,6 +171,7 @@ pub struct BtfFeatures { btf_float: bool, btf_decl_tag: bool, btf_type_tag: bool, + btf_enum64: bool, } impl BtfFeatures { @@ -182,6 +183,7 @@ impl BtfFeatures { btf_float: bool, btf_decl_tag: bool, btf_type_tag: bool, + btf_enum64: bool, ) -> Self { BtfFeatures { btf_func, @@ -190,6 +192,7 @@ impl BtfFeatures { btf_float, btf_decl_tag, btf_type_tag, + btf_enum64, } } @@ -227,6 +230,11 @@ impl BtfFeatures { pub fn btf_kind_func_proto(&self) -> bool { self.btf_func && self.btf_decl_tag } + + /// Returns true if the BTF_KIND_ENUM64 is supported. + pub fn btf_enum64(&self) -> bool { + self.btf_enum64 + } } /// Bpf Type Format metadata. @@ -467,29 +475,51 @@ impl Btf { buf } + // This follows the same logic as libbpf's bpf_object__sanitize_btf() function. + // https://github.com/libbpf/libbpf/blob/05f94ddbb837f5f4b3161e341eed21be307eaa04/src/libbpf.c#L2701 + // + // Fixup: The loader needs to adjust values in the BTF before it's loaded into the kernel. + // Sanitize: Replace an unsupported BTF type with a placeholder type. + // + // In addition to the libbpf logic, it performs some fixups to the BTF generated by bpf-linker + // for Aya programs. These fixups are gradually moving into bpf-linker itself. pub(crate) fn fixup_and_sanitize( &mut self, section_infos: &HashMap, symbol_offsets: &HashMap, features: &BtfFeatures, ) -> Result<(), BtfError> { + // ENUM64 placeholder type needs to be added before we take ownership of + // self.types to ensure that the offsets in the BtfHeader are correct. + let placeholder_name = self.add_string("enum64_placeholder"); + let enum64_placeholder_id = (!features.btf_enum64 + && self.types().any(|t| t.kind() == BtfKind::Enum64)) + .then(|| { + self.add_type(BtfType::Int(Int::new( + placeholder_name, + 1, + IntEncoding::None, + 0, + ))) + }); let mut types = mem::take(&mut self.types); for i in 0..types.types.len() { let t = &mut types.types[i]; let kind = t.kind(); match t { - // Fixup PTR for Rust - // LLVM emits names for Rust pointer types, which the kernel doesn't like + // Fixup PTR for Rust. + // + // LLVM emits names for Rust pointer types, which the kernel doesn't like. // While I figure out if this needs fixing in the Kernel or LLVM, we'll - // do a fixup here + // do a fixup here. BtfType::Ptr(ptr) => { ptr.name_offset = 0; } - // Sanitize VAR if they are not supported + // Sanitize VAR if they are not supported. BtfType::Var(v) if !features.btf_datasec => { types.types[i] = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); } - // Sanitize DATASEC if they are not supported + // Sanitize DATASEC if they are not supported. BtfType::DataSec(d) if !features.btf_datasec => { debug!("{}: not supported. replacing with STRUCT", kind); @@ -497,7 +527,7 @@ impl Btf { let mut name_offset = d.name_offset; let name = self.string_at(name_offset)?; - // Handle any "." characters in struct names + // Handle any "." characters in struct names. // Example: ".maps" let fixed_name = name.replace('.', "_"); if fixed_name != name { @@ -521,29 +551,29 @@ impl Btf { types.types[i] = BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32)); } - // Fixup DATASEC - // DATASEC sizes aren't always set by LLVM - // we need to fix them here before loading the btf to the kernel + // Fixup DATASEC. + // + // DATASEC sizes aren't always set by LLVM so we need to fix them + // here before loading the btf to the kernel. BtfType::DataSec(d) if features.btf_datasec => { // Start DataSec Fixups let name = self.string_at(d.name_offset)?; let name = name.into_owned(); - // Handle any "/" characters in section names + // Handle any "/" characters in section names. // Example: "maps/hashmap" let fixed_name = name.replace('/', "."); if fixed_name != name { d.name_offset = self.add_string(&fixed_name); } - // There are some cases when the compiler does indeed populate the - // size + // There are some cases when the compiler does indeed populate the size. if d.size > 0 { debug!("{} {}: size fixup not required", kind, name); } else { - // We need to get the size of the section from the ELF file + // We need to get the size of the section from the ELF file. // Fortunately, we cached these when parsing it initially - // and we can this up by name in section_infos + // and we can this up by name in section_infos. let size = match section_infos.get(&name) { Some((_, size)) => size, None => { @@ -557,7 +587,7 @@ impl Btf { // that need to have their offsets adjusted. To do this, // we need to get the offset from the ELF file. // This was also cached during initial parsing and - // we can query by name in symbol_offsets + // we can query by name in symbol_offsets. let mut entries = mem::take(&mut d.entries); let mut fixed_section = d.clone(); @@ -593,7 +623,7 @@ impl Btf { types.types[i] = BtfType::DataSec(fixed_section); } } - // Fixup FUNC_PROTO + // Fixup FUNC_PROTO. BtfType::FuncProto(ty) if features.btf_func => { for (i, param) in ty.params.iter_mut().enumerate() { if param.name_offset == 0 && param.btf_type != 0 { @@ -601,7 +631,7 @@ impl Btf { } } } - // Sanitize FUNC_PROTO + // Sanitize FUNC_PROTO. BtfType::FuncProto(ty) if !features.btf_func => { debug!("{}: not supported. replacing with ENUM", kind); let members: Vec = ty @@ -612,13 +642,13 @@ impl Btf { value: p.btf_type, }) .collect(); - let enum_type = BtfType::Enum(Enum::new(ty.name_offset, members)); + let enum_type = BtfType::Enum(Enum::new(ty.name_offset, false, members)); types.types[i] = enum_type; } - // Sanitize FUNC + // Sanitize FUNC. BtfType::Func(ty) => { let name = self.string_at(ty.name_offset)?; - // Sanitize FUNC + // Sanitize FUNC. if !features.btf_func { debug!("{}: not supported. replacing with TYPEDEF", kind); let typedef_type = @@ -648,25 +678,48 @@ impl Btf { } } } - // Sanitize FLOAT + // Sanitize FLOAT. BtfType::Float(ty) if !features.btf_float => { debug!("{}: not supported. replacing with STRUCT", kind); let struct_ty = BtfType::Struct(Struct::new(0, vec![], ty.size)); types.types[i] = struct_ty; } - // Sanitize DECL_TAG + // Sanitize DECL_TAG. BtfType::DeclTag(ty) if !features.btf_decl_tag => { debug!("{}: not supported. replacing with INT", kind); let int_type = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); types.types[i] = int_type; } - // Sanitize TYPE_TAG + // Sanitize TYPE_TAG. BtfType::TypeTag(ty) if !features.btf_type_tag => { debug!("{}: not supported. replacing with CONST", kind); let const_type = BtfType::Const(Const::new(ty.btf_type)); types.types[i] = const_type; } - // The type does not need fixing up or sanitization + // Sanitize Signed ENUMs. + BtfType::Enum(ty) if !features.btf_enum64 && ty.is_signed() => { + debug!("{}: signed ENUMs not supported. Marking as unsigned", kind); + ty.set_signed(false); + } + // Sanitize ENUM64. + BtfType::Enum64(ty) if !features.btf_enum64 => { + debug!("{}: not supported. replacing with UNION", kind); + let placeholder_id = + enum64_placeholder_id.expect("enum64_placeholder_id must be set"); + let members: Vec = ty + .variants + .iter() + .map(|v| BtfMember { + name_offset: v.name_offset, + btf_type: placeholder_id, + offset: 0, + }) + .collect(); + let union_type = + BtfType::Union(Union::new(ty.name_offset, members.len() as u32, members)); + types.types[i] = union_type; + } + // The type does not need fixing up or sanitization. _ => {} } } @@ -1054,7 +1107,8 @@ pub(crate) struct SecInfo<'a> { mod tests { use super::*; use crate::btf::{ - BtfParam, DataSec, DataSecEntry, DeclTag, Float, Func, FuncProto, Ptr, TypeTag, Var, + BtfEnum64, BtfParam, DataSec, DataSecEntry, DeclTag, Enum64, Float, Func, FuncProto, Ptr, + TypeTag, Var, }; use assert_matches::assert_matches; @@ -1676,4 +1730,96 @@ mod tests { let u32_ty = btf.type_by_id(u32_base).unwrap(); assert_eq!(u32_ty.kind(), BtfKind::Int); } + + #[test] + fn test_sanitize_signed_enum() { + let mut btf = Btf::new(); + let name_offset = btf.add_string("signed_enum"); + let name_a = btf.add_string("A"); + let name_b = btf.add_string("B"); + let name_c = btf.add_string("C"); + let enum64_type = Enum::new( + name_offset, + true, + vec![ + BtfEnum::new(name_a, -1i32 as u32), + BtfEnum::new(name_b, -2i32 as u32), + BtfEnum::new(name_c, -3i32 as u32), + ], + ); + let enum_type_id = btf.add_type(BtfType::Enum(enum64_type)); + + let features = BtfFeatures { + btf_enum64: false, + ..Default::default() + }; + + btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) + .unwrap(); + + assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Enum(fixed) => { + assert!(!fixed.is_signed()); + assert_matches!(fixed.variants[..], [ + BtfEnum { name_offset: name1, value: 0xFFFF_FFFF }, + BtfEnum { name_offset: name2, value: 0xFFFF_FFFE }, + BtfEnum { name_offset: name3, value: 0xFFFF_FFFD }, + ] => { + assert_eq!(name1, name_a); + assert_eq!(name2, name_b); + assert_eq!(name3, name_c); + }); + }); + + // Ensure we can convert to bytes and back again. + let raw = btf.to_bytes(); + Btf::parse(&raw, Endianness::default()).unwrap(); + } + + #[test] + fn test_sanitize_enum64() { + let mut btf = Btf::new(); + let name_offset = btf.add_string("enum64"); + let name_a = btf.add_string("A"); + let name_b = btf.add_string("B"); + let name_c = btf.add_string("C"); + let enum64_type = Enum64::new( + name_offset, + false, + vec![ + BtfEnum64::new(name_a, 1), + BtfEnum64::new(name_b, 2), + BtfEnum64::new(name_c, 3), + ], + ); + let enum_type_id = btf.add_type(BtfType::Enum64(enum64_type)); + + let features = BtfFeatures { + btf_enum64: false, + ..Default::default() + }; + + btf.fixup_and_sanitize(&HashMap::new(), &HashMap::new(), &features) + .unwrap(); + + assert_matches!(btf.type_by_id(enum_type_id).unwrap(), BtfType::Union(fixed) => { + let placeholder = btf.id_by_type_name_kind("enum64_placeholder", BtfKind::Int) + .expect("enum64_placeholder type not found"); + assert_matches!(fixed.members[..], [ + BtfMember { name_offset: name_offset1, btf_type: btf_type1, offset: 0 }, + BtfMember { name_offset: name_offset2, btf_type: btf_type2, offset: 0 }, + BtfMember { name_offset: name_offset3, btf_type: btf_type3, offset: 0 }, + ] => { + assert_eq!(name_offset1, name_a); + assert_eq!(btf_type1, placeholder); + assert_eq!(name_offset2, name_b); + assert_eq!(btf_type2, placeholder); + assert_eq!(name_offset3, name_c); + assert_eq!(btf_type3, placeholder); + }); + }); + + // Ensure we can convert to bytes and back again. + let raw = btf.to_bytes(); + Btf::parse(&raw, Endianness::default()).unwrap(); + } } diff --git a/aya-obj/src/btf/types.rs b/aya-obj/src/btf/types.rs index a910b126..895484df 100644 --- a/aya-obj/src/btf/types.rs +++ b/aya-obj/src/btf/types.rs @@ -400,6 +400,12 @@ pub struct BtfEnum { pub value: u32, } +impl BtfEnum { + pub fn new(name_offset: u32, value: u32) -> Self { + Self { name_offset, value } + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct Enum { @@ -439,9 +445,12 @@ impl Enum { mem::size_of::() + mem::size_of::() * self.variants.len() } - pub fn new(name_offset: u32, variants: Vec) -> Self { + pub fn new(name_offset: u32, signed: bool, variants: Vec) -> Self { let mut info = (BtfKind::Enum as u32) << 24; info |= (variants.len() as u32) & 0xFFFF; + if signed { + info |= 1 << 31; + } Self { name_offset, info, @@ -453,6 +462,14 @@ impl Enum { pub(crate) fn is_signed(&self) -> bool { self.info >> 31 == 1 } + + pub(crate) fn set_signed(&mut self, signed: bool) { + if signed { + self.info |= 1 << 31; + } else { + self.info &= !(1 << 31); + } + } } #[repr(C)] @@ -463,6 +480,16 @@ pub struct BtfEnum64 { pub(crate) value_high: u32, } +impl BtfEnum64 { + pub fn new(name_offset: u32, value: u64) -> Self { + Self { + name_offset, + value_low: value as u32, + value_high: (value >> 32) as u32, + } + } +} + #[repr(C)] #[derive(Clone, Debug)] pub struct Enum64 { @@ -515,6 +542,26 @@ impl Enum64 { pub(crate) fn is_signed(&self) -> bool { self.info >> 31 == 1 } + + pub fn new(name_offset: u32, signed: bool, variants: Vec) -> Self { + let mut info = (BtfKind::Enum64 as u32) << 24; + if signed { + info |= 1 << 31 + }; + info |= (variants.len() as u32) & 0xFFFF; + Enum64 { + name_offset, + info, + // According to the documentation: + // + // https://www.kernel.org/doc/html/next/bpf/btf.html + // + // The size may be 1/2/4/8. Since BtfEnum64::new() takes a u64, we + // can assume that the size is 8. + size: 8, + variants, + } + } } #[repr(C)] @@ -614,6 +661,16 @@ pub struct Union { } impl Union { + pub(crate) fn new(name_offset: u32, size: u32, members: Vec) -> Self { + let info = (BtfKind::Union as u32) << 24; + Self { + name_offset, + info, + size, + members, + } + } + pub(crate) fn to_bytes(&self) -> Vec { let Self { name_offset, @@ -1794,4 +1851,21 @@ mod tests { assert!(types_are_compatible(&btf, u32t, &btf, u64t).unwrap()); assert!(types_are_compatible(&btf, array_type, &btf, array_type).unwrap()); } + + #[test] + pub fn test_read_btf_type_enum64() { + let endianness = Endianness::default(); + let data: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, // name offset + 0x01, 0x00, 0x00, 0x13, // info: vlen, type_kind + 0x08, 0x00, 0x00, 0x00, // size + 0xd7, 0x06, 0x00, 0x00, // enum variant name offset + 0xbb, 0xbb, 0xbb, 0xbb, // enum variant low + 0xaa, 0xaa, 0xaa, 0xaa, // enum variant high + ]; + + assert_matches!(unsafe { BtfType::read(data, endianness) }.unwrap(), BtfType::Enum64(got) => { + assert_eq!(got.to_bytes(), data); + }); + } } diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index d768770c..6b63c103 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -39,8 +39,8 @@ use crate::{ sys::{ bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_bpf_cookie_supported, is_bpf_global_data_supported, is_btf_datasec_supported, is_btf_decl_tag_supported, - is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported, - is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, + is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported, + is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, SyscallError, }, @@ -84,6 +84,7 @@ fn detect_features() -> Features { is_btf_float_supported(), is_btf_decl_tag_supported(), is_btf_type_tag_supported(), + is_btf_enum64_supported(), )) } else { None diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index d3446cc8..597edc76 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -10,6 +10,7 @@ use std::{ use crate::util::KernelVersion; use libc::{c_char, c_long, close, ENOENT, ENOSPC}; use obj::{ + btf::{BtfEnum64, Enum64}, maps::{bpf_map_def, LegacyMap}, BpfSectionKind, VerifierLog, }; @@ -873,6 +874,22 @@ pub(crate) fn is_btf_datasec_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } +pub(crate) fn is_btf_enum64_supported() -> bool { + let mut btf = Btf::new(); + let name_offset = btf.add_string("enum64"); + + let enum_64_type = BtfType::Enum64(Enum64::new( + name_offset, + true, + vec![BtfEnum64::new(btf.add_string("a"), 1)], + )); + btf.add_type(enum_64_type); + + let btf_bytes = btf.to_bytes(); + + bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() +} + pub(crate) fn is_btf_float_supported() -> bool { let mut btf = Btf::new(); let name_offset = btf.add_string("float"); diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 398df4d8..57efafb4 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -384,6 +384,8 @@ pub fn aya_obj::btf::Btf::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::BtfEnum pub aya_obj::btf::BtfEnum::name_offset: u32 pub aya_obj::btf::BtfEnum::value: u32 +impl aya_obj::btf::BtfEnum +pub fn aya_obj::btf::BtfEnum::new(name_offset: u32, value: u32) -> Self impl core::clone::Clone for aya_obj::btf::BtfEnum pub fn aya_obj::btf::BtfEnum::clone(&self) -> aya_obj::btf::BtfEnum impl core::fmt::Debug for aya_obj::btf::BtfEnum @@ -414,6 +416,8 @@ pub fn aya_obj::btf::BtfEnum::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::btf::BtfEnum pub fn aya_obj::btf::BtfEnum::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::BtfEnum64 +impl aya_obj::btf::BtfEnum64 +pub fn aya_obj::btf::BtfEnum64::new(name_offset: u32, value: u64) -> Self impl core::clone::Clone for aya_obj::btf::BtfEnum64 pub fn aya_obj::btf::BtfEnum64::clone(&self) -> aya_obj::btf::BtfEnum64 impl core::fmt::Debug for aya_obj::btf::BtfEnum64 @@ -477,6 +481,7 @@ pub struct aya_obj::btf::BtfFeatures impl aya_obj::btf::BtfFeatures pub fn aya_obj::btf::BtfFeatures::btf_datasec(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_decl_tag(&self) -> bool +pub fn aya_obj::btf::BtfFeatures::btf_enum64(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_float(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_func(&self) -> bool pub fn aya_obj::btf::BtfFeatures::btf_func_global(&self) -> bool @@ -701,7 +706,7 @@ impl core::convert::From for aya_obj::btf::DeclTag pub fn aya_obj::btf::DeclTag::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::Enum impl aya_obj::btf::Enum -pub fn aya_obj::btf::Enum::new(name_offset: u32, variants: alloc::vec::Vec) -> Self +pub fn aya_obj::btf::Enum::new(name_offset: u32, signed: bool, variants: alloc::vec::Vec) -> Self impl core::clone::Clone for aya_obj::btf::Enum pub fn aya_obj::btf::Enum::clone(&self) -> aya_obj::btf::Enum impl core::fmt::Debug for aya_obj::btf::Enum @@ -732,6 +737,8 @@ pub fn aya_obj::btf::Enum::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya_obj::btf::Enum pub fn aya_obj::btf::Enum::from(t: T) -> T #[repr(C)] pub struct aya_obj::btf::Enum64 +impl aya_obj::btf::Enum64 +pub fn aya_obj::btf::Enum64::new(name_offset: u32, signed: bool, variants: alloc::vec::Vec) -> Self impl core::clone::Clone for aya_obj::btf::Enum64 pub fn aya_obj::btf::Enum64::clone(&self) -> aya_obj::btf::Enum64 impl core::fmt::Debug for aya_obj::btf::Enum64 From dfb6020a1dc1d0ee28426bd9e3086dd449f643f7 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 9 Aug 2023 13:08:43 -0400 Subject: [PATCH 12/42] aya-obj: s/types.types[i]/*t/ where possible We already have a mutable reference in scope, use it where possible. --- aya-obj/src/btf/btf.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 8c8469a5..02976569 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -517,7 +517,7 @@ impl Btf { } // Sanitize VAR if they are not supported. BtfType::Var(v) if !features.btf_datasec => { - types.types[i] = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); + *t = BtfType::Int(Int::new(v.name_offset, 1, IntEncoding::None, 0)); } // Sanitize DATASEC if they are not supported. BtfType::DataSec(d) if !features.btf_datasec => { @@ -548,8 +548,9 @@ impl Btf { }) .collect(); - types.types[i] = - BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32)); + // Must reborrow here because we borrow `types` immutably above. + let t = &mut types.types[i]; + *t = BtfType::Struct(Struct::new(name_offset, members, entries.len() as u32)); } // Fixup DATASEC. // @@ -620,7 +621,10 @@ impl Btf { } } fixed_section.entries = entries; - types.types[i] = BtfType::DataSec(fixed_section); + + // Must reborrow here because we borrow `types` immutably above. + let t = &mut types.types[i]; + *t = BtfType::DataSec(fixed_section); } } // Fixup FUNC_PROTO. @@ -643,7 +647,7 @@ impl Btf { }) .collect(); let enum_type = BtfType::Enum(Enum::new(ty.name_offset, false, members)); - types.types[i] = enum_type; + *t = enum_type; } // Sanitize FUNC. BtfType::Func(ty) => { @@ -651,9 +655,7 @@ impl Btf { // Sanitize FUNC. if !features.btf_func { debug!("{}: not supported. replacing with TYPEDEF", kind); - let typedef_type = - BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type)); - types.types[i] = typedef_type; + *t = BtfType::Typedef(Typedef::new(ty.name_offset, ty.btf_type)); } else if !features.btf_func_global || name == "memset" || name == "memcpy" @@ -681,20 +683,17 @@ impl Btf { // Sanitize FLOAT. BtfType::Float(ty) if !features.btf_float => { debug!("{}: not supported. replacing with STRUCT", kind); - let struct_ty = BtfType::Struct(Struct::new(0, vec![], ty.size)); - types.types[i] = struct_ty; + *t = BtfType::Struct(Struct::new(0, vec![], ty.size)); } // Sanitize DECL_TAG. BtfType::DeclTag(ty) if !features.btf_decl_tag => { debug!("{}: not supported. replacing with INT", kind); - let int_type = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); - types.types[i] = int_type; + *t = BtfType::Int(Int::new(ty.name_offset, 1, IntEncoding::None, 0)); } // Sanitize TYPE_TAG. BtfType::TypeTag(ty) if !features.btf_type_tag => { debug!("{}: not supported. replacing with CONST", kind); - let const_type = BtfType::Const(Const::new(ty.btf_type)); - types.types[i] = const_type; + *t = BtfType::Const(Const::new(ty.btf_type)); } // Sanitize Signed ENUMs. BtfType::Enum(ty) if !features.btf_enum64 && ty.is_signed() => { @@ -715,9 +714,7 @@ impl Btf { offset: 0, }) .collect(); - let union_type = - BtfType::Union(Union::new(ty.name_offset, members.len() as u32, members)); - types.types[i] = union_type; + *t = BtfType::Union(Union::new(ty.name_offset, members.len() as u32, members)); } // The type does not need fixing up or sanitization. _ => {} From b6a6a81f9507a77df139f26a41f6c9dfe3d663bf Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 8 Aug 2023 14:34:03 -0400 Subject: [PATCH 13/42] integration-test: deflake log test Wait for at least one log and increase the wait time 10x. --- test/integration-test/src/tests/log.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/integration-test/src/tests/log.rs b/test/integration-test/src/tests/log.rs index 65ad34eb..c51f7e96 100644 --- a/test/integration-test/src/tests/log.rs +++ b/test/integration-test/src/tests/log.rs @@ -70,12 +70,16 @@ async fn log() { let mut logs = 0; let records = loop { - tokio::time::sleep(std::time::Duration::from_millis(10)).await; + tokio::time::sleep(std::time::Duration::from_millis(100)).await; let records = captured_logs.lock().unwrap(); - if records.len() == logs { + let len = records.len(); + if len == 0 { + continue; + } + if len == logs { break records; } - logs = records.len(); + logs = len; }; let mut records = records.iter(); From 82a77bc83d865af56914545625d97fa1f65fe733 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 7 Aug 2023 16:57:22 -0400 Subject: [PATCH 14/42] integration-test: Implement running on VMs Implements running integration tests on multiple VMs with arbitrary kernel images using `cargo xtask integration-test vm ...`. This changes our coverage from 6.2 to 6.1 and 6.4. --- .github/workflows/ci.yml | 118 +++++---- Cargo.toml | 3 + bpf/aya-log-ebpf/src/lib.rs | 19 +- init/Cargo.toml | 10 + init/src/main.rs | 166 ++++++++++++ test/README.md | 22 +- test/cloud-localds | 264 ------------------- test/run.sh | 241 ----------------- xtask/src/main.rs | 12 - xtask/src/run.rs | 498 +++++++++++++++++++++++++++++++----- 10 files changed, 709 insertions(+), 644 deletions(-) create mode 100644 init/Cargo.toml create mode 100644 init/src/main.rs delete mode 100755 test/cloud-localds delete mode 100755 test/run.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2ab4cee..e9eece29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,8 +139,14 @@ jobs: --target ${{ matrix.target }} \ -Z build-std=core - build-integration-test: - runs-on: ubuntu-22.04 + run-integration-test: + strategy: + fail-fast: false + matrix: + runner: + - macos-12 + - ubuntu-22.04 + runs-on: ${{ matrix.runner }} steps: - uses: actions/checkout@v3 with: @@ -150,13 +156,12 @@ jobs: with: toolchain: nightly components: rust-src + targets: aarch64-unknown-linux-musl,x86_64-unknown-linux-musl - uses: Swatinem/rust-cache@v2 - - name: bpf-linker - run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git - - - name: Install dependencies + - name: Install prerequisites + if: runner.os == 'Linux' # ubuntu-22.04 comes with clang 14[0] which doesn't include support for signed and 64bit # enum values which was added in clang 15[1]. # @@ -171,63 +176,78 @@ jobs: set -euxo pipefail wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main | sudo tee /etc/apt/sources.list.d/llvm.list - sudo apt-get update - sudo apt-get -y install clang gcc-multilib llvm + sudo apt update + sudo apt -y install clang gcc-multilib llvm locate qemu-system-{arm,x86} - - name: Build + - name: bpf-linker + if: runner.os == 'Linux' + run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git + + - name: Install prerequisites + if: runner.os == 'macOS' + # The clang shipped on macOS doesn't support BPF, so we need LLVM from brew. + # + # We also need LLVM for bpf-linker, see comment below. run: | set -euxo pipefail - mkdir -p integration-test-binaries - # See https://doc.rust-lang.org/cargo/reference/profiles.html for the - # names of the builtin profiles. Note that dev builds "debug" targets. - cargo xtask build-integration-test --cargo-arg=--profile=dev | xargs -I % cp % integration-test-binaries/dev - cargo xtask build-integration-test --cargo-arg=--profile=release | xargs -I % cp % integration-test-binaries/release - - - uses: actions/upload-artifact@v3 - with: - name: integration-test-binaries - path: integration-test-binaries + brew install qemu dpkg pkg-config llvm + echo /usr/local/opt/llvm/bin >> $GITHUB_PATH - run-integration-test: - runs-on: macos-latest - needs: ["build-integration-test"] - steps: - - uses: actions/checkout@v3 - with: - sparse-checkout: | - test/run.sh - test/cloud-localds + - name: bpf-linker + if: runner.os == 'macOS' + # NB: rustc doesn't ship libLLVM.so on macOS, so disable proxying (default feature). + run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git --no-default-features - - name: Install Pre-requisites + - name: Download debian kernels + if: runner.arch == 'ARM64' run: | - brew install qemu gnu-getopt coreutils cdrtools - - - name: Cache tmp files - uses: actions/cache@v3 - with: - path: | - .tmp/*.qcow2 - .tmp/test_rsa - .tmp/test_rsa.pub - key: tmp-files-${{ hashFiles('test/run.sh') }} - - - uses: actions/download-artifact@v3 - with: - name: integration-test-binaries - path: integration-test-binaries - - - name: Run integration tests + set -euxo pipefail + mkdir -p test/.tmp/debian-kernels/arm64 + # NB: a 4.19 kernel image for arm64 was not available. + # TODO: enable tests on kernels before 6.0. + # linux-image-5.10.0-23-cloud-arm64-unsigned_5.10.179-3_arm64.deb \ + printf '%s\0' \ + linux-image-6.1.0-10-cloud-arm64-unsigned_6.1.38-2_arm64.deb \ + linux-image-6.4.0-1-cloud-arm64-unsigned_6.4.4-2_arm64.deb \ + | xargs -0 -t -P0 -I {} wget -nd -q -P test/.tmp/debian-kernels/arm64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + + - name: Download debian kernels + if: runner.arch == 'X64' run: | set -euxo pipefail - find integration-test-binaries -type f -exec chmod +x {} \; - test/run.sh integration-test-binaries + mkdir -p test/.tmp/debian-kernels/amd64 + # TODO: enable tests on kernels before 6.0. + # linux-image-4.19.0-21-cloud-amd64-unsigned_4.19.249-2_amd64.deb \ + # linux-image-5.10.0-23-cloud-amd64-unsigned_5.10.179-3_amd64.deb \ + printf '%s\0' \ + linux-image-6.1.0-10-cloud-amd64-unsigned_6.1.38-2_amd64.deb \ + linux-image-6.4.0-1-cloud-amd64-unsigned_6.4.4-2_amd64.deb \ + | xargs -0 -t -P0 -I {} wget -nd -q -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + + - name: Alias gtar as tar + if: runner.os == 'macOS' + # macOS tar doesn't support --wildcards which we use below. + run: mkdir tar-is-gtar && ln -s "$(which gtar)" tar-is-gtar/tar && echo "$PWD"/tar-is-gtar >> $GITHUB_PATH + + - name: Extract debian kernels + run: | + set -euxo pipefail + find test/.tmp -name '*.deb' -print0 | xargs -t -0 -I {} \ + sh -c "dpkg --fsys-tarfile {} | tar -C test/.tmp --wildcards --extract '*vmlinuz*' --file -" + + - name: Run integration tests + run: find test/.tmp -name 'vmlinuz-*' | xargs -t cargo xtask integration-test vm # Provides a single status check for the entire build workflow. # This is used for merge automation, like Mergify, since GH actions # has no concept of "when all status checks pass". # https://docs.mergify.com/conditions/#validating-all-status-checks build-workflow-complete: - needs: ["lint", "build-test-aya", "build-test-aya-bpf", "run-integration-test"] + needs: + - lint + - build-test-aya + - build-test-aya-bpf + - run-integration-test runs-on: ubuntu-latest steps: - name: Build Complete diff --git a/Cargo.toml b/Cargo.toml index 0a95461b..4a4bdbca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "aya-log-parser", "aya-obj", "aya-tool", + "init", "test/integration-test", "xtask", @@ -29,6 +30,7 @@ default-members = [ "aya-log-parser", "aya-obj", "aya-tool", + "init", # test/integration-test is omitted; including it in this list causes `cargo test` to run its # tests, and that doesn't work unless they've been built with `cargo xtask`. "xtask", @@ -72,6 +74,7 @@ lazy_static = { version = "1", default-features = false } libc = { version = "0.2.105", default-features = false } log = { version = "0.4", default-features = false } netns-rs = { version = "0.1", default-features = false } +nix = { version = "0.26.2", default-features = false } num_enum = { version = "0.6", default-features = false } object = { version = "0.31", default-features = false } parking_lot = { version = "0.12.0", default-features = false } diff --git a/bpf/aya-log-ebpf/src/lib.rs b/bpf/aya-log-ebpf/src/lib.rs index 2933509c..5962c239 100644 --- a/bpf/aya-log-ebpf/src/lib.rs +++ b/bpf/aya-log-ebpf/src/lib.rs @@ -1,10 +1,9 @@ #![no_std] #![warn(clippy::cast_lossless, clippy::cast_sign_loss)] -use aya_bpf::{ - macros::map, - maps::{PerCpuArray, PerfEventByteArray}, -}; +#[cfg(target_arch = "bpf")] +use aya_bpf::macros::map; +use aya_bpf::maps::{PerCpuArray, PerfEventByteArray}; pub use aya_log_common::{write_record_header, Level, WriteToBuf, LOG_BUF_CAPACITY}; pub use aya_log_ebpf_macros::{debug, error, info, log, trace, warn}; @@ -15,11 +14,19 @@ pub struct LogBuf { } #[doc(hidden)] -#[map] +// This cfg_attr prevents compilation failures on macOS where the generated section name doesn't +// meet mach-o's requirements. We wouldn't ordinarily build this crate for macOS, but we do so +// because the integration-test crate depends on this crate transitively. See comment in +// test/integration-test/Cargo.toml. +#[cfg_attr(target_arch = "bpf", map)] pub static mut AYA_LOG_BUF: PerCpuArray = PerCpuArray::with_max_entries(1, 0); #[doc(hidden)] -#[map] +// This cfg_attr prevents compilation failures on macOS where the generated section name doesn't +// meet mach-o's requirements. We wouldn't ordinarily build this crate for macOS, but we do so +// because the integration-test crate depends on this crate transitively. See comment in +// test/integration-test/Cargo.toml. +#[cfg_attr(target_arch = "bpf", map)] pub static mut AYA_LOGS: PerfEventByteArray = PerfEventByteArray::new(0); #[doc(hidden)] diff --git a/init/Cargo.toml b/init/Cargo.toml new file mode 100644 index 00000000..6adf153e --- /dev/null +++ b/init/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "init" +version = "0.1.0" +authors = ["Tamir Duberstein "] +edition = "2021" +publish = false + +[dependencies] +anyhow = { workspace = true, features = ["std"] } +nix = { workspace = true, features = ["fs", "mount", "reboot"] } diff --git a/init/src/main.rs b/init/src/main.rs new file mode 100644 index 00000000..89253de7 --- /dev/null +++ b/init/src/main.rs @@ -0,0 +1,166 @@ +//! init is the first process started by the kernel. +//! +//! This implementation creates the minimal mounts required to run BPF programs, runs all binaries +//! in /bin, prints a final message ("init: success|failure"), and powers off the machine. + +use anyhow::Context as _; + +#[derive(Debug)] +struct Errors(Vec); + +impl std::fmt::Display for Errors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(errors) = self; + for (i, error) in errors.iter().enumerate() { + if i != 0 { + writeln!(f)?; + } + write!(f, "{:?}", error)?; + } + Ok(()) + } +} + +impl std::error::Error for Errors {} + +fn run() -> anyhow::Result<()> { + const RXRXRX: nix::sys::stat::Mode = nix::sys::stat::Mode::empty() + .union(nix::sys::stat::Mode::S_IRUSR) + .union(nix::sys::stat::Mode::S_IXUSR) + .union(nix::sys::stat::Mode::S_IRGRP) + .union(nix::sys::stat::Mode::S_IXGRP) + .union(nix::sys::stat::Mode::S_IROTH) + .union(nix::sys::stat::Mode::S_IXOTH); + + struct Mount { + source: &'static str, + target: &'static str, + fstype: &'static str, + flags: nix::mount::MsFlags, + data: Option<&'static str>, + target_mode: Option, + } + + for Mount { + source, + target, + fstype, + flags, + data, + target_mode, + } in [ + Mount { + source: "proc", + target: "/proc", + fstype: "proc", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: Some(RXRXRX), + }, + Mount { + source: "sysfs", + target: "/sys", + fstype: "sysfs", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: Some(RXRXRX), + }, + Mount { + source: "debugfs", + target: "/sys/kernel/debug", + fstype: "debugfs", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: None, + }, + Mount { + source: "bpffs", + target: "/sys/fs/bpf", + fstype: "bpf", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: None, + }, + ] { + match target_mode { + None => { + // Must exist. + let nix::sys::stat::FileStat { st_mode, .. } = nix::sys::stat::stat(target) + .with_context(|| format!("stat({target}) failed"))?; + let s_flag = nix::sys::stat::SFlag::from_bits_truncate(st_mode); + + if !s_flag.contains(nix::sys::stat::SFlag::S_IFDIR) { + anyhow::bail!("{target} is not a directory"); + } + } + Some(target_mode) => { + // Must not exist. + nix::unistd::mkdir(target, target_mode) + .with_context(|| format!("mkdir({target}) failed"))?; + } + } + nix::mount::mount(Some(source), target, Some(fstype), flags, data).with_context(|| { + format!("mount({source}, {target}, {fstype}, {flags:?}, {data:?}) failed") + })?; + } + + // By contract we run everything in /bin and assume they're rust test binaries. + // + // If the user requested command line arguments, they're named init.arg={}. + + // Read kernel parameters from /proc/cmdline. They're space separated on a single line. + let cmdline = std::fs::read_to_string("/proc/cmdline") + .with_context(|| "read_to_string(/proc/cmdline) failed")?; + let args = cmdline + .split_whitespace() + .filter_map(|parameter| { + parameter + .strip_prefix("init.arg=") + .map(std::ffi::OsString::from) + }) + .collect::>(); + + // Iterate files in /bin. + let read_dir = std::fs::read_dir("/bin").context("read_dir(/bin) failed")?; + let errors = read_dir + .filter_map(|entry| { + match (|| { + let entry = entry.context("read_dir(/bin) failed")?; + let path = entry.path(); + let status = std::process::Command::new(&path) + .args(&args) + .status() + .with_context(|| format!("failed to execute {}", path.display()))?; + + if status.code() == Some(0) { + Ok(()) + } else { + Err(anyhow::anyhow!("{} failed: {status:?}", path.display())) + } + })() { + Ok(()) => None, + Err(err) => Some(err), + } + }) + .collect::>(); + if errors.is_empty() { + Ok(()) + } else { + Err(Errors(errors).into()) + } +} + +fn main() { + match run() { + Ok(()) => { + println!("init: success"); + } + Err(err) => { + println!("{err:?}"); + println!("init: failure"); + } + } + let how = nix::sys::reboot::RebootMode::RB_POWER_OFF; + let _: std::convert::Infallible = nix::sys::reboot::reboot(how) + .unwrap_or_else(|err| panic!("reboot({how:?}) failed: {err:?}")); +} diff --git a/test/README.md b/test/README.md index a9521c0b..82e41da0 100644 --- a/test/README.md +++ b/test/README.md @@ -3,21 +3,15 @@ Aya Integration Tests The aya integration test suite is a set of tests to ensure that common usage behaviours work on real Linux distros -## Prerequisites - -### Linux - -To run locally all you need is: -1. Rust nightly -1. `cargo install bpf-linker` +## Prerequisites -### Other OSs +You'll need: -1. A POSIX shell -1. `rustup target add x86_64-unknown-linux-musl` +1. `rustup toolchain install nightly` +1. `rustup target add {aarch64,x86_64}-unknown-linux-musl` 1. `cargo install bpf-linker` -1. Install `qemu` and `cloud-init-utils` package - or any package that provides `cloud-localds` +1. (virtualized only) `qemu` ## Usage @@ -26,15 +20,13 @@ From the root of this repository: ### Native ``` -cargo xtask integration-test +cargo xtask integration-test local ``` ### Virtualized ``` -mkdir -p integration-test-binaries -cargo xtask build-integration-test | xargs -I % cp % integration-test-binaries -./test/run.sh integration-test-binaries +cargo xtask integration-test vm ``` ### Writing an integration test diff --git a/test/cloud-localds b/test/cloud-localds deleted file mode 100755 index 3a28129f..00000000 --- a/test/cloud-localds +++ /dev/null @@ -1,264 +0,0 @@ -#!/bin/bash - -VERBOSITY=0 -TEMP_D="" -DEF_DISK_FORMAT="raw" -DEF_FILESYSTEM="iso9660" -CR=" -" - -error() { echo "$@" 1>&2; } -fail() { [ $# -eq 0 ] || error "$@"; exit 1; } - -Usage() { - cat < my-meta-data - * ${0##*/} my-seed.img my-user-data my-meta-data - * kvm -net nic -net user,hostfwd=tcp::2222-:22 \\ - -drive file=disk1.img,if=virtio -drive file=my-seed.img,if=virtio - * ssh -p 2222 ubuntu@localhost -EOF -} - -bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; exit 1; } -cleanup() { - [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}" -} - -debug() { - local level=${1}; shift; - [ "${level}" -gt "${VERBOSITY}" ] && return - error "${@}" -} - -has_cmd() { - command -v "$1" >/dev/null 2>&1 -} - -short_opts="hH:i:d:f:m:N:o:V:v" -long_opts="disk-format:,dsmode:,filesystem:,help,hostname:,interfaces:," -long_opts="${long_opts}network-config:,output:,vendor-data:,verbose" -getopt_out=$(getopt -n "${0##*/}" \ - -o "${short_opts}" -l "${long_opts}" -- "$@") && - eval set -- "${getopt_out}" || - bad_Usage - -## <> -output="" -userdata="" -metadata="" -vendordata="" -filesystem="" -diskformat=$DEF_DISK_FORMAT -interfaces=_unset -dsmode="" -hostname="" -ncname="network-config" - - -while [ $# -ne 0 ]; do - cur=${1}; next=${2}; - case "$cur" in - -h|--help) Usage ; exit 0;; - -d|--disk-format) diskformat=$next; shift;; - -f|--filesystem) filesystem=$next; shift;; - -H|--hostname) hostname=$next; shift;; - -i|--interfaces) interfaces=$next; shift;; - -N|--network-config) netcfg=$next; shift;; - -m|--dsmode) dsmode=$next; shift;; - -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; - -V|--vendor-data) vendordata="$next";; - --) shift; break;; - esac - shift; -done - -## check arguments here -## how many args do you expect? -echo $1 -echo $2 -echo $3 -[ $# -ge 2 ] || bad_Usage "must provide output, userdata" -[ $# -le 3 ] || bad_Usage "confused by additional args" - -output=$1 -userdata=$2 -metadata=$3 - -if [ -n "$metadata" ]; then - [ "$interfaces" = "_unset" -a -z "$dsmode" -a -z "$hostname" ] || - fail "metadata is incompatible with:" \ - "--interfaces, --hostname, --dsmode" -fi - -case "$diskformat" in - tar|tar-seed-local|tar-seed-net) - if [ "${filesystem:-tar}" != "tar" ]; then - fail "diskformat=tar is incompatible with filesystem" - fi - filesystem="$diskformat" - ;; - tar*) - fail "supported 'tar' formats are tar, tar-seed-local, tar-seed-net" -esac - -if [ -z "$filesystem" ]; then - filesystem="$DEF_FILESYSTEM" -fi -if [ "$filesystem" = "iso" ]; then - filesystem="iso9660" -fi - -case "$filesystem" in - tar*) - has_cmd tar || - fail "missing 'tar'. Required for --filesystem=$filesystem";; - vfat) - has_cmd mkfs.vfat || - fail "missing 'mkfs.vfat'. Required for --filesystem=vfat." - has_cmd mcopy || - fail "missing 'mcopy'. Required for --filesystem=vfat." - ;; - iso9660) - has_cmd mkisofs || - fail "missing 'mkisofs'. Required for --filesystem=iso9660." - ;; - *) fail "unknown filesystem $filesystem";; -esac - -case "$diskformat" in - tar*|raw) :;; - *) has_cmd "qemu-img" || - fail "missing 'qemu-img'. Required for --disk-format=$diskformat." -esac - -[ "$interfaces" = "_unset" -o -r "$interfaces" ] || - fail "$interfaces: not a readable file" - -TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") || - fail "failed to make tempdir" -trap cleanup EXIT - -files=( "${TEMP_D}/user-data" "${TEMP_D}/meta-data" ) -if [ -n "$metadata" ]; then - cp "$metadata" "$TEMP_D/meta-data" || fail "$metadata: failed to copy" -else - instance_id="iid-local01" - iface_data="" - [ "$interfaces" != "_unset" ] && - iface_data=$(sed ':a;N;$!ba;s/\n/\\n/g' "$interfaces") - - # write json formatted user-data (json is a subset of yaml) - mdata="" - for kv in "instance-id:$instance_id" "local-hostname:$hostname" \ - "interfaces:${iface_data}" "dsmode:$dsmode"; do - key=${kv%%:*} - val=${kv#*:} - [ -n "$val" ] || continue - mdata="${mdata:+${mdata},${CR}}\"$key\": \"$val\"" - done - printf "{\n%s\n}\n" "$mdata" > "${TEMP_D}/meta-data" -fi - -if [ -n "$netcfg" ]; then - cp "$netcfg" "${TEMP_D}/$ncname" || - fail "failed to copy network config" - files[${#files[@]}]="$TEMP_D/$ncname" -fi - -if [ -n "$vendordata" ]; then - cp "$vendordata" "${TEMP_D}/vendor-data" || - fail "failed to copy vendor data" - files[${#files[@]}]="$TEMP_D/vendor-data" -fi - -files_rel=( ) -for f in "${files[@]}"; do - files_rel[${#files_rel[@]}]="${f#${TEMP_D}/}" -done - -if [ "$userdata" = "-" ]; then - cat > "$TEMP_D/user-data" || fail "failed to read from stdin" -else - cp "$userdata" "$TEMP_D/user-data" || fail "$userdata: failed to copy" -fi - -## alternatively, create a vfat filesystem with same files -img="$TEMP_D/seed-data" -tar_opts=( --owner=root --group=root ) - -case "$filesystem" in - tar) - tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${files_rel[@]}" || - fail "failed to create tarball of ${files_rel[*]}" - ;; - tar-seed-local|tar-seed-net) - if [ "$filesystem" = "tar-seed-local" ]; then - path="var/lib/cloud/seed/nocloud" - else - path="var/lib/cloud/seed/nocloud-net" - fi - mkdir -p "${TEMP_D}/${path}" || - fail "failed making path for seed files" - mv "${files[@]}" "${TEMP_D}/$path" || - fail "failed moving files" - tar "${tar_opts[@]}" -C "${TEMP_D}" -cf "$img" "${path}" || - fail "failed to create tarball with $path" - ;; - iso9660) - mkisofs -output "$img" -volid cidata \ - -joliet -rock "${files[@]}" > "$TEMP_D/err" 2>&1 || - { cat "$TEMP_D/err" 1>&2; fail "failed to mkisofs"; } - ;; - vfat) - truncate -s 128K "$img" || fail "failed truncate image" - out=$(mkfs.vfat -n cidata "$img" 2>&1) || - { error "failed: mkfs.vfat -n cidata $img"; error "$out"; } - mcopy -oi "$img" "${files[@]}" :: || - fail "failed to copy user-data, meta-data to img" - ;; -esac - -[ "$output" = "-" ] && output="$TEMP_D/final" -if [ "${diskformat#tar}" != "$diskformat" -o "$diskformat" = "raw" ]; then - cp "$img" "$output" || - fail "failed to copy image to $output" -else - qemu-img convert -f raw -O "$diskformat" "$img" "$output" || - fail "failed to convert to disk format $diskformat" -fi - -[ "$output" != "$TEMP_D/final" ] || { cat "$output" && output="-"; } || - fail "failed to write to -" - -debug 1 "wrote ${output} with filesystem=$filesystem and diskformat=$diskformat" -# vi: ts=4 noexpandtab diff --git a/test/run.sh b/test/run.sh deleted file mode 100755 index 26c98918..00000000 --- a/test/run.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -if [ "$(uname -s)" = "Darwin" ]; then - PATH="$(dirname "$(brew list gnu-getopt | grep "bin/getopt$")"):$PATH" - export PATH -fi - -AYA_SOURCE_DIR="$(realpath "$(dirname "$0")"/..)" - -# Temporary directory for tests to use. -AYA_TMPDIR="${AYA_SOURCE_DIR}/.tmp" - -# Directory for VM images -AYA_IMGDIR=${AYA_TMPDIR} - -if [ -z "${AYA_BUILD_TARGET}" ]; then - AYA_BUILD_TARGET=$(rustc -vV | sed -n 's|host: ||p') -fi - -AYA_HOST_ARCH=$(uname -m) -if [ "${AYA_HOST_ARCH}" = "arm64" ]; then - AYA_HOST_ARCH="aarch64" -fi - -if [ -z "${AYA_GUEST_ARCH}" ]; then - AYA_GUEST_ARCH="${AYA_HOST_ARCH}" -fi - -if [ "${AYA_GUEST_ARCH}" = "aarch64" ]; then - if [ -z "${AARCH64_UEFI}" ]; then - AARCH64_UEFI="$(brew list qemu -1 -v | grep edk2-aarch64-code.fd)" - fi -fi - -if [ -z "$AYA_MUSL_TARGET" ]; then - AYA_MUSL_TARGET=${AYA_GUEST_ARCH}-unknown-linux-musl -fi - -# Test Image -if [ -z "${AYA_TEST_IMAGE}" ]; then - AYA_TEST_IMAGE="fedora38" -fi - -case "${AYA_TEST_IMAGE}" in - fedora*) AYA_SSH_USER="fedora";; - centos*) AYA_SSH_USER="centos";; -esac - -download_images() { - mkdir -p "${AYA_IMGDIR}" - case $1 in - fedora37) - if [ ! -f "${AYA_IMGDIR}/fedora37.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="Fedora-Cloud-Base-37-1.7.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/fedora37.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - fedora38) - if [ ! -f "${AYA_IMGDIR}/fedora38.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="Fedora-Cloud-Base-38_Beta-1.3.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://fr2.rpmfind.net/linux/fedora/linux/releases/test/38_Beta/Cloud/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/fedora38.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - centos8) - if [ ! -f "${AYA_IMGDIR}/centos8.${AYA_GUEST_ARCH}.qcow2" ]; then - IMAGE="CentOS-8-GenericCloud-8.4.2105-20210603.0.${AYA_GUEST_ARCH}.qcow2" - IMAGE_URL="https://cloud.centos.org/centos/8/${AYA_GUEST_ARCH}/images" - echo "Downloading: ${IMAGE}, this may take a while..." - curl -o "${AYA_IMGDIR}/centos8.${AYA_GUEST_ARCH}.qcow2" -sSL "${IMAGE_URL}/${IMAGE}" - fi - ;; - *) - echo "$1 is not a recognized image name" - return 1 - ;; - esac -} - -start_vm() { - download_images "${AYA_TEST_IMAGE}" - # prepare config - cat > "${AYA_TMPDIR}/metadata.yaml" < "${AYA_TMPDIR}/ssh_config" < "${AYA_TMPDIR}/user-data.yaml" < actual_cores - nr_cpus=8 - fi - fi - ;; - *) - echo "${AYA_GUEST_ARCH} is not supported" - return 1 - ;; - esac - - if [ ! -f "${AYA_IMGDIR}/vm.qcow2" ]; then - echo "Creating VM image" - qemu-img create -F qcow2 -f qcow2 -o backing_file="${AYA_IMGDIR}/${AYA_TEST_IMAGE}.${AYA_GUEST_ARCH}.qcow2" "${AYA_IMGDIR}/vm.qcow2" || return 1 - else - echo "Reusing existing VM image" - fi - $QEMU \ - -machine "${machine}" \ - -cpu "${cpu}" \ - -m 3G \ - -smp "${nr_cpus}" \ - -display none \ - -monitor none \ - -daemonize \ - -pidfile "${AYA_TMPDIR}/vm.pid" \ - -device virtio-net-pci,netdev=net0 \ - -netdev user,id=net0,hostfwd=tcp::2222-:22 \ - "${uefi[@]}" \ - -drive if=virtio,format=qcow2,file="${AYA_IMGDIR}/vm.qcow2" \ - -drive if=virtio,format=raw,file="${AYA_TMPDIR}/seed.img" || return 1 - - trap cleanup_vm EXIT - echo "Waiting for SSH on port 2222..." - retry=0 - max_retries=300 - while ! ssh -q -F "${AYA_TMPDIR}/ssh_config" -o ConnectTimeout=1 -i "${AYA_TMPDIR}/test_rsa" "${AYA_SSH_USER}"@localhost -p 2222 echo "Hello VM"; do - retry=$((retry+1)) - if [ ${retry} -gt ${max_retries} ]; then - echo "Unable to connect to VM" - return 1 - fi - sleep 1 - done - - echo "VM launched" - exec_vm uname -a - echo "Enabling testing repositories" - exec_vm sudo dnf config-manager --set-enabled updates-testing - exec_vm sudo dnf config-manager --set-enabled updates-testing-modular -} - -scp_vm() { - local=$1 - remote=$(basename "$1") - scp -q -F "${AYA_TMPDIR}/ssh_config" \ - -i "${AYA_TMPDIR}/test_rsa" \ - -P 2222 "${local}" \ - "${AYA_SSH_USER}@localhost:${remote}" -} - -rsync_vm() { - rsync -a -e "ssh -p 2222 -F ${AYA_TMPDIR}/ssh_config -i ${AYA_TMPDIR}/test_rsa" "$1" "$AYA_SSH_USER"@localhost: -} - -exec_vm() { - ssh -q -F "${AYA_TMPDIR}/ssh_config" \ - -i "${AYA_TMPDIR}/test_rsa" \ - -p 2222 \ - "${AYA_SSH_USER}"@localhost \ - "$@" -} - -stop_vm() { - if [ -f "${AYA_TMPDIR}/vm.pid" ]; then - echo "Stopping VM forcefully" - kill -9 "$(cat "${AYA_TMPDIR}/vm.pid")" - rm "${AYA_TMPDIR}/vm.pid" - fi -} - -cleanup_vm() { - if ! stop_vm; then - rm -f "${AYA_IMGDIR}/vm.qcow2" - fi -} - -start_vm -trap cleanup_vm EXIT - -# make sure we always use fresh sources (also see comment at the end) -rsync_vm "$*" - -exec_vm "find $* -type f -executable -print0 | xargs -0 -I {} sudo {} --test-threads=1" - -# we rm and sync but it doesn't seem to work reliably - I guess we could sleep a -# few seconds after but ain't nobody got time for that. Instead we also rm -# before rsyncing. -exec_vm "rm -rf $*; sync" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3f93d692..01105c00 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -19,7 +19,6 @@ pub struct XtaskOptions { enum Subcommand { Codegen(codegen::Options), Docs, - BuildIntegrationTest(run::BuildOptions), IntegrationTest(run::Options), PublicApi(public_api::Options), } @@ -45,17 +44,6 @@ fn main() -> Result<()> { match command { Subcommand::Codegen(opts) => codegen::codegen(opts, libbpf_dir), Subcommand::Docs => docs::docs(metadata), - Subcommand::BuildIntegrationTest(opts) => { - let binaries = run::build(opts)?; - let mut stdout = std::io::stdout(); - for (_name, binary) in binaries { - use std::{io::Write as _, os::unix::ffi::OsStrExt as _}; - - stdout.write_all(binary.as_os_str().as_bytes())?; - stdout.write_all("\n".as_bytes())?; - } - Ok(()) - } Subcommand::IntegrationTest(opts) => run::run(opts), Subcommand::PublicApi(opts) => public_api::public_api(opts, metadata), } diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 6742a26b..9b80b6ef 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -1,47 +1,66 @@ use std::{ + env::consts::{ARCH, OS}, ffi::OsString, fmt::Write as _, - io::BufReader, - path::PathBuf, - process::{Child, Command, Stdio}, + fs::{copy, create_dir_all, metadata, File}, + io::{BufRead as _, BufReader, ErrorKind, Write as _}, + path::{Path, PathBuf}, + process::{Child, Command, Output, Stdio}, }; use anyhow::{anyhow, bail, Context as _, Result}; use cargo_metadata::{Artifact, CompilerMessage, Message, Target}; use clap::Parser; -use xtask::AYA_BUILD_INTEGRATION_BPF; +use xtask::{exec, AYA_BUILD_INTEGRATION_BPF}; -#[derive(Debug, Parser)] -pub struct BuildOptions { - /// Arguments to pass to `cargo build`. - #[clap(long)] - pub cargo_arg: Vec, +#[derive(Parser)] +enum Environment { + /// Runs the integration tests locally. + Local { + /// The command used to wrap your application. + #[clap(short, long, default_value = "sudo -E")] + runner: String, + }, + /// Runs the integration tests in a VM. + VM { + /// The kernel images to use. + /// + /// You can download some images with: + /// + /// wget --accept-regex '.*/linux-image-[0-9\.-]+-cloud-.*-unsigned*' \ + /// --recursive ftp://ftp.us.debian.org/debian/pool/main/l/linux/ + /// + /// You can then extract them with: + /// + /// find . -name '*.deb' -print0 \ + /// | xargs -0 -I {} sh -c "dpkg --fsys-tarfile {} \ + /// | tar --wildcards --extract '*vmlinuz*' --file -" + #[clap(required = true)] + kernel_image: Vec, + }, } -#[derive(Debug, Parser)] +#[derive(Parser)] pub struct Options { - #[command(flatten)] - pub build_options: BuildOptions, - /// The command used to wrap your application. - #[clap(short, long, default_value = "sudo -E")] - pub runner: String, + #[clap(subcommand)] + environment: Environment, /// Arguments to pass to your application. - #[clap(last = true)] - pub run_args: Vec, + #[clap(global = true, last = true)] + run_args: Vec, } -/// Build the project -pub fn build(opts: BuildOptions) -> Result> { - let BuildOptions { cargo_arg } = opts; +pub fn build(target: Option<&str>, f: F) -> Result> +where + F: FnOnce(&mut Command) -> &mut Command, +{ + // Always use rust-lld and -Zbuild-std in case we're cross-compiling. let mut cmd = Command::new("cargo"); - cmd.env(AYA_BUILD_INTEGRATION_BPF, "true") - .args([ - "build", - "--tests", - "--message-format=json", - "--package=integration-test", - ]) - .args(cargo_arg); + cmd.args(["build", "--message-format=json"]); + if let Some(target) = target { + let config = format!("target.{target}.linker = \"rust-lld\""); + cmd.args(["--target", target, "--config", &config]); + } + f(&mut cmd); let mut child = cmd .stdout(Stdio::piped()) @@ -83,40 +102,405 @@ pub fn build(opts: BuildOptions) -> Result> { Ok(executables) } -/// Build and run the project +#[derive(Debug)] +struct Errors(Vec); + +impl std::fmt::Display for Errors { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(errors) = self; + for (i, error) in errors.iter().enumerate() { + if i != 0 { + writeln!(f)?; + } + write!(f, "{:?}", error)?; + } + Ok(()) + } +} + +impl std::error::Error for Errors {} + +/// Build and run the project. pub fn run(opts: Options) -> Result<()> { let Options { - build_options, - runner, + environment, run_args, } = opts; - let binaries = build(build_options).context("error while building userspace application")?; - let mut args = runner.trim().split_terminator(' '); - let runner = args.next().ok_or(anyhow!("no first argument"))?; - let args = args.collect::>(); - - let mut failures = String::new(); - for (name, binary) in binaries { - let mut cmd = Command::new(runner); - let cmd = cmd - .args(args.iter()) - .arg(binary) - .args(run_args.iter()) - .arg("--test-threads=1"); - - println!("{name} running {cmd:?}"); - - let status = cmd - .status() - .with_context(|| format!("failed to run {cmd:?}"))?; - if status.code() != Some(0) { - writeln!(&mut failures, "{name} failed: {status:?}").context("String write failed")? - } + type Binary = (String, PathBuf); + fn binaries(target: Option<&str>) -> Result)>> { + ["dev", "release"] + .into_iter() + .map(|profile| { + let binaries = build(target, |cmd| { + cmd.env(AYA_BUILD_INTEGRATION_BPF, "true").args([ + "--package", + "integration-test", + "--tests", + "--profile", + profile, + ]) + })?; + anyhow::Ok((profile, binaries)) + }) + .collect() } - if failures.is_empty() { - Ok(()) - } else { - Err(anyhow!("failures:\n{}", failures)) + + // Use --test-threads=1 to prevent tests from interacting with shared + // kernel state due to the lack of inter-test isolation. + let default_args = [OsString::from("--test-threads=1")]; + let run_args = default_args.iter().chain(run_args.iter()); + + match environment { + Environment::Local { runner } => { + let mut args = runner.trim().split_terminator(' '); + let runner = args.next().ok_or(anyhow!("no first argument"))?; + let args = args.collect::>(); + + let binaries = binaries(None)?; + + let mut failures = String::new(); + for (profile, binaries) in binaries { + for (name, binary) in binaries { + let mut cmd = Command::new(runner); + let cmd = cmd.args(args.iter()).arg(binary).args(run_args.clone()); + + println!("{profile}:{name} running {cmd:?}"); + + let status = cmd + .status() + .with_context(|| format!("failed to run {cmd:?}"))?; + if status.code() != Some(0) { + writeln!(&mut failures, "{profile}:{name} failed: {status:?}") + .context("String write failed")? + } + } + } + if failures.is_empty() { + Ok(()) + } else { + Err(anyhow!("failures:\n{}", failures)) + } + } + Environment::VM { kernel_image } => { + // The user has asked us to run the tests on a VM. This is involved; strap in. + // + // We need tools to build the initramfs; we use gen_init_cpio from the Linux repository, + // taking care to cache it. + // + // Then we iterate the kernel images, using the `file` program to guess the target + // architecture. We then build the init program and our test binaries for that + // architecture, and use gen_init_cpio to build an initramfs containing the test + // binaries. We're almost ready to run the VM. + // + // We consult our OS, our architecture, and the target architecture to determine if + // hardware acceleration is available, and then start QEMU with the provided kernel + // image and the initramfs we built. + // + // We consume the output of QEMU, looking for the output of our init program. This is + // the only way to distinguish success from failure. We batch up the errors across all + // VM images and report to the user. The end. + let cache_dir = Path::new("test/.tmp"); + create_dir_all(cache_dir).context("failed to create cache dir")?; + let gen_init_cpio = cache_dir.join("gen_init_cpio"); + if !gen_init_cpio + .try_exists() + .context("failed to check existence of gen_init_cpio")? + { + let mut curl = Command::new("curl"); + curl.args([ + "-sfSL", + "https://raw.githubusercontent.com/torvalds/linux/master/usr/gen_init_cpio.c", + ]); + let mut curl_child = curl + .stdout(Stdio::piped()) + .spawn() + .with_context(|| format!("failed to spawn {curl:?}"))?; + let Child { stdout, .. } = &mut curl_child; + let curl_stdout = stdout.take().unwrap(); + + let mut clang = Command::new("clang"); + let clang = exec( + clang + .args(["-g", "-O2", "-x", "c", "-", "-o"]) + .arg(&gen_init_cpio) + .stdin(curl_stdout), + ); + + let output = curl_child + .wait_with_output() + .with_context(|| format!("failed to wait for {curl:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{curl:?} failed: {output:?}") + } + + // Check the result of clang *after* checking curl; in case the download failed, + // only curl's output will be useful. + clang?; + } + + let mut errors = Vec::new(); + for kernel_image in kernel_image { + // Guess the guest architecture. + let mut cmd = Command::new("file"); + let output = cmd + .arg("--brief") + .arg(&kernel_image) + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{cmd:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + + // Now parse the output of the file command, which looks something like + // + // - Linux kernel ARM64 boot executable Image, little-endian, 4K pages + // + // - Linux kernel x86 boot executable bzImage, version 6.1.0-10-cloud-amd64 [..] + + let stdout = String::from_utf8(stdout) + .with_context(|| format!("invalid UTF-8 in {cmd:?} stdout"))?; + let (_, stdout) = stdout + .split_once("Linux kernel") + .ok_or_else(|| anyhow!("failed to parse {cmd:?} stdout: {stdout}"))?; + let (guest_arch, _) = stdout + .split_once("boot executable") + .ok_or_else(|| anyhow!("failed to parse {cmd:?} stdout: {stdout}"))?; + let guest_arch = guest_arch.trim(); + + let (guest_arch, machine, cpu) = match guest_arch { + "ARM64" => ("aarch64", Some("virt"), Some("cortex-a57")), + "x86" => ("x86_64", Some("q35"), Some("qemu64")), + guest_arch => (guest_arch, None, None), + }; + + let target = format!("{guest_arch}-unknown-linux-musl"); + + // Build our init program. The contract is that it will run anything it finds in /bin. + let init = build(Some(&target), |cmd| { + cmd.args(["--package", "init", "--profile", "release"]) + }) + .context("building init program failed")?; + + let init = match &*init { + [(name, init)] => { + if name != "init" { + bail!("expected init program to be named init, found {name}") + } + init + } + init => bail!("expected exactly one init program, found {init:?}"), + }; + + let binaries = binaries(Some(&target))?; + + let tmp_dir = tempfile::tempdir().context("tempdir failed")?; + + let initrd_image = tmp_dir.path().join("qemu-initramfs.img"); + let initrd_image_file = File::create(&initrd_image).with_context(|| { + format!("failed to create {} for writing", initrd_image.display()) + })?; + + let mut gen_init_cpio = Command::new(&gen_init_cpio); + let mut gen_init_cpio_child = gen_init_cpio + .arg("-") + .stdin(Stdio::piped()) + .stdout(initrd_image_file) + .spawn() + .with_context(|| format!("failed to spawn {gen_init_cpio:?}"))?; + let Child { stdin, .. } = &mut gen_init_cpio_child; + let mut stdin = stdin.take().unwrap(); + + use std::os::unix::ffi::OsStrExt as _; + + // Send input into gen_init_cpio which looks something like + // + // file /init path-to-init 0755 0 0 + // dir /bin 0755 0 0 + // file /bin/foo path-to-foo 0755 0 0 + // file /bin/bar path-to-bar 0755 0 0 + + for bytes in [ + "file /init ".as_bytes(), + init.as_os_str().as_bytes(), + " 0755 0 0\n".as_bytes(), + "dir /bin 0755 0 0\n".as_bytes(), + ] { + stdin.write_all(bytes).expect("write"); + } + + for (profile, binaries) in binaries { + for (name, binary) in binaries { + let name = format!("{}-{}", profile, name); + let path = tmp_dir.path().join(&name); + copy(&binary, &path).with_context(|| { + format!("copy({}, {}) failed", binary.display(), path.display()) + })?; + for bytes in [ + "file /bin/".as_bytes(), + name.as_bytes(), + " ".as_bytes(), + path.as_os_str().as_bytes(), + " 0755 0 0\n".as_bytes(), + ] { + stdin.write_all(bytes).expect("write"); + } + } + } + // Must explicitly close to signal EOF. + drop(stdin); + + let output = gen_init_cpio_child + .wait_with_output() + .with_context(|| format!("failed to wait for {gen_init_cpio:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{gen_init_cpio:?} failed: {output:?}") + } + + copy(&initrd_image, "/tmp/initrd.img").context("copy failed")?; + + let mut qemu = Command::new(format!("qemu-system-{guest_arch}")); + if let Some(machine) = machine { + qemu.args(["-machine", machine]); + } + if guest_arch == ARCH { + match OS { + "linux" => match metadata("/dev/kvm") { + Ok(metadata) => { + use std::os::unix::fs::FileTypeExt as _; + if metadata.file_type().is_char_device() { + qemu.args(["-accel", "kvm"]); + } + } + Err(error) => { + if error.kind() != ErrorKind::NotFound { + Err(error).context("failed to check existence of /dev/kvm")?; + } + } + }, + "macos" => { + qemu.args(["-accel", "hvf"]); + } + os => bail!("unsupported OS: {os}"), + } + } else if let Some(cpu) = cpu { + qemu.args(["-cpu", cpu]); + } + let console = OsString::from("ttyS0"); + let kernel_args = std::iter::once(("console", &console)) + .chain(run_args.clone().map(|run_arg| ("init.arg", run_arg))) + .enumerate() + .fold(OsString::new(), |mut acc, (i, (k, v))| { + if i != 0 { + acc.push(" "); + } + acc.push(k); + acc.push("="); + acc.push(v); + acc + }); + qemu.args(["-no-reboot", "-nographic", "-m", "512M", "-smp", "2"]) + .arg("-append") + .arg(kernel_args) + .arg("-kernel") + .arg(&kernel_image) + .arg("-initrd") + .arg(&initrd_image); + if guest_arch == "aarch64" { + match OS { + "linux" => { + let mut cmd = Command::new("locate"); + let output = cmd + .arg("QEMU_EFI.fd") + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + let bios = String::from_utf8(stdout) + .with_context(|| format!("failed to parse output of {cmd:?}"))?; + qemu.args(["-bios", bios.trim()]); + } + "macos" => { + let mut cmd = Command::new("brew"); + let output = cmd + .args(["list", "qemu", "-1", "-v"]) + .output() + .with_context(|| format!("failed to run {cmd:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + let Output { stdout, .. } = output; + let output = String::from_utf8(stdout) + .with_context(|| format!("failed to parse output of {cmd:?}"))?; + const NAME: &str = "edk2-aarch64-code.fd"; + let bios = output.lines().find(|line| line.contains(NAME)).ok_or_else( + || anyhow!("failed to find {NAME} in output of {cmd:?}: {output}"), + )?; + qemu.args(["-bios", bios.trim()]); + } + os => bail!("unsupported OS: {os}"), + }; + } + let mut qemu_child = qemu + .stdout(Stdio::piped()) + .spawn() + .with_context(|| format!("failed to spawn {qemu:?}"))?; + let Child { stdout, .. } = &mut qemu_child; + let stdout = stdout.take().unwrap(); + let stdout = BufReader::new(stdout); + + let mut outcome = None; + for line in stdout.lines() { + let line = + line.with_context(|| format!("failed to read line from {qemu:?}"))?; + println!("{}", line); + // The init program will print "init: success" or "init: failure" to indicate + // the outcome of running the binaries it found in /bin. + if let Some(line) = line.strip_prefix("init: ") { + let previous = match line { + "success" => outcome.replace(Ok(())), + "failure" => outcome.replace(Err(())), + line => bail!("unexpected init output: {}", line), + }; + if let Some(previous) = previous { + bail!("multiple exit status: previous={previous:?}, current={line}"); + } + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + if line.contains("end Kernel panic") { + qemu_child.kill().context("failed to kill {qemu:?}")?; + } + } + } + + let output = qemu_child + .wait_with_output() + .with_context(|| format!("failed to wait for {qemu:?}"))?; + let Output { status, .. } = &output; + if status.code() != Some(0) { + bail!("{qemu:?} failed: {output:?}") + } + + let outcome = outcome.ok_or(anyhow!("init did not exit"))?; + match outcome { + Ok(()) => {} + Err(()) => { + errors.push(anyhow!("VM binaries failed on {}", kernel_image.display())) + } + } + } + if errors.is_empty() { + Ok(()) + } else { + Err(Errors(errors).into()) + } + } } } From 00d265c51b69e672457502593fbc63d0ac953e27 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sun, 16 Jul 2023 13:55:01 -0400 Subject: [PATCH 15/42] Remove pointless DefaultLogger This avoids an atomic load on every log. --- aya-log/src/lib.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/aya-log/src/lib.rs b/aya-log/src/lib.rs index 854a63a4..dd5b734b 100644 --- a/aya-log/src/lib.rs +++ b/aya-log/src/lib.rs @@ -98,7 +98,7 @@ impl BpfLogger { /// Starts reading log records created with `aya-log-ebpf` and logs them /// with the default logger. See [log::logger]. pub fn init(bpf: &mut Bpf) -> Result { - BpfLogger::init_with_logger(bpf, DefaultLogger {}) + BpfLogger::init_with_logger(bpf, log::logger()) } /// Starts reading log records created with `aya-log-ebpf` and logs them @@ -356,23 +356,6 @@ macro_rules! impl_format_float { impl_format_float!(f32); impl_format_float!(f64); -#[derive(Copy, Clone, Debug)] -struct DefaultLogger; - -impl Log for DefaultLogger { - fn enabled(&self, metadata: &log::Metadata) -> bool { - log::logger().enabled(metadata) - } - - fn log(&self, record: &Record) { - log::logger().log(record) - } - - fn flush(&self) { - log::logger().flush() - } -} - #[derive(Error, Debug)] pub enum Error { #[error("log event array {} doesn't exist", MAP_NAME)] From ca3f70b16a705bf26d2ccc7ce754de403be36223 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 9 Aug 2023 16:06:49 -0400 Subject: [PATCH 16/42] aya-log: s/Result/Option/ `Option` is guaranteed to have the same size as `usize`, which is not guarnateed for `Result`. This is a minor optimization, but also results in simpler code. --- aya-log-common/src/lib.rs | 45 +++++++------- aya-log-ebpf-macros/src/expand.rs | 14 +++-- aya-log/src/lib.rs | 93 ++++++++++++++++++----------- xtask/public-api/aya-log-common.txt | 40 ++++++------- 4 files changed, 107 insertions(+), 85 deletions(-) diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index ba20876f..f6cb3517 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::num; +use core::num::{NonZeroUsize, TryFromIntError}; use num_enum::IntoPrimitive; @@ -151,16 +151,16 @@ pub enum DisplayHint { // // llvm: :0:0: in function _ZN14aya_log_common5write17hc9ed05433e23a663E { i64, i64 } (i8, ptr, i64, ptr, i64): only integer returns supported #[inline(always)] -pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Result { - let wire_len: LogValueLength = value - .len() - .try_into() - .map_err(|num::TryFromIntError { .. }| ())?; +pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Option { + let wire_len: LogValueLength = match value.len().try_into() { + Ok(wire_len) => Some(wire_len), + Err(TryFromIntError { .. }) => None, + }?; let mut size = 0; macro_rules! copy_from_slice { ($value:expr) => {{ - let buf = buf.get_mut(size..).ok_or(())?; - let buf = buf.get_mut(..$value.len()).ok_or(())?; + let buf = buf.get_mut(size..)?; + let buf = buf.get_mut(..$value.len())?; buf.copy_from_slice($value); size += $value.len(); }}; @@ -168,12 +168,11 @@ pub(crate) fn write(tag: u8, value: &[u8], buf: &mut [u8]) -> Result copy_from_slice!(&[tag]); copy_from_slice!(&wire_len.to_ne_bytes()); copy_from_slice!(value); - Ok(size) + NonZeroUsize::new(size) } pub trait WriteToBuf { - #[allow(clippy::result_unit_err)] - fn write(self, buf: &mut [u8]) -> Result; + fn write(self, buf: &mut [u8]) -> Option; } macro_rules! impl_write_to_buf { @@ -182,7 +181,7 @@ macro_rules! impl_write_to_buf { // This need not be inlined because the return value is Result where N is // mem::size_of<$type>, which is a compile-time constant. #[inline(never)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { write($arg_type.into(), &self.to_ne_bytes(), buf) } } @@ -208,7 +207,7 @@ impl WriteToBuf for [u8; 16] { // This need not be inlined because the return value is Result where N is 16, which is a // compile-time constant. #[inline(never)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { write(Argument::ArrU8Len16.into(), &self, buf) } } @@ -217,7 +216,7 @@ impl WriteToBuf for [u16; 8] { // This need not be inlined because the return value is Result where N is 16, which is a // compile-time constant. #[inline(never)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) }; write(Argument::ArrU16Len8.into(), &bytes, buf) } @@ -227,7 +226,7 @@ impl WriteToBuf for [u8; 6] { // This need not be inlined because the return value is Result where N is 6, which is a // compile-time constant. #[inline(never)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { write(Argument::ArrU8Len6.into(), &self, buf) } } @@ -237,7 +236,7 @@ impl WriteToBuf for &[u8] { // // llvm: :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 #[inline(always)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { write(Argument::Bytes.into(), self, buf) } } @@ -247,7 +246,7 @@ impl WriteToBuf for &str { // // llvm: :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 #[inline(always)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { write(Argument::Str.into(), self.as_bytes(), buf) } } @@ -256,13 +255,12 @@ impl WriteToBuf for DisplayHint { // This need not be inlined because the return value is Result where N is 1, which is a // compile-time constant. #[inline(never)] - fn write(self, buf: &mut [u8]) -> Result { + fn write(self, buf: &mut [u8]) -> Option { let v: u8 = self.into(); write(Argument::DisplayHint.into(), &v.to_ne_bytes(), buf) } } -#[allow(clippy::result_unit_err)] #[doc(hidden)] #[inline(always)] // This function takes too many arguments to not be inlined. pub fn write_record_header( @@ -273,13 +271,14 @@ pub fn write_record_header( file: &str, line: u32, num_args: usize, -) -> Result { +) -> Option { let level: u8 = level.into(); let mut size = 0; macro_rules! write { ($tag:expr, $value:expr) => {{ - let buf = buf.get_mut(size..).ok_or(())?; - size += write($tag.into(), $value, buf)?; + let buf = buf.get_mut(size..)?; + let len = write($tag.into(), $value, buf)?; + size += len.get(); }}; } write!(RecordField::Target, target.as_bytes()); @@ -288,7 +287,7 @@ pub fn write_record_header( write!(RecordField::File, file.as_bytes()); write!(RecordField::Line, &line.to_ne_bytes()); write!(RecordField::NumArgs, &num_args.to_ne_bytes()); - Ok(size) + NonZeroUsize::new(size) } #[cfg(test)] diff --git a/aya-log-ebpf-macros/src/expand.rs b/aya-log-ebpf-macros/src/expand.rs index 78c92b47..ffbe3dbe 100644 --- a/aya-log-ebpf-macros/src/expand.rs +++ b/aya-log-ebpf-macros/src/expand.rs @@ -147,8 +147,8 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result {}, Some(::aya_log_ebpf::LogBuf { buf }) => { - let _: Result<(), ()> = (|| { - let mut len = ::aya_log_ebpf::write_record_header( + let _: Option<()> = (|| { + let size = ::aya_log_ebpf::write_record_header( buf, #target, #lvl, @@ -157,13 +157,15 @@ pub(crate) fn log(args: LogArgs, level: Option) -> Result Result<(usize, Vec), ()> { + fn new_log(args: usize) -> Option<(usize, Vec)> { let mut buf = vec![0; 8192]; let len = write_record_header( &mut buf, @@ -595,7 +595,7 @@ mod test { 123, args, )?; - Ok((len, buf)) + Some((len.get(), buf)) } #[test] @@ -603,7 +603,7 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(1).unwrap(); - len += "test".write(&mut input[len..]).unwrap(); + len += "test".write(&mut input[len..]).unwrap().get(); _ = len; @@ -621,8 +621,8 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(2).unwrap(); - len += "hello ".write(&mut input[len..]).unwrap(); - len += "test".write(&mut input[len..]).unwrap(); + len += "hello ".write(&mut input[len..]).unwrap().get(); + len += "test".write(&mut input[len..]).unwrap().get(); _ = len; @@ -640,8 +640,11 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(2).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += [0xde, 0xad].write(&mut input[len..]).unwrap(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xde, 0xad].write(&mut input[len..]).unwrap().get(); _ = len; @@ -659,13 +662,19 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(5).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += [0xde, 0xad].write(&mut input[len..]).unwrap(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xde, 0xad].write(&mut input[len..]).unwrap().get(); - len += " ".write(&mut input[len..]).unwrap(); + len += " ".write(&mut input[len..]).unwrap().get(); - len += DisplayHint::UpperHex.write(&mut input[len..]).unwrap(); - len += [0xbe, 0xef].write(&mut input[len..]).unwrap(); + len += DisplayHint::UpperHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += [0xbe, 0xef].write(&mut input[len..]).unwrap().get(); _ = len; @@ -683,9 +692,9 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "default hint: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Default.write(&mut input[len..]).unwrap(); - len += 14.write(&mut input[len..]).unwrap(); + len += "default hint: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Default.write(&mut input[len..]).unwrap().get(); + len += 14.write(&mut input[len..]).unwrap().get(); _ = len; @@ -703,9 +712,12 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "lower hex: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::LowerHex.write(&mut input[len..]).unwrap(); - len += 200.write(&mut input[len..]).unwrap(); + len += "lower hex: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::LowerHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += 200.write(&mut input[len..]).unwrap().get(); _ = len; @@ -723,9 +735,12 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "upper hex: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::UpperHex.write(&mut input[len..]).unwrap(); - len += 200.write(&mut input[len..]).unwrap(); + len += "upper hex: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::UpperHex + .write(&mut input[len..]) + .unwrap() + .get(); + len += 200.write(&mut input[len..]).unwrap().get(); _ = len; @@ -743,10 +758,10 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv4: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv4: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 10.0.0.1 as u32 - len += 167772161u32.write(&mut input[len..]).unwrap(); + len += 167772161u32.write(&mut input[len..]).unwrap().get(); _ = len; @@ -764,14 +779,14 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv6: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv6: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 2001:db8::1:1 as byte array let ipv6_arr: [u8; 16] = [ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, ]; - len += ipv6_arr.write(&mut input[len..]).unwrap(); + len += ipv6_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -789,13 +804,13 @@ mod test { testing_logger::setup(); let (mut len, mut input) = new_log(3).unwrap(); - len += "ipv6: ".write(&mut input[len..]).unwrap(); - len += DisplayHint::Ip.write(&mut input[len..]).unwrap(); + len += "ipv6: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::Ip.write(&mut input[len..]).unwrap().get(); // 2001:db8::1:1 as u16 array let ipv6_arr: [u16; 8] = [ 0x2001, 0x0db8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, ]; - len += ipv6_arr.write(&mut input[len..]).unwrap(); + len += ipv6_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -813,11 +828,14 @@ mod test { 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(); + len += "mac: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::LowerMac + .write(&mut input[len..]) + .unwrap() + .get(); // 00:00:5e:00:53:af as byte array let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; - len += mac_arr.write(&mut input[len..]).unwrap(); + len += mac_arr.write(&mut input[len..]).unwrap().get(); _ = len; @@ -835,11 +853,14 @@ mod test { 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(); + len += "mac: ".write(&mut input[len..]).unwrap().get(); + len += DisplayHint::UpperMac + .write(&mut input[len..]) + .unwrap() + .get(); // 00:00:5E:00:53:AF as byte array let mac_arr: [u8; 6] = [0x00, 0x00, 0x5e, 0x00, 0x53, 0xaf]; - len += mac_arr.write(&mut input[len..]).unwrap(); + len += mac_arr.write(&mut input[len..]).unwrap().get(); _ = len; diff --git a/xtask/public-api/aya-log-common.txt b/xtask/public-api/aya-log-common.txt index 1b3e48c1..fd921d9b 100644 --- a/xtask/public-api/aya-log-common.txt +++ b/xtask/public-api/aya-log-common.txt @@ -54,7 +54,7 @@ pub aya_log_common::DisplayHint::LowerMac pub aya_log_common::DisplayHint::UpperHex pub aya_log_common::DisplayHint::UpperMac impl aya_log_common::WriteToBuf for aya_log_common::DisplayHint -pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::option::Option impl core::convert::From for u8 pub fn u8::from(enum_value: aya_log_common::DisplayHint) -> Self impl core::clone::Clone for aya_log_common::DisplayHint @@ -216,41 +216,41 @@ impl aya_log_common::UpperHexFormatter for usize pub trait aya_log_common::UpperMacFormatter impl aya_log_common::UpperMacFormatter for [u8; 6] pub trait aya_log_common::WriteToBuf -pub fn aya_log_common::WriteToBuf::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::WriteToBuf::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for &[u8] -pub fn &[u8]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn &[u8]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for &str -pub fn &str::write(self, buf: &mut [u8]) -> core::result::Result +pub fn &str::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u16; 8] -pub fn [u16; 8]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u16; 8]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u8; 16] -pub fn [u8; 16]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u8; 16]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for [u8; 6] -pub fn [u8; 6]::write(self, buf: &mut [u8]) -> core::result::Result +pub fn [u8; 6]::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for aya_log_common::DisplayHint -pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::result::Result +pub fn aya_log_common::DisplayHint::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for f32 -pub fn f32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn f32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for f64 -pub fn f64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn f64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i16 -pub fn i16::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i16::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i32 -pub fn i32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i64 -pub fn i64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for i8 -pub fn i8::write(self, buf: &mut [u8]) -> core::result::Result +pub fn i8::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for isize -pub fn isize::write(self, buf: &mut [u8]) -> core::result::Result +pub fn isize::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u16 -pub fn u16::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u16::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u32 -pub fn u32::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u32::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u64 -pub fn u64::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u64::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for u8 -pub fn u8::write(self, buf: &mut [u8]) -> core::result::Result +pub fn u8::write(self, buf: &mut [u8]) -> core::option::Option impl aya_log_common::WriteToBuf for usize -pub fn usize::write(self, buf: &mut [u8]) -> core::result::Result +pub fn usize::write(self, buf: &mut [u8]) -> core::option::Option pub type aya_log_common::LogValueLength = u16 From b54a106584bf636cbd0ad217aa62124348e6b29f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 05:07:09 -0400 Subject: [PATCH 17/42] log: update comments These were missed when the code was updated. --- aya-log-common/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aya-log-common/src/lib.rs b/aya-log-common/src/lib.rs index f6cb3517..472090ee 100644 --- a/aya-log-common/src/lib.rs +++ b/aya-log-common/src/lib.rs @@ -178,7 +178,7 @@ pub trait WriteToBuf { macro_rules! impl_write_to_buf { ($type:ident, $arg_type:expr) => { impl WriteToBuf for $type { - // This need not be inlined because the return value is Result where N is + // This need not be inlined because the return value is Option where N is // mem::size_of<$type>, which is a compile-time constant. #[inline(never)] fn write(self, buf: &mut [u8]) -> Option { @@ -204,7 +204,7 @@ impl_write_to_buf!(f32, Argument::F32); impl_write_to_buf!(f64, Argument::F64); impl WriteToBuf for [u8; 16] { - // This need not be inlined because the return value is Result where N is 16, which is a + // This need not be inlined because the return value is Option where N is 16, which is a // compile-time constant. #[inline(never)] fn write(self, buf: &mut [u8]) -> Option { @@ -213,7 +213,7 @@ impl WriteToBuf for [u8; 16] { } impl WriteToBuf for [u16; 8] { - // This need not be inlined because the return value is Result where N is 16, which is a + // This need not be inlined because the return value is Option where N is 16, which is a // compile-time constant. #[inline(never)] fn write(self, buf: &mut [u8]) -> Option { @@ -223,7 +223,7 @@ impl WriteToBuf for [u16; 8] { } impl WriteToBuf for [u8; 6] { - // This need not be inlined because the return value is Result where N is 6, which is a + // This need not be inlined because the return value is Option where N is 6, which is a // compile-time constant. #[inline(never)] fn write(self, buf: &mut [u8]) -> Option { @@ -252,7 +252,7 @@ impl WriteToBuf for &str { } impl WriteToBuf for DisplayHint { - // This need not be inlined because the return value is Result where N is 1, which is a + // This need not be inlined because the return value is Option where N is 1, which is a // compile-time constant. #[inline(never)] fn write(self, buf: &mut [u8]) -> Option { From 58ba66c003d684e3cdb805daff522445818b895c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 9 Aug 2023 17:22:40 -0400 Subject: [PATCH 18/42] xtask: watch for kernel panics on stderr It seems these go to stderr, not stdout. Use `Ctrl-A x` to shut QEMU down if a panic is seen. --- xtask/src/run.rs | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 9b80b6ef..63d33dad 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -6,6 +6,7 @@ use std::{ io::{BufRead as _, BufReader, ErrorKind, Write as _}, path::{Path, PathBuf}, process::{Child, Command, Output, Stdio}, + thread, }; use anyhow::{anyhow, bail, Context as _, Result}; @@ -450,17 +451,42 @@ pub fn run(opts: Options) -> Result<()> { }; } let mut qemu_child = qemu + .stdin(Stdio::piped()) .stdout(Stdio::piped()) + .stderr(Stdio::piped()) .spawn() .with_context(|| format!("failed to spawn {qemu:?}"))?; - let Child { stdout, .. } = &mut qemu_child; + let Child { + stdin, + stdout, + stderr, + .. + } = &mut qemu_child; + let mut stdin = stdin.take().unwrap(); let stdout = stdout.take().unwrap(); let stdout = BufReader::new(stdout); + let stderr = stderr.take().unwrap(); + let stderr = BufReader::new(stderr); + + let stderr = thread::Builder::new() + .spawn(move || { + for line in stderr.lines() { + let line = line.context("failed to read line from stderr")?; + eprintln!("{}", line); + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + if line.contains("end Kernel panic") { + stdin + .write_all(&[0x01, b'x']) + .context("failed to write to stdin")?; + } + } + anyhow::Ok(()) + }) + .unwrap(); let mut outcome = None; for line in stdout.lines() { - let line = - line.with_context(|| format!("failed to read line from {qemu:?}"))?; + let line = line.context("failed to read line from stdout")?; println!("{}", line); // The init program will print "init: success" or "init: failure" to indicate // the outcome of running the binaries it found in /bin. @@ -473,10 +499,6 @@ pub fn run(opts: Options) -> Result<()> { if let Some(previous) = previous { bail!("multiple exit status: previous={previous:?}, current={line}"); } - // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. - if line.contains("end Kernel panic") { - qemu_child.kill().context("failed to kill {qemu:?}")?; - } } } @@ -488,6 +510,8 @@ pub fn run(opts: Options) -> Result<()> { bail!("{qemu:?} failed: {output:?}") } + stderr.join().unwrap()?; + let outcome = outcome.ok_or(anyhow!("init did not exit"))?; match outcome { Ok(()) => {} From ed777273b187cc30afa573101a1fade14a4fb465 Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Thu, 10 Aug 2023 17:22:56 +0200 Subject: [PATCH 19/42] nuclear option: no symbol resolution in the crate --- aya/src/maps/stack_trace.rs | 58 ++++++++++--------------------------- aya/src/util.rs | 19 +++--------- xtask/public-api/aya.txt | 9 +----- 3 files changed, 20 insertions(+), 66 deletions(-) diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index 63a92fe9..8d3add5a 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -1,12 +1,7 @@ //! A hash map of kernel or user space stack traces. //! //! See [`StackTraceMap`] for documentation and examples. -use std::{ - borrow::{Borrow, Cow}, - fs, io, mem, - path::Path, - str::FromStr, -}; +use std::{borrow::Borrow, fs, io, mem, path::Path, str::FromStr}; use crate::{ maps::{IterableMap, MapData, MapError, MapIter, MapKeys}, @@ -51,15 +46,19 @@ use crate::{ /// // here we resolve symbol names using kernel symbols. If this was a user space stack (for /// // example captured from a uprobe), you'd have to load the symbols using some other mechanism /// // (eg loading the target binary debuginfo) -/// for frame in stack_trace.resolve(&ksyms).frames() { -/// println!( -/// "{:#x} {}", -/// frame.ip, -/// frame -/// .symbol_name -/// .as_deref() -/// .unwrap_or("[unknown symbol name]") -/// ); +/// for frame in stack_trace.frames() { +/// if let Some(sym) = ksyms.range(..=frame.ip).next_back().map(|(_, s)| s) { +/// println!( +/// "{:#x} {}", +/// frame.ip, +/// sym +/// ); +/// } else { +/// println!( +/// "{:#x}", +/// frame.ip +/// ); +/// } /// } /// /// # Ok::<(), Error>(()) @@ -118,10 +117,7 @@ impl> StackTraceMap { let frames = frames .into_iter() .take_while(|ip| *ip != 0) - .map(|ip| StackFrame { - ip, - symbol_name: None, - }) + .map(|ip| StackFrame { ip }) .collect::>(); Ok(StackTrace { @@ -162,12 +158,6 @@ impl<'a, T: Borrow> IntoIterator for &'a StackTraceMap { } } -/// A resolver for symbols based on an address obtained from a stack trace. -pub trait SymbolResolver { - /// Resolve a symbol for a given address, if possible. - fn resolve_symbol(&self, addr: u64) -> Option>; -} - /// A kernel or user space stack trace. /// /// See the [`StackTraceMap`] documentation for examples. @@ -178,19 +168,6 @@ pub struct StackTrace { } impl StackTrace { - /// Resolves symbol names using the given symbol map. - /// - /// You can use [`util::kernel_symbols()`](crate::util::kernel_symbols) to load kernel symbols. For - /// user-space traces you need to provide the symbols, for example loading - /// them from debug info. - pub fn resolve(&mut self, symbols: &R) -> &StackTrace { - for frame in self.frames.iter_mut() { - frame.symbol_name = symbols.resolve_symbol(frame.ip).map(|s| s.into_owned()) - } - - self - } - /// Returns the frames in this stack trace. pub fn frames(&self) -> &[StackFrame] { &self.frames @@ -201,11 +178,6 @@ impl StackTrace { pub struct StackFrame { /// The instruction pointer of this frame. pub ip: u64, - /// The symbol name corresponding to the start of this frame. - /// - /// Set to `Some()` if the frame address can be found in the symbols passed - /// to [`StackTrace::resolve`]. - pub symbol_name: Option, } fn sysctl(key: &str) -> Result { diff --git a/aya/src/util.rs b/aya/src/util.rs index 1161885e..4db89af8 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -1,6 +1,5 @@ //! Utility functions. use std::{ - borrow::Cow, collections::BTreeMap, error::Error, ffi::{CStr, CString}, @@ -12,7 +11,6 @@ use std::{ use crate::{ generated::{TC_H_MAJ_MASK, TC_H_MIN_MASK}, - maps::stack_trace::SymbolResolver, Pod, }; @@ -203,25 +201,16 @@ fn parse_cpu_ranges(data: &str) -> Result, ()> { Ok(cpus) } -/// The simplest resolver: a direct map from addresses to strings. -pub type SimpleSymbolResolver = BTreeMap; - -impl SymbolResolver for SimpleSymbolResolver { - fn resolve_symbol(&self, addr: u64) -> Option> { - self.range(..=addr).next_back().map(|(_, s)| s.into()) - } -} - /// Loads kernel symbols from `/proc/kallsyms`. /// -/// The symbols can be passed to [`StackTrace::resolve`](crate::maps::stack_trace::StackTrace::resolve). -pub fn kernel_symbols() -> Result { +/// See [`crate::maps::StackTraceMap`] for an example on how to use this to resolve kernel addresses to symbols. +pub fn kernel_symbols() -> Result, io::Error> { let mut reader = BufReader::new(File::open("/proc/kallsyms")?); parse_kernel_symbols(&mut reader) } -fn parse_kernel_symbols(reader: impl BufRead) -> Result { - let mut syms = SimpleSymbolResolver::new(); +fn parse_kernel_symbols(reader: impl BufRead) -> Result, io::Error> { + let mut syms = BTreeMap::new(); for line in reader.lines() { let line = line?; diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 7adc9b63..db03ee59 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -708,7 +708,6 @@ pub fn aya::maps::stack::Stack::from(t: T) -> T pub mod aya::maps::stack_trace pub struct aya::maps::stack_trace::StackFrame pub aya::maps::stack_trace::StackFrame::ip: u64 -pub aya::maps::stack_trace::StackFrame::symbol_name: core::option::Option impl core::marker::Send for aya::maps::stack_trace::StackFrame impl core::marker::Sync for aya::maps::stack_trace::StackFrame impl core::marker::Unpin for aya::maps::stack_trace::StackFrame @@ -734,7 +733,6 @@ pub struct aya::maps::stack_trace::StackTrace pub aya::maps::stack_trace::StackTrace::id: u32 impl aya::maps::stack_trace::StackTrace pub fn aya::maps::stack_trace::StackTrace::frames(&self) -> &[aya::maps::stack_trace::StackFrame] -pub fn aya::maps::stack_trace::StackTrace::resolve(&mut self, symbols: &R) -> &aya::maps::stack_trace::StackTrace impl> aya::maps::IterableMap for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::get(&self, index: &u32) -> core::result::Result pub fn aya::maps::stack_trace::StackTraceMap::map(&self) -> &aya::maps::MapData @@ -803,10 +801,6 @@ impl core::borrow::BorrowMut for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::stack_trace::StackTraceMap pub fn aya::maps::stack_trace::StackTraceMap::from(t: T) -> T -pub trait aya::maps::stack_trace::SymbolResolver -pub fn aya::maps::stack_trace::SymbolResolver::resolve_symbol(&self, addr: u64) -> core::option::Option> -impl aya::maps::stack_trace::SymbolResolver for aya::util::SimpleSymbolResolver -pub fn aya::util::SimpleSymbolResolver::resolve_symbol(&self, addr: u64) -> core::option::Option> pub enum aya::maps::Map pub aya::maps::Map::Array(aya::maps::MapData) pub aya::maps::Map::BloomFilter(aya::maps::MapData) @@ -6935,11 +6929,10 @@ impl core::borrow::BorrowMut for aya::util::KernelVersion where T: core::m pub fn aya::util::KernelVersion::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::util::KernelVersion pub fn aya::util::KernelVersion::from(t: T) -> T -pub fn aya::util::kernel_symbols() -> core::result::Result +pub fn aya::util::kernel_symbols() -> core::result::Result, std::io::error::Error> pub fn aya::util::nr_cpus() -> core::result::Result pub fn aya::util::online_cpus() -> core::result::Result, std::io::error::Error> pub fn aya::util::syscall_prefix() -> core::result::Result<&'static str, std::io::error::Error> -pub type aya::util::SimpleSymbolResolver = alloc::collections::btree::map::BTreeMap pub macro aya::include_bytes_aligned! pub enum aya::BpfError pub aya::BpfError::BtfError(aya_obj::btf::btf::BtfError) From 5138c731a92a8e5107e41829573617fc624ea9c7 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 11:58:27 -0400 Subject: [PATCH 20/42] util: avoid vector allocation when parsing ksyms --- aya/src/util.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/aya/src/util.rs b/aya/src/util.rs index 4db89af8..65bcb415 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -5,7 +5,9 @@ use std::{ ffi::{CStr, CString}, fs::{self, File}, io::{self, BufRead, BufReader}, - mem, slice, + mem, + num::ParseIntError, + slice, str::{FromStr, Utf8Error}, }; @@ -210,18 +212,24 @@ pub fn kernel_symbols() -> Result, io::Error> { } fn parse_kernel_symbols(reader: impl BufRead) -> Result, io::Error> { - let mut syms = BTreeMap::new(); - - for line in reader.lines() { - let line = line?; - let parts = line.splitn(4, ' ').collect::>(); - let addr = u64::from_str_radix(parts[0], 16) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, line.clone()))?; - let name = parts[2].to_owned(); - syms.insert(addr, name); - } - - Ok(syms) + reader + .lines() + .map(|line| { + let line = line?; + (|| { + let mut parts = line.splitn(4, ' '); + let addr = parts.next()?; + let _kind = parts.next()?; + let name = parts.next()?; + let addr = match u64::from_str_radix(addr, 16) { + Ok(addr) => Some(addr), + Err(ParseIntError { .. }) => None, + }?; + Some((addr, name.to_owned())) + })() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, line.clone())) + }) + .collect() } /// Returns the prefix used by syscalls. From de65ba0067edcc4bd5f79c6a10ec148c974b3bdc Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 12:08:32 -0400 Subject: [PATCH 21/42] xtask: watch for kernel panic in stdout too Seems unclear whether kernel panics go to stdout or stderr, so do them both. --- xtask/src/run.rs | 50 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 63d33dad..c76e3e22 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -5,7 +5,8 @@ use std::{ fs::{copy, create_dir_all, metadata, File}, io::{BufRead as _, BufReader, ErrorKind, Write as _}, path::{Path, PathBuf}, - process::{Child, Command, Output, Stdio}, + process::{Child, ChildStdin, Command, Output, Stdio}, + sync::{Arc, Mutex}, thread, }; @@ -462,32 +463,49 @@ pub fn run(opts: Options) -> Result<()> { stderr, .. } = &mut qemu_child; - let mut stdin = stdin.take().unwrap(); + let stdin = stdin.take().unwrap(); + let stdin = Arc::new(Mutex::new(stdin)); let stdout = stdout.take().unwrap(); let stdout = BufReader::new(stdout); let stderr = stderr.take().unwrap(); let stderr = BufReader::new(stderr); - let stderr = thread::Builder::new() - .spawn(move || { - for line in stderr.lines() { - let line = line.context("failed to read line from stderr")?; - eprintln!("{}", line); - // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. - if line.contains("end Kernel panic") { - stdin - .write_all(&[0x01, b'x']) - .context("failed to write to stdin")?; + fn terminate_if_contains_kernel_panic( + line: &str, + stdin: &Arc>, + ) -> anyhow::Result<()> { + if line.contains("end Kernel panic") { + println!("kernel panic detected; terminating QEMU"); + let mut stdin = stdin.lock().unwrap(); + stdin + .write_all(&[0x01, b'x']) + .context("failed to write to stdin")?; + println!("waiting for QEMU to terminate"); + } + Ok(()) + } + + let stderr = { + let stdin = stdin.clone(); + thread::Builder::new() + .spawn(move || { + for line in stderr.lines() { + let line = line.context("failed to read line from stderr")?; + eprintln!("{}", line); + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + terminate_if_contains_kernel_panic(&line, &stdin)?; } - } - anyhow::Ok(()) - }) - .unwrap(); + anyhow::Ok(()) + }) + .unwrap() + }; let mut outcome = None; for line in stdout.lines() { let line = line.context("failed to read line from stdout")?; println!("{}", line); + // Try to get QEMU to exit on kernel panic; otherwise it might hang indefinitely. + terminate_if_contains_kernel_panic(&line, &stdin)?; // The init program will print "init: success" or "init: failure" to indicate // the outcome of running the binaries it found in /bin. if let Some(line) = line.strip_prefix("init: ") { From 7e14214f47df032fa585d4ca66022b46b9dbd287 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 15:39:49 -0400 Subject: [PATCH 22/42] xtask: add noapic to kernel parameters This might prevent some kernel panics. --- xtask/src/run.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xtask/src/run.rs b/xtask/src/run.rs index c76e3e22..15ee7035 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -393,7 +393,7 @@ pub fn run(opts: Options) -> Result<()> { qemu.args(["-cpu", cpu]); } let console = OsString::from("ttyS0"); - let kernel_args = std::iter::once(("console", &console)) + let mut kernel_args = std::iter::once(("console", &console)) .chain(run_args.clone().map(|run_arg| ("init.arg", run_arg))) .enumerate() .fold(OsString::new(), |mut acc, (i, (k, v))| { @@ -405,6 +405,12 @@ pub fn run(opts: Options) -> Result<()> { acc.push(v); acc }); + // We sometimes see kernel panics containing: + // + // [ 0.064000] Kernel panic - not syncing: IO-APIC + timer doesn't work! Boot with apic=debug and send a report. Then try booting with the 'noapic' option. + // + // Heed the advice and boot with noapic. We don't know why this happens. + kernel_args.push(" noapic"); qemu.args(["-no-reboot", "-nographic", "-m", "512M", "-smp", "2"]) .arg("-append") .arg(kernel_args) From c7a19bcefba25455279d9e718f6430dee7a84b74 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 18:19:24 -0400 Subject: [PATCH 23/42] sys: add map_ids to bpf_prog_get_info_by_fd Allows the caller to pass a slice which the kernel will populate with map ids used by the program. --- aya/src/programs/extension.rs | 2 +- aya/src/programs/lirc_mode2.rs | 2 +- aya/src/programs/mod.rs | 6 +++--- aya/src/sys/bpf.rs | 26 ++++++++++++++++++-------- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 143c909f..00f8b02a 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -151,7 +151,7 @@ impl Extension { /// with the name `func_name` within that BTF object. fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { // retrieve program information - let info = sys::bpf_prog_get_info_by_fd(prog_fd)?; + let info = sys::bpf_prog_get_info_by_fd(prog_fd, &mut [])?; // btf_id refers to the ID of the program btf that was loaded with bpf(BPF_BTF_LOAD) if info.btf_id == 0 { diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index e39bbf1a..39e1d820 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -131,7 +131,7 @@ impl LircLink { /// Get ProgramInfo from this link pub fn info(&self) -> Result { - bpf_prog_get_info_by_fd(self.prog_fd) + bpf_prog_get_info_by_fd(self.prog_fd, &mut []) .map(ProgramInfo) .map_err(Into::into) } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index eab30abe..ff643fa5 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -488,7 +488,7 @@ impl ProgramData { io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd())?; + let info = bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])?; let name = ProgramInfo(info).name_as_str().map(|s| s.to_string()); ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level) } @@ -955,7 +955,7 @@ impl ProgramInfo { io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd())?; + let info = bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])?; Ok(ProgramInfo(info)) } } @@ -991,7 +991,7 @@ pub fn loaded_programs() -> impl Iterator Result(fd: BorrowedFd<'_>) -> Result { +fn bpf_obj_get_info_by_fd( + fd: BorrowedFd<'_>, + init: F, +) -> Result { let mut attr = unsafe { mem::zeroed::() }; - // info gets entirely populated by the kernel - let info = MaybeUninit::zeroed(); + let mut info = unsafe { mem::zeroed() }; + + init(&mut info); attr.info.bpf_fd = fd.as_raw_fd() as u32; attr.info.info = &info as *const _ as u64; @@ -489,7 +493,7 @@ fn bpf_obj_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { Ok(code) => { assert_eq!(code, 0); - Ok(unsafe { info.assume_init() }) + Ok(info) } Err((code, io_error)) => { assert_eq!(code, -1); @@ -501,13 +505,19 @@ fn bpf_obj_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { } } -pub(crate) fn bpf_prog_get_info_by_fd(fd: RawFd) -> Result { +pub(crate) fn bpf_prog_get_info_by_fd( + fd: RawFd, + map_ids: &mut [u32], +) -> Result { let fd = unsafe { BorrowedFd::borrow_raw(fd) }; - bpf_obj_get_info_by_fd::(fd) + bpf_obj_get_info_by_fd(fd, |info: &mut bpf_prog_info| { + info.nr_map_ids = map_ids.len() as _; + info.map_ids = map_ids.as_mut_ptr() as _; + }) } pub(crate) fn bpf_map_get_info_by_fd(fd: BorrowedFd<'_>) -> Result { - bpf_obj_get_info_by_fd::(fd) + bpf_obj_get_info_by_fd(fd, |_| {}) } pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result { @@ -525,7 +535,7 @@ pub(crate) fn bpf_link_get_fd_by_id(link_id: u32) -> Result) -> Result { - bpf_obj_get_info_by_fd::(fd) + bpf_obj_get_info_by_fd(fd, |_| {}) } pub(crate) fn btf_obj_get_info_by_fd( From 5ac186299b468e54f93b16393bae44b3d896c544 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 18:31:49 -0400 Subject: [PATCH 24/42] sys: refactor btf_obj_get_info_by_fd to share code --- aya/src/programs/extension.rs | 35 +++++++++++------------------------ aya/src/sys/bpf.rs | 24 ++++++++---------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 00f8b02a..3c389791 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -159,36 +159,23 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr } // the bpf fd of the BTF object - let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id).map_err(|io_error| SyscallError { - call: "bpf_btf_get_fd_by_id", - io_error, - })?; + let btf_fd = sys::bpf_btf_get_fd_by_id(info.btf_id)?; // we need to read the btf bytes into a buffer but we don't know the size ahead of time. // assume 4kb. if this is too small we can resize based on the size obtained in the response. let mut buf = vec![0u8; 4096]; - let btf_info = match sys::btf_obj_get_info_by_fd(btf_fd, &buf) { - Ok(info) => { - if info.btf_size > buf.len() as u32 { - buf.resize(info.btf_size as usize, 0u8); - let btf_info = - sys::btf_obj_get_info_by_fd(btf_fd, &buf).map_err(|io_error| SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - })?; - Ok(btf_info) - } else { - Ok(info) - } + loop { + let info = sys::btf_obj_get_info_by_fd(btf_fd, &mut buf)?; + let btf_size = info.btf_size as usize; + if btf_size > buf.len() { + buf.resize(btf_size, 0u8); + continue; } - Err(io_error) => Err(SyscallError { - call: "bpf_prog_get_info_by_fd", - io_error, - }), - }?; + buf.truncate(btf_size); + break; + } - let btf = Btf::parse(&buf[0..btf_info.btf_size as usize], Endianness::default()) - .map_err(ProgramError::Btf)?; + let btf = Btf::parse(&buf, Endianness::default()).map_err(ProgramError::Btf)?; let btf_id = btf .id_by_type_name_kind(func_name, BtfKind::Func) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index db70fe5a..4e3c3602 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -539,22 +539,14 @@ pub(crate) fn bpf_link_get_info_by_fd(fd: BorrowedFd<'_>) -> Result Result { - let mut attr = unsafe { mem::zeroed::() }; - let mut info = unsafe { mem::zeroed::() }; - let buf_size = buf.len() as u32; - info.btf = buf.as_ptr() as u64; - info.btf_size = buf_size; - attr.info.bpf_fd = prog_fd as u32; - attr.info.info = &info as *const bpf_btf_info as u64; - attr.info.info_len = mem::size_of::() as u32; - - match sys_bpf(bpf_cmd::BPF_OBJ_GET_INFO_BY_FD, &mut attr) { - Ok(_) => Ok(info), - Err((_, err)) => Err(err), - } + fd: RawFd, + buf: &mut [u8], +) -> Result { + let fd = unsafe { BorrowedFd::borrow_raw(fd) }; + bpf_obj_get_info_by_fd(fd, |info: &mut bpf_btf_info| { + info.btf = buf.as_mut_ptr() as _; + info.btf_size = buf.len() as _; + }) } pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> SysResult { From d85afe78f978d088e34412b8e39eafa502be5d66 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 11 Aug 2023 13:15:52 +0100 Subject: [PATCH 25/42] xtask: Fix aya public-api Changes to the bitflags crate changed some of our public api signature. Signed-off-by: Dave Tucker --- xtask/public-api/aya.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index db03ee59..69f57fb4 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -4645,9 +4645,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpFlags impl core::marker::Unpin for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpFlags -impl bitflags::traits::BitFlags for aya::programs::xdp::XdpFlags where B: bitflags::traits::Flags -pub type aya::programs::xdp::XdpFlags::Iter = bitflags::iter::Iter -pub type aya::programs::xdp::XdpFlags::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::programs::xdp::XdpFlags where U: core::convert::From pub fn aya::programs::xdp::XdpFlags::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpFlags where U: core::convert::Into @@ -6775,9 +6772,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpFlags impl core::marker::Unpin for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpFlags impl core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpFlags -impl bitflags::traits::BitFlags for aya::programs::xdp::XdpFlags where B: bitflags::traits::Flags -pub type aya::programs::xdp::XdpFlags::Iter = bitflags::iter::Iter -pub type aya::programs::xdp::XdpFlags::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::programs::xdp::XdpFlags where U: core::convert::From pub fn aya::programs::xdp::XdpFlags::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpFlags where U: core::convert::Into @@ -7180,9 +7174,6 @@ impl core::marker::Sync for aya::VerifierLogLevel impl core::marker::Unpin for aya::VerifierLogLevel impl core::panic::unwind_safe::RefUnwindSafe for aya::VerifierLogLevel impl core::panic::unwind_safe::UnwindSafe for aya::VerifierLogLevel -impl bitflags::traits::BitFlags for aya::VerifierLogLevel where B: bitflags::traits::Flags -pub type aya::VerifierLogLevel::Iter = bitflags::iter::Iter -pub type aya::VerifierLogLevel::IterNames = bitflags::iter::IterNames impl core::convert::Into for aya::VerifierLogLevel where U: core::convert::From pub fn aya::VerifierLogLevel::into(self) -> U impl core::convert::TryFrom for aya::VerifierLogLevel where U: core::convert::Into From 02124002c88d7a89d6c9afd89857c4c301e09801 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 11 Aug 2023 10:28:46 +0100 Subject: [PATCH 26/42] .github: Add clang-format Signed-off-by: Dave Tucker --- .github/workflows/ci.yml | 3 +++ aya-obj/include/linux_wrapper.h | 8 ++++---- bpf/aya-bpf-bindings/include/bindings.h | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9eece29..1ff70200 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,9 @@ jobs: with: tool: cargo-hack,taplo-cli + - name: Check C formatting + run: git ls-files -- '*.c' '*.h' | xargs clang-format --dry-run --Werror + - run: taplo fmt --check - name: Check formatting diff --git a/aya-obj/include/linux_wrapper.h b/aya-obj/include/linux_wrapper.h index 58ffa680..8be2459a 100644 --- a/aya-obj/include/linux_wrapper.h +++ b/aya-obj/include/linux_wrapper.h @@ -1,11 +1,11 @@ +#include #include #include -#include #include -#include -#include -#include +#include #include +#include +#include /* workaround the fact that bindgen can't parse the IOC macros */ int AYA_PERF_EVENT_IOC_ENABLE = PERF_EVENT_IOC_ENABLE; diff --git a/bpf/aya-bpf-bindings/include/bindings.h b/bpf/aya-bpf-bindings/include/bindings.h index b2f3b072..05344214 100644 --- a/bpf/aya-bpf-bindings/include/bindings.h +++ b/bpf/aya-bpf-bindings/include/bindings.h @@ -3,9 +3,9 @@ // https://elixir.bootlin.com/linux/v5.13/source/include/uapi/linux/types.h typedef __u32 __bitwise __wsum; +#include "bpf_helpers.h" #include -#include -#include // needed for TC_ACT_* #include -#include "bpf_helpers.h" \ No newline at end of file +#include +#include From db975e977813ed6961963f7052ae53bc6df69309 Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Mon, 31 Jul 2023 11:05:36 +0100 Subject: [PATCH 27/42] aya: Don't store bpf_fd in MapData This is only used in create and therefore can be passed as a parameter. Signed-off-by: Dave Tucker --- aya/src/bpf.rs | 7 ++--- aya/src/maps/bloom_filter.rs | 9 ------ aya/src/maps/hash_map/hash_map.rs | 22 ------------- aya/src/maps/lpm_trie.rs | 12 -------- aya/src/maps/mod.rs | 51 +++++++++++++++---------------- aya/src/sys/bpf.rs | 3 +- xtask/public-api/aya.txt | 2 +- 7 files changed, 29 insertions(+), 77 deletions(-) diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 6b63c103..ee074dba 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -4,7 +4,7 @@ use std::{ ffi::CString, fs, io, os::{ - fd::{OwnedFd, RawFd}, + fd::{AsFd as _, OwnedFd, RawFd}, raw::c_int, }, path::{Path, PathBuf}, @@ -479,7 +479,6 @@ impl<'a> BpfLoader<'a> { obj, fd: None, pinned: false, - btf_fd: btf_fd.as_ref().map(Arc::clone), }; let fd = match map.obj.pinning() { PinningType::ByName => { @@ -494,7 +493,7 @@ impl<'a> BpfLoader<'a> { fd as RawFd } Err(_) => { - let fd = map.create(&name)?; + let fd = map.create(&name, btf_fd.as_deref().map(|f| f.as_fd()))?; map.pin(&name, path).map_err(|error| MapError::PinError { name: Some(name.to_string()), error, @@ -503,7 +502,7 @@ impl<'a> BpfLoader<'a> { } } } - PinningType::None => map.create(&name)?, + PinningType::None => map.create(&name, btf_fd.as_deref().map(|f| f.as_fd()))?, }; if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss { bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index b38bccf4..03374b4e 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -116,7 +116,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( BloomFilter::<_, u16>::new(&map), @@ -145,7 +144,6 @@ mod tests { }), fd: None, pinned: false, - btf_fd: None, }; let map = Map::PerfEventArray(map_data); @@ -162,7 +160,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( @@ -177,7 +174,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; assert!(BloomFilter::<_, u32>::new(&mut map).is_ok()); @@ -189,7 +185,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let map = Map::BloomFilter(map_data); @@ -204,7 +199,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); @@ -228,7 +222,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); @@ -242,7 +235,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); @@ -265,7 +257,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 0cb8e408..cbd2fc81 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -147,7 +147,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( HashMap::<_, u8, u32>::new(&map), @@ -164,7 +163,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( HashMap::<_, u32, u16>::new(&map), @@ -181,7 +179,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; let map = Map::Array(map_data); @@ -197,7 +194,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; let map = Map::HashMap(map_data); @@ -216,7 +212,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( @@ -231,7 +226,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; assert!(HashMap::<_, u32, u32>::new(&mut map).is_ok()); @@ -243,7 +237,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let map = Map::HashMap(map_data); @@ -268,7 +261,6 @@ mod tests { }), fd: Some(42), pinned: false, - btf_fd: None, }; let map = Map::HashMap(map_data); @@ -284,7 +276,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); @@ -308,7 +299,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); @@ -329,7 +319,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); @@ -344,7 +333,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); @@ -368,7 +356,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); @@ -382,7 +369,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -405,7 +391,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -442,7 +427,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let keys = hm.keys().collect::, _>>(); @@ -491,7 +475,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -524,7 +507,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -562,7 +544,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let items = hm.iter().collect::, _>>().unwrap(); @@ -600,7 +581,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -639,7 +619,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); @@ -687,7 +666,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 075aa558..864eb431 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -238,7 +238,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( LpmTrie::<_, u16, u32>::new(&map), @@ -255,7 +254,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( LpmTrie::<_, u32, u16>::new(&map), @@ -283,7 +281,6 @@ mod tests { data: Vec::new(), }), fd: None, - btf_fd: None, pinned: false, }; @@ -301,7 +298,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, }; assert_matches!( @@ -316,7 +312,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; assert!(LpmTrie::<_, u32, u32>::new(&mut map).is_ok()); @@ -328,7 +323,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let map = Map::LpmTrie(map_data); @@ -343,7 +337,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); @@ -368,7 +361,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); @@ -385,7 +377,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); @@ -410,7 +401,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); @@ -425,7 +415,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); @@ -450,7 +439,6 @@ mod tests { obj: new_obj_map(), fd: Some(42), pinned: false, - btf_fd: None, }; let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 25ca21be..28fd688e 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -42,10 +42,9 @@ use std::{ marker::PhantomData, mem, ops::Deref, - os::fd::{AsFd as _, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, OwnedFd, RawFd}, path::Path, ptr, - sync::Arc, }; use crate::util::KernelVersion; @@ -482,14 +481,17 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { pub struct MapData { pub(crate) obj: obj::Map, pub(crate) fd: Option, - pub(crate) btf_fd: Option>, /// Indicates if this map has been pinned to bpffs pub pinned: bool, } impl MapData { /// Creates a new map with the provided `name` - pub fn create(&mut self, name: &str) -> Result { + pub fn create( + &mut self, + name: &str, + btf_fd: Option>, + ) -> Result { if self.fd.is_some() { return Err(MapError::AlreadyCreated { name: name.into() }); } @@ -500,23 +502,19 @@ impl MapData { let kernel_version = KernelVersion::current().unwrap(); #[cfg(test)] let kernel_version = KernelVersion::new(0xff, 0xff, 0xff); - let fd = bpf_create_map( - &c_name, - &self.obj, - self.btf_fd.as_ref().map(|f| f.as_fd()), - kernel_version, - ) - .map_err(|(code, io_error)| { - if kernel_version < KernelVersion::new(5, 11, 0) { - maybe_warn_rlimit(); - } + let fd = bpf_create_map(&c_name, &self.obj, btf_fd, kernel_version).map_err( + |(code, io_error)| { + if kernel_version < KernelVersion::new(5, 11, 0) { + maybe_warn_rlimit(); + } - MapError::CreateError { - name: name.into(), - code, - io_error, - } - })?; + MapError::CreateError { + name: name.into(), + code, + io_error, + } + }, + )?; Ok(*self.fd.insert(fd as RawFd)) } @@ -561,7 +559,6 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::ByName), fd: Some(fd.into_raw_fd()), - btf_fd: None, pinned: true, }) } @@ -577,7 +574,6 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::None), fd: Some(fd.into_raw_fd()), - btf_fd: None, pinned: false, }) } @@ -629,7 +625,6 @@ impl Clone for MapData { MapData { obj: self.obj.clone(), fd: self.fd.map(|fd| unsafe { libc::dup(fd) }), - btf_fd: self.btf_fd.as_ref().map(Arc::clone), pinned: self.pinned, } } @@ -864,7 +859,6 @@ mod tests { obj: new_obj_map(), fd: None, pinned: false, - btf_fd: None, } } @@ -879,9 +873,12 @@ mod tests { }); let mut map = new_map(); - assert_matches!(map.create("foo"), Ok(42)); + assert_matches!(map.create("foo", None), Ok(42)); assert_eq!(map.fd, Some(42)); - assert_matches!(map.create("foo"), Err(MapError::AlreadyCreated { .. })); + assert_matches!( + map.create("foo", None), + Err(MapError::AlreadyCreated { .. }) + ); } #[test] @@ -889,7 +886,7 @@ mod tests { override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT)))); let mut map = new_map(); - let ret = map.create("foo"); + let ret = map.create("foo", None); assert_matches!(ret, Err(MapError::CreateError { .. })); if let Err(MapError::CreateError { name, diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 4e3c3602..1cc144c7 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -732,10 +732,9 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { }), fd: None, pinned: false, - btf_fd: None, }; - if let Ok(map_fd) = map_data.create("aya_global") { + if let Ok(map_fd) = map_data.create("aya_global", None) { insns[0].imm = map_fd; let gpl = b"GPL\0"; diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 69f57fb4..c8e54bec 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1230,7 +1230,7 @@ pub fn aya::maps::lpm_trie::LpmTrie::from(t: T) -> T pub struct aya::maps::MapData pub aya::maps::MapData::pinned: bool impl aya::maps::MapData -pub fn aya::maps::MapData::create(&mut self, name: &str) -> core::result::Result +pub fn aya::maps::MapData::create(&mut self, name: &str, btf_fd: core::option::Option>) -> core::result::Result pub fn aya::maps::MapData::fd(&self) -> core::option::Option pub fn aya::maps::MapData::from_fd(fd: std::os::fd::owned::OwnedFd) -> core::result::Result pub fn aya::maps::MapData::from_pin>(path: P) -> core::result::Result From d88ca62aaaff690335c18ac725164c82fd173be2 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 18:47:35 -0400 Subject: [PATCH 28/42] programs: Plug attach_btf_obj_fd leak `ProgramData::attach_btf_obj_fd` is now owned. This means that `ProgramData` now closes the file descriptor on drop. Updates #612. --- aya/src/programs/extension.rs | 8 ++++---- aya/src/programs/mod.rs | 17 +++++------------ aya/src/sys/bpf.rs | 21 ++++++++++++--------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 3c389791..85e9c3c1 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -1,5 +1,5 @@ //! Extension programs. -use std::os::fd::{AsRawFd, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd}; use thiserror::Error; use object::Endianness; @@ -72,7 +72,7 @@ impl Extension { let target_prog_fd = program.as_raw_fd(); let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?; - self.data.attach_btf_obj_fd = Some(btf_fd as u32); + self.data.attach_btf_obj_fd = Some(btf_fd); self.data.attach_prog_fd = Some(target_prog_fd); self.data.attach_btf_id = Some(btf_id); load_program(BPF_PROG_TYPE_EXT, &mut self.data) @@ -149,7 +149,7 @@ impl Extension { /// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function /// with the name `func_name` within that BTF object. -fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { +fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> { // retrieve program information let info = sys::bpf_prog_get_info_by_fd(prog_fd, &mut [])?; @@ -165,7 +165,7 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr // assume 4kb. if this is too small we can resize based on the size obtained in the response. let mut buf = vec![0u8; 4096]; loop { - let info = sys::btf_obj_get_info_by_fd(btf_fd, &mut buf)?; + let info = sys::btf_obj_get_info_by_fd(btf_fd.as_fd(), &mut buf)?; let btf_size = info.btf_size as usize; if btf_size > buf.len() { buf.resize(btf_size, 0u8); diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index ff643fa5..32ffedc7 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -406,7 +406,7 @@ pub(crate) struct ProgramData { pub(crate) fd: Option, pub(crate) links: LinkMap, pub(crate) expected_attach_type: Option, - pub(crate) attach_btf_obj_fd: Option, + pub(crate) attach_btf_obj_fd: Option, pub(crate) attach_btf_id: Option, pub(crate) attach_prog_fd: Option, pub(crate) btf_fd: Option>, @@ -450,16 +450,9 @@ impl ProgramData { } else { None }; - let attach_btf_obj_fd = if info.attach_btf_obj_id > 0 { - let fd = - bpf_btf_get_fd_by_id(info.attach_btf_obj_id).map_err(|io_error| SyscallError { - call: "bpf_btf_get_fd_by_id", - io_error, - })?; - Some(fd as u32) - } else { - None - }; + let attach_btf_obj_fd = (info.attach_btf_obj_id != 0) + .then(|| bpf_btf_get_fd_by_id(info.attach_btf_obj_id)) + .transpose()?; Ok(ProgramData { name, @@ -604,7 +597,7 @@ fn load_program( kernel_version: target_kernel_version, expected_attach_type: *expected_attach_type, prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()), - attach_btf_obj_fd: *attach_btf_obj_fd, + attach_btf_obj_fd: attach_btf_obj_fd.as_ref().map(|fd| fd.as_fd()), attach_btf_id: *attach_btf_id, attach_prog_fd: *attach_prog_fd, func_info_rec_size: *func_info_rec_size, diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 4e3c3602..fae2d30c 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -118,7 +118,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> { pub(crate) kernel_version: u32, pub(crate) expected_attach_type: Option, pub(crate) prog_btf_fd: Option>, - pub(crate) attach_btf_obj_fd: Option, + pub(crate) attach_btf_obj_fd: Option>, pub(crate) attach_btf_id: Option, pub(crate) attach_prog_fd: Option, pub(crate) func_info_rec_size: usize, @@ -181,7 +181,7 @@ pub(crate) fn bpf_load_program( u.log_size = log_buf.len() as u32; } if let Some(v) = aya_attr.attach_btf_obj_fd { - u.__bindgen_anon_1.attach_btf_obj_fd = v; + u.__bindgen_anon_1.attach_btf_obj_fd = v.as_raw_fd() as _; } if let Some(v) = aya_attr.attach_prog_fd { u.__bindgen_anon_1.attach_prog_fd = v as u32; @@ -539,10 +539,9 @@ pub(crate) fn bpf_link_get_info_by_fd(fd: BorrowedFd<'_>) -> Result, buf: &mut [u8], ) -> Result { - let fd = unsafe { BorrowedFd::borrow_raw(fd) }; bpf_obj_get_info_by_fd(fd, |info: &mut bpf_btf_info| { info.btf = buf.as_mut_ptr() as _; info.btf_size = buf.len() as _; @@ -595,14 +594,18 @@ unsafe fn fd_sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { Ok(OwnedFd::from_raw_fd(fd)) } -pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result { +pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> Result { let mut attr = unsafe { mem::zeroed::() }; attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id; - match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) { - Ok(v) => Ok(v as RawFd), - Err((_, err)) => Err(err), - } + // SAFETY: BPF_BTF_GET_FD_BY_ID returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &mut attr) }.map_err(|(code, io_error)| { + assert_eq!(code, -1); + SyscallError { + call: "bpf_btf_get_fd_by_id", + io_error, + } + }) } pub(crate) fn is_prog_name_supported() -> bool { From e1a556894c412daeb44c09c6aa2f9f4489952f34 Mon Sep 17 00:00:00 2001 From: Andrew Stoycos Date: Mon, 24 Jul 2023 12:16:23 -0400 Subject: [PATCH 29/42] aya: add helper methods for ProgramInfo - Add helper methods to get useful information from the ProgramInfo object which is returned by the `loaded_programs()` API. Specifically this code mirrors the `bpftool prog` command in terms of useful fields. - Add a new API macro to each aya `Program` type to allow us to fetch its accompanying `ProgramInfo` metadata after its been loaded. - Add a new ProgramInfo constructor that builds a new instance using a raw fd. - Add a smoke test for the loaded_programs() API as well as all the relevant methods on the ProgramInfo type. Signed-off-by: Andrew Stoycos --- aya/src/programs/lirc_mode2.rs | 9 +- aya/src/programs/mod.rs | 142 +++++++++++++++++++++-- aya/src/programs/utils.rs | 48 +++++++- test/integration-test/src/tests/smoke.rs | 31 ++++- xtask/public-api/aya.txt | 96 ++++++++++++++- 5 files changed, 306 insertions(+), 20 deletions(-) diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index 39e1d820..88d5c6c0 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -4,10 +4,7 @@ use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd}; use crate::{ generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, programs::{load_program, query, Link, ProgramData, ProgramError, ProgramInfo}, - sys::{ - bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, - SyscallError, - }, + sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id, SyscallError}, }; use libc::{close, dup}; @@ -131,9 +128,7 @@ impl LircLink { /// Get ProgramInfo from this link pub fn info(&self) -> Result { - bpf_prog_get_info_by_fd(self.prog_fd, &mut []) - .map(ProgramInfo) - .map_err(Into::into) + ProgramInfo::new_from_fd(self.prog_fd) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 32ffedc7..42bec325 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -68,9 +68,11 @@ use libc::ENOSPC; use std::{ ffi::CString, io, + num::NonZeroU32, os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, path::{Path, PathBuf}, sync::Arc, + time::{Duration, SystemTime}, }; use thiserror::Error; @@ -108,6 +110,7 @@ use crate::{ maps::MapError, obj::{self, btf::BtfError, Function, VerifierLog}, pin::PinError, + programs::utils::{boot_time, get_fdinfo}, sys::{ bpf_btf_get_fd_by_id, bpf_get_object, bpf_link_get_fd_by_id, bpf_link_get_info_by_fd, bpf_load_program, bpf_pin_object, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, @@ -476,14 +479,15 @@ impl ProgramData { ) -> Result, ProgramError> { let path_string = CString::new(path.as_ref().as_os_str().to_string_lossy().as_bytes()).unwrap(); + let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "bpf_obj_get", io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])?; - let name = ProgramInfo(info).name_as_str().map(|s| s.to_string()); - ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info, verifier_log_level) + let info = ProgramInfo::new_from_fd(fd.as_raw_fd())?; + let name = info.name_as_str().map(|s| s.to_string()); + ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level) } } @@ -901,11 +905,65 @@ impl_try_from_program!( CgroupDevice, ); +/// Returns information about a loaded program with the [`ProgramInfo`] structure. +/// +/// This information is populated at load time by the kernel and can be used +/// to correlate a given [`Program`] to it's corresponding [`ProgramInfo`] +/// metadata. +macro_rules! impl_program_info { + ($($struct_name:ident),+ $(,)?) => { + $( + impl $struct_name { + /// Returns the file descriptor of this Program. + pub fn program_info(&self) -> Result { + let fd = self.data.fd_or_err()?; + + ProgramInfo::new_from_fd(fd.as_raw_fd()) + } + } + )+ + } +} + +impl_program_info!( + KProbe, + UProbe, + TracePoint, + SocketFilter, + Xdp, + SkMsg, + SkSkb, + SchedClassifier, + CgroupSkb, + CgroupSysctl, + CgroupSockopt, + LircMode2, + PerfEvent, + Lsm, + RawTracePoint, + BtfTracePoint, + FEntry, + FExit, + Extension, + CgroupSockAddr, + SkLookup, + SockOps, + CgroupSock, + CgroupDevice, +); + /// Provides information about a loaded program, like name, id and statistics #[derive(Debug)] pub struct ProgramInfo(bpf_prog_info); impl ProgramInfo { + fn new_from_fd(fd: RawFd) -> Result { + Ok(ProgramInfo(bpf_prog_get_info_by_fd( + fd.as_raw_fd(), + &mut [], + )?)) + } + /// The name of the program as was provided when it was load. This is limited to 16 bytes pub fn name(&self) -> &[u8] { let length = self @@ -921,23 +979,89 @@ impl ProgramInfo { unsafe { std::slice::from_raw_parts(self.0.name.as_ptr() as *const _, length) } } - /// The name of the program as a &str. If the name was not valid unicode, None is returned + /// The name of the program as a &str. If the name was not valid unicode, None is returned. pub fn name_as_str(&self) -> Option<&str> { std::str::from_utf8(self.name()).ok() } - /// The program id for this program. Each program has a unique id. + /// The id for this program. Each program has a unique id. pub fn id(&self) -> u32 { self.0.id } - /// Returns the fd associated with the program. + /// The program tag. + /// + /// The program tag is a SHA sum of the program's instructions which be used as an alternative to + /// [`Self::id()`]". A program's id can vary every time it's loaded or unloaded, but the tag + /// will remain the same. + pub fn tag(&self) -> u64 { + u64::from_be_bytes(self.0.tag) + } + + /// The program type as defined by the linux kernel enum + /// [`bpf_prog_type`](https://elixir.bootlin.com/linux/v6.4.4/source/include/uapi/linux/bpf.h#L948). + pub fn program_type(&self) -> u32 { + self.0.type_ + } + + /// Returns true if the program is defined with a GPL-compatible license. + pub fn gpl_compatible(&self) -> bool { + self.0.gpl_compatible() != 0 + } + + /// The ids of the maps used by the program. + pub fn map_ids(&self) -> Result, ProgramError> { + let fd = self.fd()?; + let mut map_ids = vec![0u32; self.0.nr_map_ids as usize]; + + bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut map_ids)?; + + Ok(map_ids) + } + + /// The btf id for the program. + pub fn btf_id(&self) -> Option { + NonZeroU32::new(self.0.btf_id) + } + + /// The size in bytes of the program's translated eBPF bytecode, which is + /// the bytecode after it has been passed though the verifier where it was + /// possibly modified by the kernel. + pub fn size_translated(&self) -> u32 { + self.0.xlated_prog_len + } + + /// The size in bytes of the program's JIT-compiled machine code. + pub fn size_jitted(&self) -> u32 { + self.0.jited_prog_len + } + + /// How much memory in bytes has been allocated and locked for the program. + pub fn memory_locked(&self) -> Result { + get_fdinfo(self.fd()?.as_fd(), "memlock") + } + + /// The number of verified instructions in the program. + /// + /// This may be less than the total number of instructions in the compiled + /// program due to dead code elimination in the verifier. + pub fn verified_instruction_count(&self) -> u32 { + self.0.verified_insns + } + + /// The time the program was loaded. + pub fn loaded_at(&self) -> SystemTime { + boot_time() + Duration::from_nanos(self.0.load_time) + } + + /// Returns a file descriptor referencing the program. /// - /// The returned fd must be closed when no longer needed. - pub fn fd(&self) -> Result { + /// The returned file descriptor can be closed at any time and doing so does + /// not influence the life cycle of the program. + pub fn fd(&self) -> Result { let Self(info) = self; let fd = bpf_prog_get_fd_by_id(info.id)?; - Ok(fd.into_raw_fd()) + Ok(fd) } /// Loads a program from a pinned path in bpffs. diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index 66f62142..5913e8eb 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -1,5 +1,12 @@ //! Common functions shared between multiple eBPF program types. -use std::{ffi::CStr, io, path::Path}; +use std::{ + ffi::CStr, + fs::File, + io::{self, BufRead, BufReader}, + os::fd::{AsRawFd as _, BorrowedFd}, + path::Path, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; use crate::{ programs::{FdLink, Link, ProgramData, ProgramError}, @@ -22,7 +29,7 @@ pub(crate) fn attach_raw_tracepoint>( program_data.links.insert(FdLink::new(pfd).into()) } -/// Find tracefs filesystem path +/// Find tracefs filesystem path. pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> { lazy_static::lazy_static! { static ref TRACE_FS: Option<&'static Path> = { @@ -50,3 +57,40 @@ pub(crate) fn find_tracefs_path() -> Result<&'static Path, ProgramError> { .as_deref() .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "tracefs not found").into()) } + +/// The time at which the system is booted. +pub(crate) fn boot_time() -> SystemTime { + let get_time = |clock_id| { + let mut time = unsafe { std::mem::zeroed::() }; + assert_eq!( + unsafe { libc::clock_gettime(clock_id, &mut time) }, + 0, + "clock_gettime({}, _)", + clock_id + ); + let libc::timespec { tv_sec, tv_nsec } = time; + + Duration::new(tv_sec as u64, tv_nsec as u32) + }; + let since_boot = get_time(libc::CLOCK_BOOTTIME); + let since_epoch = get_time(libc::CLOCK_REALTIME); + UNIX_EPOCH + since_boot - since_epoch +} + +/// Get the specified information from a file descriptor's fdinfo. +pub(crate) fn get_fdinfo(fd: BorrowedFd, key: &str) -> Result { + let info = File::open(format!("/proc/self/fdinfo/{}", fd.as_raw_fd()))?; + let reader = BufReader::new(info); + for line in reader.lines() { + let line = line.map_err(ProgramError::IOError)?; + if !line.contains(key) { + continue; + } + + let (_key, val) = line.rsplit_once('\t').unwrap(); + + return Ok(val.parse().unwrap()); + } + + Ok(0) +} diff --git a/test/integration-test/src/tests/smoke.rs b/test/integration-test/src/tests/smoke.rs index 78614bd9..861e9661 100644 --- a/test/integration-test/src/tests/smoke.rs +++ b/test/integration-test/src/tests/smoke.rs @@ -1,5 +1,5 @@ use aya::{ - programs::{Extension, TracePoint, Xdp, XdpFlags}, + programs::{loaded_programs, Extension, TracePoint, Xdp, XdpFlags}, util::KernelVersion, Bpf, BpfLoader, }; @@ -65,3 +65,32 @@ fn extension() { let drop_: &mut Extension = bpf.program_mut("xdp_drop").unwrap().try_into().unwrap(); drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap(); } + +#[test] +fn list_loaded_programs() { + // Load a program. + let mut bpf = Bpf::load(crate::PASS).unwrap(); + let dispatcher: &mut Xdp = bpf.program_mut("pass").unwrap().try_into().unwrap(); + dispatcher.load().unwrap(); + dispatcher.attach("lo", XdpFlags::default()).unwrap(); + + // Ensure the loaded_programs() api doesn't panic. + let prog = loaded_programs() + .map(|p| p.unwrap()) + .find(|p| p.name_as_str().unwrap() == "pass") + .unwrap(); + + // Ensure all relevant helper functions don't panic. + prog.name(); + prog.id(); + prog.tag(); + prog.program_type(); + prog.gpl_compatible(); + prog.map_ids().unwrap(); + prog.btf_id(); + prog.size_translated(); + prog.memory_locked().unwrap(); + prog.verified_instruction_count(); + prog.loaded_at(); + prog.fd().unwrap(); +} diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 69f57fb4..f4760787 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -1811,6 +1811,8 @@ impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_device::CgroupDevice::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_device::CgroupDevice +pub fn aya::programs::cgroup_device::CgroupDevice::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::drop(&mut self) @@ -1952,6 +1954,8 @@ impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_skb::CgroupSkb +pub fn aya::programs::cgroup_skb::CgroupSkb::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::drop(&mut self) @@ -2060,6 +2064,8 @@ impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock::CgroupSock +pub fn aya::programs::cgroup_sock::CgroupSock::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::drop(&mut self) @@ -2168,6 +2174,8 @@ impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock_addr::CgroupSockAddr +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::drop(&mut self) @@ -2276,6 +2284,8 @@ impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sockopt::CgroupSockopt +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::drop(&mut self) @@ -2384,6 +2394,8 @@ impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sysctl::CgroupSysctl +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::drop(&mut self) @@ -2527,6 +2539,8 @@ impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::extension::Extension::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::extension::Extension +pub fn aya::programs::extension::Extension::program_info(&self) -> core::result::Result +impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::extension::Extension pub fn aya::programs::extension::Extension::drop(&mut self) @@ -2639,6 +2653,8 @@ impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fentry::FEntry::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fentry::FEntry +pub fn aya::programs::fentry::FEntry::program_info(&self) -> core::result::Result +impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::drop(&mut self) @@ -2751,6 +2767,8 @@ impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fexit::FExit::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fexit::FExit +pub fn aya::programs::fexit::FExit::program_info(&self) -> core::result::Result +impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::drop(&mut self) @@ -2900,6 +2918,8 @@ impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::kprobe::KProbe +pub fn aya::programs::kprobe::KProbe::program_info(&self) -> core::result::Result +impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::drop(&mut self) @@ -3400,6 +3420,8 @@ impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lirc_mode2::LircMode2::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lirc_mode2::LircMode2 +pub fn aya::programs::lirc_mode2::LircMode2::program_info(&self) -> core::result::Result +impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::drop(&mut self) @@ -3447,6 +3469,8 @@ impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lsm::Lsm::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lsm::Lsm +pub fn aya::programs::lsm::Lsm::program_info(&self) -> core::result::Result +impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::drop(&mut self) @@ -3732,6 +3756,8 @@ impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::perf_event::PerfEvent::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::perf_event::PerfEvent +pub fn aya::programs::perf_event::PerfEvent::program_info(&self) -> core::result::Result +impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::drop(&mut self) @@ -3924,6 +3950,8 @@ impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::program_info(&self) -> core::result::Result +impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::drop(&mut self) @@ -4064,6 +4092,8 @@ impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tp_btf::BtfTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tp_btf::BtfTracePoint +pub fn aya::programs::tp_btf::BtfTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::drop(&mut self) @@ -4213,6 +4243,8 @@ impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::trace_point::TracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::trace_point::TracePoint +pub fn aya::programs::trace_point::TracePoint::program_info(&self) -> core::result::Result +impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::drop(&mut self) @@ -4371,6 +4403,8 @@ impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::uprobe::UProbe +pub fn aya::programs::uprobe::UProbe::program_info(&self) -> core::result::Result +impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::drop(&mut self) @@ -4523,6 +4557,8 @@ impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::xdp::Xdp::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::xdp::Xdp +pub fn aya::programs::xdp::Xdp::program_info(&self) -> core::result::Result +impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::drop(&mut self) @@ -5531,6 +5567,8 @@ impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tp_btf::BtfTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tp_btf::BtfTracePoint +pub fn aya::programs::tp_btf::BtfTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::drop(&mut self) @@ -5577,6 +5615,8 @@ impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_device::CgroupDevice::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_device::CgroupDevice +pub fn aya::programs::cgroup_device::CgroupDevice::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::drop(&mut self) @@ -5623,6 +5663,8 @@ impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_skb::CgroupSkb +pub fn aya::programs::cgroup_skb::CgroupSkb::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::drop(&mut self) @@ -5668,6 +5710,8 @@ impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock::CgroupSock +pub fn aya::programs::cgroup_sock::CgroupSock::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::drop(&mut self) @@ -5713,6 +5757,8 @@ impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sock_addr::CgroupSockAddr +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::drop(&mut self) @@ -5758,6 +5804,8 @@ impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sockopt::CgroupSockopt +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::drop(&mut self) @@ -5804,6 +5852,8 @@ impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::cgroup_sysctl::CgroupSysctl +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::program_info(&self) -> core::result::Result +impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::drop(&mut self) @@ -5851,6 +5901,8 @@ impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::extension::Extension::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::extension::Extension +pub fn aya::programs::extension::Extension::program_info(&self) -> core::result::Result +impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::extension::Extension pub fn aya::programs::extension::Extension::drop(&mut self) @@ -5897,6 +5949,8 @@ impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fentry::FEntry::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fentry::FEntry +pub fn aya::programs::fentry::FEntry::program_info(&self) -> core::result::Result +impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::drop(&mut self) @@ -5943,6 +5997,8 @@ impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::fexit::FExit::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::fexit::FExit +pub fn aya::programs::fexit::FExit::program_info(&self) -> core::result::Result +impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::drop(&mut self) @@ -5989,6 +6045,8 @@ impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::kprobe::KProbe +pub fn aya::programs::kprobe::KProbe::program_info(&self) -> core::result::Result +impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::drop(&mut self) @@ -6036,6 +6094,8 @@ impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lirc_mode2::LircMode2::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lirc_mode2::LircMode2 +pub fn aya::programs::lirc_mode2::LircMode2::program_info(&self) -> core::result::Result +impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::drop(&mut self) @@ -6082,6 +6142,8 @@ impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::lsm::Lsm::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::lsm::Lsm +pub fn aya::programs::lsm::Lsm::program_info(&self) -> core::result::Result +impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::drop(&mut self) @@ -6128,6 +6190,8 @@ impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::perf_event::PerfEvent::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::perf_event::PerfEvent +pub fn aya::programs::perf_event::PerfEvent::program_info(&self) -> core::result::Result +impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::drop(&mut self) @@ -6193,11 +6257,21 @@ impl core::convert::From for aya::programs::ProgramFd pub fn aya::programs::ProgramFd::from(t: T) -> T pub struct aya::programs::ProgramInfo(_) impl aya::programs::ProgramInfo -pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result +pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option +pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::from_pin>(path: P) -> core::result::Result +pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> bool pub fn aya::programs::ProgramInfo::id(&self) -> u32 +pub fn aya::programs::ProgramInfo::loaded_at(&self) -> std::time::SystemTime +pub fn aya::programs::ProgramInfo::map_ids(&self) -> core::result::Result, aya::programs::ProgramError> +pub fn aya::programs::ProgramInfo::memory_locked(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::name(&self) -> &[u8] pub fn aya::programs::ProgramInfo::name_as_str(&self) -> core::option::Option<&str> +pub fn aya::programs::ProgramInfo::program_type(&self) -> u32 +pub fn aya::programs::ProgramInfo::size_jitted(&self) -> u32 +pub fn aya::programs::ProgramInfo::size_translated(&self) -> u32 +pub fn aya::programs::ProgramInfo::tag(&self) -> u64 +pub fn aya::programs::ProgramInfo::verified_instruction_count(&self) -> u32 impl core::fmt::Debug for aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::programs::ProgramInfo @@ -6235,6 +6309,8 @@ impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::RawTracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::RawTracePoint +pub fn aya::programs::RawTracePoint::program_info(&self) -> core::result::Result +impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::drop(&mut self) @@ -6281,6 +6357,8 @@ impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::tc::SchedClassifier +pub fn aya::programs::tc::SchedClassifier::program_info(&self) -> core::result::Result +impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::drop(&mut self) @@ -6327,6 +6405,8 @@ impl aya::programs::SkLookup pub fn aya::programs::SkLookup::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkLookup::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkLookup +pub fn aya::programs::SkLookup::program_info(&self) -> core::result::Result +impl aya::programs::SkLookup pub fn aya::programs::SkLookup::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkLookup pub fn aya::programs::SkLookup::drop(&mut self) @@ -6373,6 +6453,8 @@ impl aya::programs::SkMsg pub fn aya::programs::SkMsg::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkMsg::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkMsg +pub fn aya::programs::SkMsg::program_info(&self) -> core::result::Result +impl aya::programs::SkMsg pub fn aya::programs::SkMsg::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkMsg pub fn aya::programs::SkMsg::drop(&mut self) @@ -6418,6 +6500,8 @@ impl aya::programs::SkSkb pub fn aya::programs::SkSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SkSkb +pub fn aya::programs::SkSkb::program_info(&self) -> core::result::Result +impl aya::programs::SkSkb pub fn aya::programs::SkSkb::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SkSkb pub fn aya::programs::SkSkb::drop(&mut self) @@ -6464,6 +6548,8 @@ impl aya::programs::SockOps pub fn aya::programs::SockOps::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SockOps::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SockOps +pub fn aya::programs::SockOps::program_info(&self) -> core::result::Result +impl aya::programs::SockOps pub fn aya::programs::SockOps::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SockOps pub fn aya::programs::SockOps::drop(&mut self) @@ -6510,6 +6596,8 @@ impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SocketFilter::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::SocketFilter +pub fn aya::programs::SocketFilter::program_info(&self) -> core::result::Result +impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::SocketFilter pub fn aya::programs::SocketFilter::drop(&mut self) @@ -6556,6 +6644,8 @@ impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::trace_point::TracePoint::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::trace_point::TracePoint +pub fn aya::programs::trace_point::TracePoint::program_info(&self) -> core::result::Result +impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::drop(&mut self) @@ -6602,6 +6692,8 @@ impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::uprobe::UProbe +pub fn aya::programs::uprobe::UProbe::program_info(&self) -> core::result::Result +impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::drop(&mut self) @@ -6650,6 +6742,8 @@ impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::xdp::Xdp::unpin(self) -> core::result::Result<(), std::io::error::Error> impl aya::programs::xdp::Xdp +pub fn aya::programs::xdp::Xdp::program_info(&self) -> core::result::Result +impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::unload(&mut self) -> core::result::Result<(), aya::programs::ProgramError> impl core::ops::drop::Drop for aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::drop(&mut self) From 47a8a4b8783ec9f9cd4e90e6289eca5ca934c6f8 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 14 Aug 2023 10:36:37 -0400 Subject: [PATCH 30/42] github: reduce wget verbosity, remove -q This allows errors to be shown; -q hides *all* output, which is not what we want. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ff70200..f886c2a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,7 +212,7 @@ jobs: printf '%s\0' \ linux-image-6.1.0-10-cloud-arm64-unsigned_6.1.38-2_arm64.deb \ linux-image-6.4.0-1-cloud-arm64-unsigned_6.4.4-2_arm64.deb \ - | xargs -0 -t -P0 -I {} wget -nd -q -P test/.tmp/debian-kernels/arm64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/arm64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} - name: Download debian kernels if: runner.arch == 'X64' @@ -225,7 +225,7 @@ jobs: printf '%s\0' \ linux-image-6.1.0-10-cloud-amd64-unsigned_6.1.38-2_amd64.deb \ linux-image-6.4.0-1-cloud-amd64-unsigned_6.4.4-2_amd64.deb \ - | xargs -0 -t -P0 -I {} wget -nd -q -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} + | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} - name: Alias gtar as tar if: runner.os == 'macOS' From 89eafd139d06c91cb137e36d8c13c3be13e6b936 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 14 Aug 2023 11:00:16 -0400 Subject: [PATCH 31/42] github: use gxargs on macOS `xargs -P0` always exits 0 on macOS, even on error. --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f886c2a9..c408ee93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,7 +193,7 @@ jobs: # We also need LLVM for bpf-linker, see comment below. run: | set -euxo pipefail - brew install qemu dpkg pkg-config llvm + brew install findutils qemu dpkg pkg-config llvm echo /usr/local/opt/llvm/bin >> $GITHUB_PATH - name: bpf-linker @@ -201,6 +201,11 @@ jobs: # NB: rustc doesn't ship libLLVM.so on macOS, so disable proxying (default feature). run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git --no-default-features + - name: Alias gxargs as xargs + if: runner.os == 'macOS' + # macOS xargs always exits 0 with -P0. + run: mkdir xargs-is-gxargs && ln -s "$(which gxargs)" xargs-is-gxargs/xargs && echo "$PWD"/xargs-is-gxargs >> $GITHUB_PATH + - name: Download debian kernels if: runner.arch == 'ARM64' run: | From 6740c43a0282a22b59c021953a45dab47547ab7e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 14 Aug 2023 10:37:10 -0400 Subject: [PATCH 32/42] github: update 6.4.0 URLs Seems the previous spin was pulled. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c408ee93..a078ee35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,7 +216,7 @@ jobs: # linux-image-5.10.0-23-cloud-arm64-unsigned_5.10.179-3_arm64.deb \ printf '%s\0' \ linux-image-6.1.0-10-cloud-arm64-unsigned_6.1.38-2_arm64.deb \ - linux-image-6.4.0-1-cloud-arm64-unsigned_6.4.4-2_arm64.deb \ + linux-image-6.4.0-2-cloud-arm64-unsigned_6.4.4-3_arm64.deb \ | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/arm64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} - name: Download debian kernels @@ -229,7 +229,7 @@ jobs: # linux-image-5.10.0-23-cloud-amd64-unsigned_5.10.179-3_amd64.deb \ printf '%s\0' \ linux-image-6.1.0-10-cloud-amd64-unsigned_6.1.38-2_amd64.deb \ - linux-image-6.4.0-1-cloud-amd64-unsigned_6.4.4-2_amd64.deb \ + linux-image-6.4.0-2-cloud-amd64-unsigned_6.4.4-3_amd64.deb \ | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} - name: Alias gtar as tar From 504fd1df0a29a02f5a19185e302c3e305a1045c7 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 10 Aug 2023 14:37:08 -0400 Subject: [PATCH 33/42] programs: `ProgramFd` is owned `ProgramData::fd` is now a `ProgramFd`. This means that `ProgramData` now closes the file descriptor on drop. In the future we might consider making `ProgramFd` hold a `BorrowedFd` but this requires API design work due to overlapping borrows. Since `ProgramFd` is no longer `Copy`, update methods to take it by reference to allow callers to use it multiple times as they are accustomed to doing. `ProgramFd` is now returned by reference and implements `try_clone` to allow callers to avoid file descriptor cloning when desired. This is an API breaking change. Updates #612. --- aya/src/maps/array/program_array.rs | 13 ++- aya/src/maps/perf/async_perf_event_array.rs | 2 +- aya/src/programs/cgroup_device.rs | 6 +- aya/src/programs/cgroup_skb.rs | 10 +- aya/src/programs/cgroup_sock.rs | 10 +- aya/src/programs/cgroup_sock_addr.rs | 10 +- aya/src/programs/cgroup_sockopt.rs | 10 +- aya/src/programs/cgroup_sysctl.rs | 9 +- aya/src/programs/extension.rs | 41 ++++--- aya/src/programs/lirc_mode2.rs | 10 +- aya/src/programs/mod.rs | 78 +++++++------ aya/src/programs/perf_event.rs | 7 +- aya/src/programs/probe.rs | 24 ++-- aya/src/programs/sk_lookup.rs | 6 +- aya/src/programs/sk_msg.rs | 6 +- aya/src/programs/sk_skb.rs | 9 +- aya/src/programs/sock_ops.rs | 6 +- aya/src/programs/socket_filter.rs | 6 +- aya/src/programs/tc.rs | 5 +- aya/src/programs/trace_point.rs | 11 +- aya/src/programs/utils.rs | 7 +- aya/src/programs/xdp.rs | 10 +- aya/src/sys/bpf.rs | 10 +- xtask/public-api/aya.txt | 115 ++++++++++---------- 24 files changed, 251 insertions(+), 170 deletions(-) diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index b7ec75cf..7a708527 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -2,7 +2,7 @@ use std::{ borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, RawFd}, }; use crate::{ @@ -37,13 +37,13 @@ use crate::{ /// let flags = 0; /// /// // bpf_tail_call(ctx, JUMP_TABLE, 0) will jump to prog_0 -/// prog_array.set(0, prog_0_fd, flags); +/// prog_array.set(0, &prog_0_fd, flags); /// /// // bpf_tail_call(ctx, JUMP_TABLE, 1) will jump to prog_1 -/// prog_array.set(1, prog_1_fd, flags); +/// prog_array.set(1, &prog_1_fd, flags); /// /// // bpf_tail_call(ctx, JUMP_TABLE, 2) will jump to prog_2 -/// prog_array.set(2, prog_2_fd, flags); +/// prog_array.set(2, &prog_2_fd, flags); /// # Ok::<(), aya::BpfError>(()) /// ``` #[doc(alias = "BPF_MAP_TYPE_PROG_ARRAY")] @@ -73,11 +73,12 @@ impl> ProgramArray { /// /// When an eBPF program calls `bpf_tail_call(ctx, prog_array, index)`, control /// flow will jump to `program`. - pub fn set(&mut self, index: u32, program: ProgramFd, flags: u64) -> Result<(), MapError> { + pub fn set(&mut self, index: u32, program: &ProgramFd, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; let fd = data.fd_or_err()?; - let prog_fd = program.as_raw_fd(); + let prog_fd = program.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); bpf_map_update_elem(fd, Some(&index), &prog_fd, flags).map_err(|(_, io_error)| { SyscallError { diff --git a/aya/src/maps/perf/async_perf_event_array.rs b/aya/src/maps/perf/async_perf_event_array.rs index 4de4dd86..447df95d 100644 --- a/aya/src/maps/perf/async_perf_event_array.rs +++ b/aya/src/maps/perf/async_perf_event_array.rs @@ -1,7 +1,7 @@ use bytes::BytesMut; use std::{ borrow::{Borrow, BorrowMut}, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsRawFd as _, RawFd}, }; // See https://doc.rust-lang.org/cargo/reference/features.html#mutually-exclusive-features. diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index dc318086..1244d27c 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -1,7 +1,7 @@ //! Cgroup device programs. use crate::util::KernelVersion; -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE}, @@ -61,7 +61,9 @@ impl CgroupDevice { /// /// The returned value can be used to detach, see [CgroupDevice::detach] pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index d0cda14a..684fd18e 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -1,7 +1,11 @@ //! Cgroup skb programs. use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::{ @@ -88,7 +92,9 @@ impl CgroupSkb { cgroup: T, attach_type: CgroupSkbAttachType, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = match attach_type { diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index a7a70e13..c906ee6c 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK, @@ -67,7 +71,9 @@ impl CgroupSock { /// /// The returned value can be used to detach, see [CgroupSock::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 827cbe57..98d60eb1 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockAddrAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR, @@ -68,7 +72,9 @@ impl CgroupSockAddr { /// /// The returned value can be used to detach, see [CgroupSockAddr::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index e2ae3b64..c137d769 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -3,7 +3,11 @@ pub use aya_obj::programs::CgroupSockoptAttachType; use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd, path::Path}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, + path::Path, +}; use crate::{ generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, @@ -65,7 +69,9 @@ impl CgroupSockopt { /// /// The returned value can be used to detach, see [CgroupSockopt::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); let attach_type = self.data.expected_attach_type.unwrap(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index 8e887657..d5325089 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -1,7 +1,10 @@ //! Cgroup sysctl programs. use crate::util::KernelVersion; -use std::{hash::Hash, os::fd::AsRawFd}; +use std::{ + hash::Hash, + os::fd::{AsFd as _, AsRawFd}, +}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL}, @@ -60,7 +63,9 @@ impl CgroupSysctl { /// /// The returned value can be used to detach, see [CgroupSysctl::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) { diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index 85e9c3c1..fd955ddc 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -1,5 +1,5 @@ //! Extension programs. -use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd}; +use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd}; use thiserror::Error; use object::Endianness; @@ -42,8 +42,9 @@ pub enum ExtensionError { /// prog.attach("eth0", XdpFlags::default())?; /// /// let prog_fd = prog.fd().unwrap(); +/// let prog_fd = prog_fd.try_clone().unwrap(); /// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?; -/// ext.load(prog_fd, "function_to_replace")?; +/// ext.load(&prog_fd, "function_to_replace")?; /// ext.attach()?; /// Ok::<(), aya::BpfError>(()) /// ``` @@ -68,12 +69,12 @@ impl Extension { /// The extension code will be loaded but inactive until it's attached. /// There are no restrictions on what functions may be replaced, so you could replace /// the main entry point of your program with an extension. - pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> { - let target_prog_fd = program.as_raw_fd(); + pub fn load(&mut self, program: &ProgramFd, func_name: &str) -> Result<(), ProgramError> { + let target_prog_fd = program.as_fd(); let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?; self.data.attach_btf_obj_fd = Some(btf_fd); - self.data.attach_prog_fd = Some(target_prog_fd); + self.data.attach_prog_fd = Some(target_prog_fd.as_raw_fd()); self.data.attach_btf_id = Some(btf_id); load_program(BPF_PROG_TYPE_EXT, &mut self.data) } @@ -86,7 +87,9 @@ impl Extension { /// The returned value can be used to detach the extension and restore the /// original function, see [Extension::detach]. pub fn attach(&mut self) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let target_fd = self.data.attach_prog_fd.ok_or(ProgramError::NotLoaded)?; let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?; // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS @@ -113,18 +116,26 @@ impl Extension { /// original function, see [Extension::detach]. pub fn attach_to_program( &mut self, - program: ProgramFd, + program: &ProgramFd, func_name: &str, ) -> Result { - let target_fd = program.as_raw_fd(); + let target_fd = program.as_fd(); let (_, btf_id) = get_btf_info(target_fd, func_name)?; - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS - let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) - .map_err(|(_, io_error)| SyscallError { - call: "bpf_link_create", - io_error, - })?; + let link_fd = bpf_link_create( + prog_fd, + target_fd.as_raw_fd(), + BPF_CGROUP_INET_INGRESS, + Some(btf_id), + 0, + ) + .map_err(|(_, io_error)| SyscallError { + call: "bpf_link_create", + io_error, + })?; self.data .links .insert(ExtensionLink::new(FdLink::new(link_fd))) @@ -149,7 +160,7 @@ impl Extension { /// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function /// with the name `func_name` within that BTF object. -fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> { +fn get_btf_info(prog_fd: BorrowedFd<'_>, func_name: &str) -> Result<(OwnedFd, u32), ProgramError> { // retrieve program information let info = sys::bpf_prog_get_info_by_fd(prog_fd, &mut [])?; diff --git a/aya/src/programs/lirc_mode2.rs b/aya/src/programs/lirc_mode2.rs index 88d5c6c0..906eec96 100644 --- a/aya/src/programs/lirc_mode2.rs +++ b/aya/src/programs/lirc_mode2.rs @@ -1,5 +1,5 @@ //! Lirc programs. -use std::os::fd::{AsRawFd, IntoRawFd as _, RawFd}; +use std::os::fd::{AsFd as _, AsRawFd, BorrowedFd, IntoRawFd as _, RawFd}; use crate::{ generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2}, @@ -61,7 +61,9 @@ impl LircMode2 { /// /// The returned value can be used to detach, see [LircMode2::detach]. pub fn attach(&mut self, lircdev: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let lircdev_fd = lircdev.as_raw_fd(); bpf_prog_attach(prog_fd, lircdev_fd, BPF_LIRC_MODE2).map_err(|(_, io_error)| { @@ -128,7 +130,9 @@ impl LircLink { /// Get ProgramInfo from this link pub fn info(&self) -> Result { - ProgramInfo::new_from_fd(self.prog_fd) + // SAFETY: TODO(https://github.com/aya-rs/aya/issues/612): make this safe by not holding `RawFd`s. + let prog_fd = unsafe { BorrowedFd::borrow_raw(self.prog_fd) }; + ProgramInfo::new_from_fd(prog_fd) } } diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 42bec325..51164f89 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -69,7 +69,7 @@ use std::{ ffi::CString, io, num::NonZeroU32, - os::fd::{AsFd, AsRawFd, IntoRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}, path::{Path, PathBuf}, sync::Arc, time::{Duration, SystemTime}, @@ -214,12 +214,23 @@ pub enum ProgramError { } /// A [`Program`] file descriptor. -#[derive(Copy, Clone)] -pub struct ProgramFd(RawFd); +#[derive(Debug)] +pub struct ProgramFd(OwnedFd); + +impl ProgramFd { + /// Creates a new `ProgramFd` instance that shares the same underlying file + /// description as the existing `ProgramFd` instance. + pub fn try_clone(&self) -> Result { + let Self(inner) = self; + let inner = inner.try_clone()?; + Ok(Self(inner)) + } +} -impl AsRawFd for ProgramFd { - fn as_raw_fd(&self) -> RawFd { - self.0 +impl AsFd for ProgramFd { + fn as_fd(&self) -> BorrowedFd<'_> { + let Self(fd) = self; + fd.as_fd() } } @@ -372,7 +383,7 @@ impl Program { /// /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program. /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> Option { + pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { match self { Program::KProbe(p) => p.fd(), Program::UProbe(p) => p.fd(), @@ -406,7 +417,7 @@ impl Program { pub(crate) struct ProgramData { pub(crate) name: Option, pub(crate) obj: Option<(obj::Program, obj::Function)>, - pub(crate) fd: Option, + pub(crate) fd: Option, pub(crate) links: LinkMap, pub(crate) expected_attach_type: Option, pub(crate) attach_btf_obj_fd: Option, @@ -460,7 +471,7 @@ impl ProgramData { Ok(ProgramData { name, obj: None, - fd: Some(fd.into_raw_fd()), + fd: Some(ProgramFd(fd)), links: LinkMap::new(), expected_attach_type: None, attach_btf_obj_fd, @@ -485,15 +496,15 @@ impl ProgramData { io_error, })?; - let info = ProgramInfo::new_from_fd(fd.as_raw_fd())?; + let info = ProgramInfo::new_from_fd(fd.as_fd())?; let name = info.name_as_str().map(|s| s.to_string()); ProgramData::from_bpf_prog_info(name, fd, path.as_ref(), info.0, verifier_log_level) } } impl ProgramData { - fn fd_or_err(&self) -> Result { - self.fd.ok_or(ProgramError::NotLoaded) + fn fd(&self) -> Result<&ProgramFd, ProgramError> { + self.fd.as_ref().ok_or(ProgramError::NotLoaded) } pub(crate) fn take_link(&mut self, link_id: T::Id) -> Result { @@ -503,15 +514,14 @@ impl ProgramData { fn unload_program(data: &mut ProgramData) -> Result<(), ProgramError> { data.links.remove_all()?; - let fd = data.fd.take().ok_or(ProgramError::NotLoaded)?; - unsafe { - libc::close(fd); - } - Ok(()) + data.fd + .take() + .ok_or(ProgramError::NotLoaded) + .map(|ProgramFd { .. }| ()) } fn pin_program>(data: &ProgramData, path: P) -> Result<(), PinError> { - let fd = data.fd.ok_or(PinError::NoFd { + let fd = data.fd.as_ref().ok_or(PinError::NoFd { name: data .name .as_deref() @@ -523,7 +533,7 @@ fn pin_program>(data: &ProgramData, path: P) -> Resul error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + bpf_pin_object(fd.as_fd().as_raw_fd(), &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; @@ -617,7 +627,7 @@ fn load_program( match ret { Ok(prog_fd) => { - *fd = Some(prog_fd as RawFd); + *fd = Some(ProgramFd(prog_fd)); Ok(()) } Err((_, io_error)) => Err(ProgramError::LoadError { @@ -722,8 +732,8 @@ macro_rules! impl_fd { $( impl $struct_name { /// Returns the file descriptor of this Program. - pub fn fd(&self) -> Option { - self.data.fd.map(|fd| ProgramFd(fd)) + pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { + self.data.fd() } } )+ @@ -916,9 +926,9 @@ macro_rules! impl_program_info { impl $struct_name { /// Returns the file descriptor of this Program. pub fn program_info(&self) -> Result { - let fd = self.data.fd_or_err()?; + let ProgramFd(fd) = self.fd()?; - ProgramInfo::new_from_fd(fd.as_raw_fd()) + ProgramInfo::new_from_fd(fd.as_fd()) } } )+ @@ -957,11 +967,9 @@ impl_program_info!( pub struct ProgramInfo(bpf_prog_info); impl ProgramInfo { - fn new_from_fd(fd: RawFd) -> Result { - Ok(ProgramInfo(bpf_prog_get_info_by_fd( - fd.as_raw_fd(), - &mut [], - )?)) + fn new_from_fd(fd: BorrowedFd<'_>) -> Result { + let info = bpf_prog_get_info_by_fd(fd, &mut [])?; + Ok(Self(info)) } /// The name of the program as was provided when it was load. This is limited to 16 bytes @@ -1011,10 +1019,10 @@ impl ProgramInfo { /// The ids of the maps used by the program. pub fn map_ids(&self) -> Result, ProgramError> { - let fd = self.fd()?; + let ProgramFd(fd) = self.fd()?; let mut map_ids = vec![0u32; self.0.nr_map_ids as usize]; - bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut map_ids)?; + bpf_prog_get_info_by_fd(fd.as_fd(), &mut map_ids)?; Ok(map_ids) } @@ -1058,10 +1066,10 @@ impl ProgramInfo { /// /// The returned file descriptor can be closed at any time and doing so does /// not influence the life cycle of the program. - pub fn fd(&self) -> Result { + pub fn fd(&self) -> Result { let Self(info) = self; let fd = bpf_prog_get_fd_by_id(info.id)?; - Ok(fd) + Ok(ProgramFd(fd)) } /// Loads a program from a pinned path in bpffs. @@ -1072,7 +1080,7 @@ impl ProgramInfo { io_error, })?; - let info = bpf_prog_get_info_by_fd(fd.as_raw_fd(), &mut [])?; + let info = bpf_prog_get_info_by_fd(fd.as_fd(), &mut [])?; Ok(ProgramInfo(info)) } } @@ -1108,7 +1116,7 @@ pub fn loaded_programs() -> impl Iterator Result { + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let (sample_period, sample_frequency) = match sample_policy { SamplePolicy::Period(period) => (period, None), SamplePolicy::Frequency(frequency) => (0, Some(frequency)), @@ -172,7 +175,7 @@ impl PerfEvent { io_error, })?; - let link = perf_attach(self.data.fd_or_err()?, fd)?; + let link = perf_attach(prog_fd, fd)?; self.data.links.insert(PerfEventLink::new(link)) } diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index fa04d31d..151c87ef 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -3,7 +3,7 @@ use libc::pid_t; use std::{ fs::{self, OpenOptions}, io::{self, Write}, - os::fd::OwnedFd, + os::fd::{AsFd as _, AsRawFd as _, OwnedFd}, path::Path, process, sync::atomic::{AtomicUsize, Ordering}, @@ -57,19 +57,17 @@ pub(crate) fn attach>( ) -> Result { // https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155 // Use debugfs to create probe - if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { + let prog_fd = program_data.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); + let link = if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; - let link = T::from(perf_attach_debugfs( - program_data.fd_or_err()?, - fd, - ProbeEvent { kind, event_alias }, - )?); - return program_data.links.insert(link); - }; - - let fd = create_as_probe(kind, fn_name, offset, pid)?; - let link = T::from(perf_attach(program_data.fd_or_err()?, fd)?); - program_data.links.insert(link) + perf_attach_debugfs(prog_fd, fd, ProbeEvent { kind, event_alias }) + } else { + let fd = create_as_probe(kind, fn_name, offset, pid)?; + perf_attach(prog_fd, fd) + }?; + program_data.links.insert(T::from(link)) } pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> { diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index 15687e43..bbcdc3a3 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -1,4 +1,4 @@ -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_SK_LOOKUP, bpf_prog_type::BPF_PROG_TYPE_SK_LOOKUP}, @@ -61,7 +61,9 @@ impl SkLookup { /// /// The returned value can be used to detach, see [SkLookup::detach]. pub fn attach(&mut self, netns: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let netns_fd = netns.as_raw_fd(); let link_fd = bpf_link_create(prog_fd, netns_fd, BPF_SK_LOOKUP, None, 0).map_err( diff --git a/aya/src/programs/sk_msg.rs b/aya/src/programs/sk_msg.rs index 93819fbe..7a03b8e3 100644 --- a/aya/src/programs/sk_msg.rs +++ b/aya/src/programs/sk_msg.rs @@ -1,6 +1,6 @@ //! Skmsg programs. -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd as _}; use crate::{ generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG}, @@ -79,7 +79,9 @@ impl SkMsg { /// /// The returned value can be used to detach, see [SkMsg::detach]. pub fn attach(&mut self, map: SockMapFd) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); bpf_prog_attach(prog_fd, map_fd, BPF_SK_MSG_VERDICT).map_err(|(_, io_error)| { diff --git a/aya/src/programs/sk_skb.rs b/aya/src/programs/sk_skb.rs index 70960265..a4c5de63 100644 --- a/aya/src/programs/sk_skb.rs +++ b/aya/src/programs/sk_skb.rs @@ -1,6 +1,9 @@ //! Skskb programs. -use std::{os::fd::AsRawFd, path::Path}; +use std::{ + os::fd::{AsFd as _, AsRawFd as _}, + path::Path, +}; use crate::{ generated::{ @@ -72,7 +75,9 @@ impl SkSkb { /// /// The returned value can be used to detach, see [SkSkb::detach]. pub fn attach(&mut self, map: SockMapFd) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let map_fd = map.as_raw_fd(); let attach_type = match self.kind { diff --git a/aya/src/programs/sock_ops.rs b/aya/src/programs/sock_ops.rs index 16e71677..2a469048 100644 --- a/aya/src/programs/sock_ops.rs +++ b/aya/src/programs/sock_ops.rs @@ -1,5 +1,5 @@ //! Socket option programs. -use std::os::fd::AsRawFd; +use std::os::fd::{AsFd as _, AsRawFd}; use crate::{ generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS}, @@ -59,7 +59,9 @@ impl SockOps { /// /// The returned value can be used to detach, see [SockOps::detach]. pub fn attach(&mut self, cgroup: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let cgroup_fd = cgroup.as_raw_fd(); bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS).map_err(|(_, io_error)| { diff --git a/aya/src/programs/socket_filter.rs b/aya/src/programs/socket_filter.rs index 5ff9a301..e737d8ae 100644 --- a/aya/src/programs/socket_filter.rs +++ b/aya/src/programs/socket_filter.rs @@ -2,7 +2,7 @@ use libc::{setsockopt, SOL_SOCKET}; use std::{ io, mem, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsFd as _, AsRawFd, RawFd}, }; use thiserror::Error; @@ -73,7 +73,9 @@ impl SocketFilter { /// /// The returned value can be used to detach from the socket, see [SocketFilter::detach]. pub fn attach(&mut self, socket: T) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let socket = socket.as_raw_fd(); let ret = unsafe { diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs index fad633a3..e289e7d0 100644 --- a/aya/src/programs/tc.rs +++ b/aya/src/programs/tc.rs @@ -4,6 +4,7 @@ use thiserror::Error; use std::{ ffi::{CStr, CString}, io, + os::fd::{AsFd as _, AsRawFd as _}, path::Path, }; @@ -152,7 +153,9 @@ impl SchedClassifier { attach_type: TcAttachType, options: TcOptions, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let if_index = ifindex_from_ifname(interface) .map_err(|io_error| TcError::NetlinkError { io_error })?; let (priority, handle) = unsafe { diff --git a/aya/src/programs/trace_point.rs b/aya/src/programs/trace_point.rs index 4e7b75b3..4c5d38db 100644 --- a/aya/src/programs/trace_point.rs +++ b/aya/src/programs/trace_point.rs @@ -1,5 +1,9 @@ //! Tracepoint programs. -use std::{fs, io, os::fd::AsFd as _, path::Path}; +use std::{ + fs, io, + os::fd::{AsFd as _, AsRawFd as _}, + path::Path, +}; use thiserror::Error; use crate::{ @@ -78,6 +82,9 @@ impl TracePoint { /// /// The returned value can be used to detach, see [TracePoint::detach]. pub fn attach(&mut self, category: &str, name: &str) -> Result { + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let tracefs = find_tracefs_path()?; let id = read_sys_fs_trace_point_id(tracefs, category, name)?; let fd = @@ -86,7 +93,7 @@ impl TracePoint { io_error, })?; - let link = perf_attach(self.data.fd_or_err()?, fd)?; + let link = perf_attach(prog_fd, fd)?; self.data.links.insert(TracePointLink::new(link)) } diff --git a/aya/src/programs/utils.rs b/aya/src/programs/utils.rs index 5913e8eb..beb9b5f5 100644 --- a/aya/src/programs/utils.rs +++ b/aya/src/programs/utils.rs @@ -3,7 +3,7 @@ use std::{ ffi::CStr, fs::File, io::{self, BufRead, BufReader}, - os::fd::{AsRawFd as _, BorrowedFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd}, path::Path, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -18,8 +18,9 @@ pub(crate) fn attach_raw_tracepoint>( program_data: &mut ProgramData, tp_name: Option<&CStr>, ) -> Result { - let prog_fd = program_data.fd_or_err()?; - + let prog_fd = program_data.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let pfd = bpf_raw_tracepoint_open(tp_name, prog_fd).map_err(|(_code, io_error)| SyscallError { call: "bpf_raw_tracepoint_open", diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 35164e72..36eec7d6 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -8,7 +8,7 @@ use std::{ ffi::CString, hash::Hash, io, - os::fd::{AsFd as _, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, RawFd}, }; use thiserror::Error; @@ -128,7 +128,9 @@ impl Xdp { if_index: u32, flags: XdpFlags, ) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); let if_index = if_index as RawFd; if KernelVersion::current().unwrap() >= KernelVersion::new(5, 9, 0) { @@ -174,7 +176,9 @@ impl Xdp { /// /// Ownership of the link will transfer to this program. pub fn attach_to_link(&mut self, link: XdpLink) -> Result { - let prog_fd = self.data.fd_or_err()?; + let prog_fd = self.fd()?; + let prog_fd = prog_fd.as_fd(); + let prog_fd = prog_fd.as_raw_fd(); match link.into_inner() { XdpLinkInner::FdLink(fd_link) => { let link_fd = fd_link.fd; diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index b667983e..9b9fab5b 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -3,7 +3,7 @@ use std::{ ffi::{CStr, CString}, io, iter, mem::{self, MaybeUninit}, - os::fd::{AsRawFd, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, + os::fd::{AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, }; @@ -132,7 +132,7 @@ pub(crate) fn bpf_load_program( aya_attr: &BpfLoadProgramAttrs, log_buf: &mut [u8], verifier_log_level: VerifierLogLevel, -) -> SysResult { +) -> SysResult { let mut attr = unsafe { mem::zeroed::() }; let u = unsafe { &mut attr.__bindgen_anon_3 }; @@ -190,7 +190,8 @@ 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, &mut attr) + // SAFETY: BPF_PROG_LOAD returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) } } fn lookup( @@ -506,10 +507,9 @@ fn bpf_obj_get_info_by_fd( } pub(crate) fn bpf_prog_get_info_by_fd( - fd: RawFd, + fd: BorrowedFd<'_>, map_ids: &mut [u32], ) -> Result { - let fd = unsafe { BorrowedFd::borrow_raw(fd) }; bpf_obj_get_info_by_fd(fd, |info: &mut bpf_prog_info| { info.nr_map_ids = map_ids.len() as _; info.map_ids = map_ids.as_mut_ptr() as _; diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index bc432d0b..41a016aa 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -91,7 +91,7 @@ impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::ProgramArray pub type aya::maps::ProgramArray::Error = aya::maps::MapError pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -1502,7 +1502,7 @@ impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::indices(&self) -> aya::maps::MapKeys<'_, u32> impl> aya::maps::ProgramArray pub fn aya::maps::ProgramArray::clear_index(&mut self, index: &u32) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> +pub fn aya::maps::ProgramArray::set(&mut self, index: u32, program: &aya::programs::ProgramFd, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl core::convert::TryFrom for aya::maps::ProgramArray pub type aya::maps::ProgramArray::Error = aya::maps::MapError pub fn aya::maps::ProgramArray::try_from(map: aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -1804,7 +1804,7 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice @@ -1949,7 +1949,7 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -2059,7 +2059,7 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -2169,7 +2169,7 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -2279,7 +2279,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -2387,7 +2387,7 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl @@ -2527,12 +2527,12 @@ pub fn aya::programs::extension::ExtensionError::from(t: T) -> T pub struct aya::programs::extension::Extension impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result -pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result +pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension -pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option +pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::from_pin>(path: P) -> core::result::Result impl aya::programs::extension::Extension @@ -2646,7 +2646,7 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs:: pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result impl aya::programs::fentry::FEntry -pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option +pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::from_pin>(path: P) -> core::result::Result impl aya::programs::fentry::FEntry @@ -2760,7 +2760,7 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result impl aya::programs::fexit::FExit -pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option +pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::from_pin>(path: P) -> core::result::Result impl aya::programs::fexit::FExit @@ -2913,7 +2913,7 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option +pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -3413,7 +3413,7 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option +pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::from_pin>(path: P) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 @@ -3462,7 +3462,7 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result impl aya::programs::lsm::Lsm -pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option +pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::from_pin>(path: P) -> core::result::Result impl aya::programs::lsm::Lsm @@ -3749,7 +3749,7 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result impl aya::programs::perf_event::PerfEvent -pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option +pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from_pin>(path: P) -> core::result::Result impl aya::programs::perf_event::PerfEvent @@ -3945,7 +3945,7 @@ pub fn aya::programs::tc::SchedClassifier::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result impl aya::programs::tc::SchedClassifier -pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -4085,7 +4085,7 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint -pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint @@ -4236,7 +4236,7 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result impl aya::programs::trace_point::TracePoint -pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::trace_point::TracePoint @@ -4398,7 +4398,7 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result impl aya::programs::uprobe::UProbe -pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option +pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -4550,7 +4550,7 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option +pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result impl aya::programs::xdp::Xdp @@ -5009,7 +5009,7 @@ pub aya::programs::Program::TracePoint(aya::programs::trace_point::TracePoint) pub aya::programs::Program::UProbe(aya::programs::uprobe::UProbe) pub aya::programs::Program::Xdp(aya::programs::xdp::Xdp) impl aya::programs::Program -pub fn aya::programs::Program::fd(&self) -> core::option::Option +pub fn aya::programs::Program::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> pub fn aya::programs::Program::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::Program::prog_type(&self) -> aya_obj::generated::linux_bindings_x86_64::bpf_prog_type pub fn aya::programs::Program::unload(self) -> core::result::Result<(), aya::programs::ProgramError> @@ -5560,7 +5560,7 @@ pub fn aya::programs::tp_btf::BtfTracePoint::detach(&mut self, link_id: aya::pro pub fn aya::programs::tp_btf::BtfTracePoint::load(&mut self, tracepoint: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tp_btf::BtfTracePoint::take_link(&mut self, link_id: aya::programs::tp_btf::BtfTracePointLinkId) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint -pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::tp_btf::BtfTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tp_btf::BtfTracePoint pub fn aya::programs::tp_btf::BtfTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::tp_btf::BtfTracePoint @@ -5608,7 +5608,7 @@ pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_device::CgroupDevice::take_link(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice -pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_device::CgroupDevice::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_device::CgroupDevice pub fn aya::programs::cgroup_device::CgroupDevice::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_device::CgroupDevice @@ -5658,7 +5658,7 @@ pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_skb::CgroupSkb::take_link(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result impl aya::programs::cgroup_skb::CgroupSkb -pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_skb::CgroupSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_skb::CgroupSkb pub fn aya::programs::cgroup_skb::CgroupSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_skb::CgroupSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -5705,7 +5705,7 @@ pub fn aya::programs::cgroup_sock::CgroupSock::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock::CgroupSock::take_link(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result impl aya::programs::cgroup_sock::CgroupSock -pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock::CgroupSock::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock::CgroupSock pub fn aya::programs::cgroup_sock::CgroupSock::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock::CgroupSock::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -5752,7 +5752,7 @@ pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::take_link(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result impl aya::programs::cgroup_sock_addr::CgroupSockAddr -pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sock_addr::CgroupSockAddr pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -5799,7 +5799,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::take_link(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result impl aya::programs::cgroup_sockopt::CgroupSockopt -pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sockopt::CgroupSockopt::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sockopt::CgroupSockopt pub fn aya::programs::cgroup_sockopt::CgroupSockopt::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::cgroup_sockopt::CgroupSockopt::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -5845,7 +5845,7 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: ay pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl -pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::option::Option +pub fn aya::programs::cgroup_sysctl::CgroupSysctl::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::cgroup_sysctl::CgroupSysctl pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from_pin>(path: P) -> core::result::Result impl aya::programs::cgroup_sysctl::CgroupSysctl @@ -5889,12 +5889,12 @@ pub fn aya::programs::cgroup_sysctl::CgroupSysctl::from(t: T) -> T pub struct aya::programs::Extension impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result -pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result +pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension -pub fn aya::programs::extension::Extension::fd(&self) -> core::option::Option +pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::from_pin>(path: P) -> core::result::Result impl aya::programs::extension::Extension @@ -5942,7 +5942,7 @@ pub fn aya::programs::fentry::FEntry::detach(&mut self, link_id: aya::programs:: pub fn aya::programs::fentry::FEntry::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fentry::FEntry::take_link(&mut self, link_id: aya::programs::fentry::FEntryLinkId) -> core::result::Result impl aya::programs::fentry::FEntry -pub fn aya::programs::fentry::FEntry::fd(&self) -> core::option::Option +pub fn aya::programs::fentry::FEntry::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fentry::FEntry pub fn aya::programs::fentry::FEntry::from_pin>(path: P) -> core::result::Result impl aya::programs::fentry::FEntry @@ -5990,7 +5990,7 @@ pub fn aya::programs::fexit::FExit::detach(&mut self, link_id: aya::programs::fe pub fn aya::programs::fexit::FExit::load(&mut self, fn_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::fexit::FExit::take_link(&mut self, link_id: aya::programs::fexit::FExitLinkId) -> core::result::Result impl aya::programs::fexit::FExit -pub fn aya::programs::fexit::FExit::fd(&self) -> core::option::Option +pub fn aya::programs::fexit::FExit::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::fexit::FExit pub fn aya::programs::fexit::FExit::from_pin>(path: P) -> core::result::Result impl aya::programs::fexit::FExit @@ -6040,7 +6040,7 @@ pub fn aya::programs::kprobe::KProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::kprobe::KProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::kprobe::KProbe::take_link(&mut self, link_id: aya::programs::kprobe::KProbeLinkId) -> core::result::Result impl aya::programs::kprobe::KProbe -pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::option::Option +pub fn aya::programs::kprobe::KProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::kprobe::KProbe pub fn aya::programs::kprobe::KProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::kprobe::KProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -6087,7 +6087,7 @@ pub fn aya::programs::lirc_mode2::LircMode2::load(&mut self) -> core::result::Re pub fn aya::programs::lirc_mode2::LircMode2::query(target_fd: T) -> core::result::Result, aya::programs::ProgramError> pub fn aya::programs::lirc_mode2::LircMode2::take_link(&mut self, link_id: aya::programs::lirc_mode2::LircLinkId) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 -pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::option::Option +pub fn aya::programs::lirc_mode2::LircMode2::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lirc_mode2::LircMode2 pub fn aya::programs::lirc_mode2::LircMode2::from_pin>(path: P) -> core::result::Result impl aya::programs::lirc_mode2::LircMode2 @@ -6135,7 +6135,7 @@ pub fn aya::programs::lsm::Lsm::detach(&mut self, link_id: aya::programs::lsm::L pub fn aya::programs::lsm::Lsm::load(&mut self, lsm_hook_name: &str, btf: &aya_obj::btf::btf::Btf) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::lsm::Lsm::take_link(&mut self, link_id: aya::programs::lsm::LsmLinkId) -> core::result::Result impl aya::programs::lsm::Lsm -pub fn aya::programs::lsm::Lsm::fd(&self) -> core::option::Option +pub fn aya::programs::lsm::Lsm::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::lsm::Lsm pub fn aya::programs::lsm::Lsm::from_pin>(path: P) -> core::result::Result impl aya::programs::lsm::Lsm @@ -6183,7 +6183,7 @@ pub fn aya::programs::perf_event::PerfEvent::detach(&mut self, link_id: aya::pro pub fn aya::programs::perf_event::PerfEvent::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::perf_event::PerfEvent::take_link(&mut self, link_id: aya::programs::perf_event::PerfEventLinkId) -> core::result::Result impl aya::programs::perf_event::PerfEvent -pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::option::Option +pub fn aya::programs::perf_event::PerfEvent::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from_pin>(path: P) -> core::result::Result impl aya::programs::perf_event::PerfEvent @@ -6225,11 +6225,12 @@ pub fn aya::programs::perf_event::PerfEvent::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::programs::perf_event::PerfEvent pub fn aya::programs::perf_event::PerfEvent::from(t: T) -> T pub struct aya::programs::ProgramFd(_) -impl std::os::fd::raw::AsRawFd for aya::programs::ProgramFd -pub fn aya::programs::ProgramFd::as_raw_fd(&self) -> std::os::fd::raw::RawFd -impl core::clone::Clone for aya::programs::ProgramFd -pub fn aya::programs::ProgramFd::clone(&self) -> aya::programs::ProgramFd -impl core::marker::Copy for aya::programs::ProgramFd +impl aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::try_clone(&self) -> core::result::Result +impl std::os::fd::owned::AsFd for aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::as_fd(&self) -> std::os::fd::owned::BorrowedFd<'_> +impl core::fmt::Debug for aya::programs::ProgramFd +pub fn aya::programs::ProgramFd::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result impl core::marker::Send for aya::programs::ProgramFd impl core::marker::Sync for aya::programs::ProgramFd impl core::marker::Unpin for aya::programs::ProgramFd @@ -6243,10 +6244,6 @@ pub fn aya::programs::ProgramFd::try_from(value: U) -> core::result::Result core::convert::TryInto for aya::programs::ProgramFd where U: core::convert::TryFrom pub type aya::programs::ProgramFd::Error = >::Error pub fn aya::programs::ProgramFd::try_into(self) -> core::result::Result>::Error> -impl alloc::borrow::ToOwned for aya::programs::ProgramFd where T: core::clone::Clone -pub type aya::programs::ProgramFd::Owned = T -pub fn aya::programs::ProgramFd::clone_into(&self, target: &mut T) -pub fn aya::programs::ProgramFd::to_owned(&self) -> T impl core::any::Any for aya::programs::ProgramFd where T: 'static + core::marker::Sized pub fn aya::programs::ProgramFd::type_id(&self) -> core::any::TypeId impl core::borrow::Borrow for aya::programs::ProgramFd where T: core::marker::Sized @@ -6258,7 +6255,7 @@ pub fn aya::programs::ProgramFd::from(t: T) -> T pub struct aya::programs::ProgramInfo(_) impl aya::programs::ProgramInfo pub fn aya::programs::ProgramInfo::btf_id(&self) -> core::option::Option -pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result +pub fn aya::programs::ProgramInfo::fd(&self) -> core::result::Result pub fn aya::programs::ProgramInfo::from_pin>(path: P) -> core::result::Result pub fn aya::programs::ProgramInfo::gpl_compatible(&self) -> bool pub fn aya::programs::ProgramInfo::id(&self) -> u32 @@ -6302,7 +6299,7 @@ pub fn aya::programs::RawTracePoint::detach(&mut self, link_id: RawTracePointLin pub fn aya::programs::RawTracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::RawTracePoint::take_link(&mut self, link_id: RawTracePointLinkId) -> core::result::Result impl aya::programs::RawTracePoint -pub fn aya::programs::RawTracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::RawTracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::RawTracePoint pub fn aya::programs::RawTracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::RawTracePoint @@ -6352,7 +6349,7 @@ pub fn aya::programs::tc::SchedClassifier::from_pin core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::tc::SchedClassifier::take_link(&mut self, link_id: aya::programs::tc::SchedClassifierLinkId) -> core::result::Result impl aya::programs::tc::SchedClassifier -pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::option::Option +pub fn aya::programs::tc::SchedClassifier::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::tc::SchedClassifier pub fn aya::programs::tc::SchedClassifier::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::tc::SchedClassifier::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -6398,7 +6395,7 @@ pub fn aya::programs::SkLookup::detach(&mut self, link_id: SkLookupLinkId) -> co pub fn aya::programs::SkLookup::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkLookup::take_link(&mut self, link_id: SkLookupLinkId) -> core::result::Result impl aya::programs::SkLookup -pub fn aya::programs::SkLookup::fd(&self) -> core::option::Option +pub fn aya::programs::SkLookup::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkLookup pub fn aya::programs::SkLookup::from_pin>(path: P) -> core::result::Result impl aya::programs::SkLookup @@ -6446,7 +6443,7 @@ pub fn aya::programs::SkMsg::detach(&mut self, link_id: SkMsgLinkId) -> core::re pub fn aya::programs::SkMsg::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkMsg::take_link(&mut self, link_id: SkMsgLinkId) -> core::result::Result impl aya::programs::SkMsg -pub fn aya::programs::SkMsg::fd(&self) -> core::option::Option +pub fn aya::programs::SkMsg::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkMsg pub fn aya::programs::SkMsg::from_pin>(path: P) -> core::result::Result impl aya::programs::SkMsg @@ -6495,7 +6492,7 @@ pub fn aya::programs::SkSkb::from_pin>( pub fn aya::programs::SkSkb::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SkSkb::take_link(&mut self, link_id: SkSkbLinkId) -> core::result::Result impl aya::programs::SkSkb -pub fn aya::programs::SkSkb::fd(&self) -> core::option::Option +pub fn aya::programs::SkSkb::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SkSkb pub fn aya::programs::SkSkb::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::SkSkb::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -6541,7 +6538,7 @@ pub fn aya::programs::SockOps::detach(&mut self, link_id: SockOpsLinkId) -> core pub fn aya::programs::SockOps::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SockOps::take_link(&mut self, link_id: SockOpsLinkId) -> core::result::Result impl aya::programs::SockOps -pub fn aya::programs::SockOps::fd(&self) -> core::option::Option +pub fn aya::programs::SockOps::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SockOps pub fn aya::programs::SockOps::from_pin>(path: P) -> core::result::Result impl aya::programs::SockOps @@ -6589,7 +6586,7 @@ pub fn aya::programs::SocketFilter::detach(&mut self, link_id: SocketFilterLinkI pub fn aya::programs::SocketFilter::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::SocketFilter::take_link(&mut self, link_id: SocketFilterLinkId) -> core::result::Result impl aya::programs::SocketFilter -pub fn aya::programs::SocketFilter::fd(&self) -> core::option::Option +pub fn aya::programs::SocketFilter::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::SocketFilter pub fn aya::programs::SocketFilter::from_pin>(path: P) -> core::result::Result impl aya::programs::SocketFilter @@ -6637,7 +6634,7 @@ pub fn aya::programs::trace_point::TracePoint::detach(&mut self, link_id: aya::p pub fn aya::programs::trace_point::TracePoint::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::trace_point::TracePoint::take_link(&mut self, link_id: aya::programs::trace_point::TracePointLinkId) -> core::result::Result impl aya::programs::trace_point::TracePoint -pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::option::Option +pub fn aya::programs::trace_point::TracePoint::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::trace_point::TracePoint pub fn aya::programs::trace_point::TracePoint::from_pin>(path: P) -> core::result::Result impl aya::programs::trace_point::TracePoint @@ -6687,7 +6684,7 @@ pub fn aya::programs::uprobe::UProbe::kind(&self) -> aya::programs::ProbeKind pub fn aya::programs::uprobe::UProbe::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::uprobe::UProbe::take_link(&mut self, link_id: aya::programs::uprobe::UProbeLinkId) -> core::result::Result impl aya::programs::uprobe::UProbe -pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::option::Option +pub fn aya::programs::uprobe::UProbe::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::uprobe::UProbe pub fn aya::programs::uprobe::UProbe::pin>(&mut self, path: P) -> core::result::Result<(), aya::pin::PinError> pub fn aya::programs::uprobe::UProbe::unpin(self) -> core::result::Result<(), std::io::error::Error> @@ -6735,7 +6732,7 @@ pub fn aya::programs::xdp::Xdp::detach(&mut self, link_id: aya::programs::xdp::X pub fn aya::programs::xdp::Xdp::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::xdp::Xdp::take_link(&mut self, link_id: aya::programs::xdp::XdpLinkId) -> core::result::Result impl aya::programs::xdp::Xdp -pub fn aya::programs::xdp::Xdp::fd(&self) -> core::option::Option +pub fn aya::programs::xdp::Xdp::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> impl aya::programs::xdp::Xdp pub fn aya::programs::xdp::Xdp::from_pin>(path: P) -> core::result::Result impl aya::programs::xdp::Xdp From d0838a76887e08a3897cb012a66e06211003c953 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 15:47:42 +0000 Subject: [PATCH 34/42] build(deps): update object requirement from 0.31 to 0.32 Updates the requirements on [object](https://github.com/gimli-rs/object) to permit the latest version. - [Changelog](https://github.com/gimli-rs/object/blob/master/CHANGELOG.md) - [Commits](https://github.com/gimli-rs/object/compare/0.31.0...0.31.1) --- updated-dependencies: - dependency-name: object dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4a4bdbca..fd85c6b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ log = { version = "0.4", default-features = false } netns-rs = { version = "0.1", default-features = false } nix = { version = "0.26.2", default-features = false } num_enum = { version = "0.6", default-features = false } -object = { version = "0.31", default-features = false } +object = { version = "0.32", default-features = false } parking_lot = { version = "0.12.0", default-features = false } proc-macro-error = { version = "1.0", default-features = false } proc-macro2 = { version = "1", default-features = false } From 623cfd89bf0735abe6143a8159ce91059bbae9f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 15:59:49 +0000 Subject: [PATCH 35/42] build(deps): update num_enum requirement from 0.6 to 0.7 Updates the requirements on [num_enum](https://github.com/illicitonion/num_enum) to permit the latest version. - [Commits](https://github.com/illicitonion/num_enum/compare/0.6.0...0.6.1) --- updated-dependencies: - dependency-name: num_enum dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fd85c6b5..f4d1df95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,7 +75,7 @@ libc = { version = "0.2.105", default-features = false } log = { version = "0.4", default-features = false } netns-rs = { version = "0.1", default-features = false } nix = { version = "0.26.2", default-features = false } -num_enum = { version = "0.6", default-features = false } +num_enum = { version = "0.7", default-features = false } object = { version = "0.32", default-features = false } parking_lot = { version = "0.12.0", default-features = false } proc-macro-error = { version = "1.0", default-features = false } From 8b3a93161d6c46e72f61f8f44748d2cf0b987a3c Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 15 Aug 2023 16:28:25 -0400 Subject: [PATCH 36/42] xtask: bless API with new nightly --- xtask/public-api/aya-log.txt | 2 -- xtask/public-api/aya-obj.txt | 14 ------------- xtask/public-api/aya-tool.txt | 2 -- xtask/public-api/aya.txt | 38 ----------------------------------- 4 files changed, 56 deletions(-) diff --git a/xtask/public-api/aya-log.txt b/xtask/public-api/aya-log.txt index 61bd2867..55276bc9 100644 --- a/xtask/public-api/aya-log.txt +++ b/xtask/public-api/aya-log.txt @@ -19,8 +19,6 @@ impl core::marker::Sync for aya_log::Error impl core::marker::Unpin for aya_log::Error impl !core::panic::unwind_safe::RefUnwindSafe for aya_log::Error impl !core::panic::unwind_safe::UnwindSafe for aya_log::Error -impl core::any::Provider for aya_log::Error where E: core::error::Error + core::marker::Sized -pub fn aya_log::Error::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_log::Error where U: core::convert::From pub fn aya_log::Error::into(self) -> U impl core::convert::TryFrom for aya_log::Error where U: core::convert::Into diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 57efafb4..a2f9d001 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -51,8 +51,6 @@ impl core::marker::Sync for aya_obj::btf::BtfError impl core::marker::Unpin for aya_obj::btf::BtfError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::btf::BtfError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::btf::BtfError -impl core::any::Provider for aya_obj::btf::BtfError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::btf::BtfError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::btf::BtfError where U: core::convert::From pub fn aya_obj::btf::BtfError::into(self) -> U impl core::convert::TryFrom for aya_obj::btf::BtfError where U: core::convert::Into @@ -557,8 +555,6 @@ impl core::marker::Sync for aya_obj::btf::BtfRelocationError impl core::marker::Unpin for aya_obj::btf::BtfRelocationError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::btf::BtfRelocationError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::btf::BtfRelocationError -impl core::any::Provider for aya_obj::btf::BtfRelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::btf::BtfRelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::btf::BtfRelocationError where U: core::convert::From pub fn aya_obj::btf::BtfRelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::btf::BtfRelocationError where U: core::convert::Into @@ -5459,8 +5455,6 @@ impl core::marker::Sync for aya_obj::maps::PinningError impl core::marker::Unpin for aya_obj::maps::PinningError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::maps::PinningError impl core::panic::unwind_safe::UnwindSafe for aya_obj::maps::PinningError -impl core::any::Provider for aya_obj::maps::PinningError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::maps::PinningError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::maps::PinningError where U: core::convert::From pub fn aya_obj::maps::PinningError::into(self) -> U impl core::convert::TryFrom for aya_obj::maps::PinningError where U: core::convert::Into @@ -5798,8 +5792,6 @@ impl core::marker::Sync for aya_obj::ParseError impl core::marker::Unpin for aya_obj::ParseError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::ParseError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::ParseError -impl core::any::Provider for aya_obj::ParseError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::ParseError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::ParseError where U: core::convert::From pub fn aya_obj::ParseError::into(self) -> U impl core::convert::TryFrom for aya_obj::ParseError where U: core::convert::Into @@ -6321,8 +6313,6 @@ impl core::marker::Sync for aya_obj::relocation::RelocationError impl core::marker::Unpin for aya_obj::relocation::RelocationError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::relocation::RelocationError impl core::panic::unwind_safe::UnwindSafe for aya_obj::relocation::RelocationError -impl core::any::Provider for aya_obj::relocation::RelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::relocation::RelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::relocation::RelocationError where U: core::convert::From pub fn aya_obj::relocation::RelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::relocation::RelocationError where U: core::convert::Into @@ -6353,8 +6343,6 @@ impl core::marker::Sync for aya_obj::relocation::BpfRelocationError impl core::marker::Unpin for aya_obj::relocation::BpfRelocationError impl core::panic::unwind_safe::RefUnwindSafe for aya_obj::relocation::BpfRelocationError impl core::panic::unwind_safe::UnwindSafe for aya_obj::relocation::BpfRelocationError -impl core::any::Provider for aya_obj::relocation::BpfRelocationError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::relocation::BpfRelocationError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::relocation::BpfRelocationError where U: core::convert::From pub fn aya_obj::relocation::BpfRelocationError::into(self) -> U impl core::convert::TryFrom for aya_obj::relocation::BpfRelocationError where U: core::convert::Into @@ -6519,8 +6507,6 @@ impl core::marker::Sync for aya_obj::ParseError impl core::marker::Unpin for aya_obj::ParseError impl !core::panic::unwind_safe::RefUnwindSafe for aya_obj::ParseError impl !core::panic::unwind_safe::UnwindSafe for aya_obj::ParseError -impl core::any::Provider for aya_obj::ParseError where E: core::error::Error + core::marker::Sized -pub fn aya_obj::ParseError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_obj::ParseError where U: core::convert::From pub fn aya_obj::ParseError::into(self) -> U impl core::convert::TryFrom for aya_obj::ParseError where U: core::convert::Into diff --git a/xtask/public-api/aya-tool.txt b/xtask/public-api/aya-tool.txt index 59e6dc4d..5d857bd1 100644 --- a/xtask/public-api/aya-tool.txt +++ b/xtask/public-api/aya-tool.txt @@ -25,8 +25,6 @@ impl core::marker::Sync for aya_tool::generate::Error impl core::marker::Unpin for aya_tool::generate::Error impl !core::panic::unwind_safe::RefUnwindSafe for aya_tool::generate::Error impl !core::panic::unwind_safe::UnwindSafe for aya_tool::generate::Error -impl core::any::Provider for aya_tool::generate::Error where E: core::error::Error + core::marker::Sized -pub fn aya_tool::generate::Error::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya_tool::generate::Error where U: core::convert::From pub fn aya_tool::generate::Error::into(self) -> U impl core::convert::TryFrom for aya_tool::generate::Error where U: core::convert::Into diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 41a016aa..a226a062 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -352,8 +352,6 @@ impl core::marker::Sync for aya::maps::perf::PerfBufferError impl core::marker::Unpin for aya::maps::perf::PerfBufferError impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::perf::PerfBufferError impl !core::panic::unwind_safe::UnwindSafe for aya::maps::perf::PerfBufferError -impl core::any::Provider for aya::maps::perf::PerfBufferError where E: core::error::Error + core::marker::Sized -pub fn aya::maps::perf::PerfBufferError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::maps::perf::PerfBufferError where U: core::convert::From pub fn aya::maps::perf::PerfBufferError::into(self) -> U impl core::convert::TryFrom for aya::maps::perf::PerfBufferError where U: core::convert::Into @@ -1012,8 +1010,6 @@ impl core::marker::Sync for aya::maps::MapError impl core::marker::Unpin for aya::maps::MapError impl !core::panic::unwind_safe::RefUnwindSafe for aya::maps::MapError impl !core::panic::unwind_safe::UnwindSafe for aya::maps::MapError -impl core::any::Provider for aya::maps::MapError where E: core::error::Error + core::marker::Sized -pub fn aya::maps::MapError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::maps::MapError where U: core::convert::From pub fn aya::maps::MapError::into(self) -> U impl core::convert::TryFrom for aya::maps::MapError where U: core::convert::Into @@ -1772,8 +1768,6 @@ impl core::marker::Sync for aya::pin::PinError impl core::marker::Unpin for aya::pin::PinError impl !core::panic::unwind_safe::RefUnwindSafe for aya::pin::PinError impl !core::panic::unwind_safe::UnwindSafe for aya::pin::PinError -impl core::any::Provider for aya::pin::PinError where E: core::error::Error + core::marker::Sized -pub fn aya::pin::PinError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::pin::PinError where U: core::convert::From pub fn aya::pin::PinError::into(self) -> U impl core::convert::TryFrom for aya::pin::PinError where U: core::convert::Into @@ -2504,8 +2498,6 @@ impl core::marker::Sync for aya::programs::extension::ExtensionError impl core::marker::Unpin for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::UnwindSafe for aya::programs::extension::ExtensionError -impl core::any::Provider for aya::programs::extension::ExtensionError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::extension::ExtensionError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::extension::ExtensionError where U: core::convert::From pub fn aya::programs::extension::ExtensionError::into(self) -> U impl core::convert::TryFrom for aya::programs::extension::ExtensionError where U: core::convert::Into @@ -2884,8 +2876,6 @@ impl core::marker::Sync for aya::programs::kprobe::KProbeError impl core::marker::Unpin for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::kprobe::KProbeError -impl core::any::Provider for aya::programs::kprobe::KProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::kprobe::KProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::kprobe::KProbeError where U: core::convert::From pub fn aya::programs::kprobe::KProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::kprobe::KProbeError where U: core::convert::Into @@ -3034,8 +3024,6 @@ impl core::marker::Sync for aya::programs::links::LinkError impl core::marker::Unpin for aya::programs::links::LinkError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::LinkError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::links::LinkError -impl core::any::Provider for aya::programs::links::LinkError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::links::LinkError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::links::LinkError where U: core::convert::From pub fn aya::programs::links::LinkError::into(self) -> U impl core::convert::TryFrom for aya::programs::links::LinkError where U: core::convert::Into @@ -3916,8 +3904,6 @@ impl core::marker::Sync for aya::programs::tc::TcError impl core::marker::Unpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError -impl core::any::Provider for aya::programs::tc::TcError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::tc::TcError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::tc::TcError where U: core::convert::From pub fn aya::programs::tc::TcError::into(self) -> U impl core::convert::TryFrom for aya::programs::tc::TcError where U: core::convert::Into @@ -4209,8 +4195,6 @@ impl core::marker::Sync for aya::programs::trace_point::TracePointError impl core::marker::Unpin for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::trace_point::TracePointError -impl core::any::Provider for aya::programs::trace_point::TracePointError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::trace_point::TracePointError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::trace_point::TracePointError where U: core::convert::From pub fn aya::programs::trace_point::TracePointError::into(self) -> U impl core::convert::TryFrom for aya::programs::trace_point::TracePointError where U: core::convert::Into @@ -4369,8 +4353,6 @@ impl core::marker::Sync for aya::programs::uprobe::UProbeError impl core::marker::Unpin for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::UProbeError -impl core::any::Provider for aya::programs::uprobe::UProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::uprobe::UProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::uprobe::UProbeError where U: core::convert::From pub fn aya::programs::uprobe::UProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::uprobe::UProbeError where U: core::convert::Into @@ -4521,8 +4503,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpError impl core::marker::Unpin for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpError -impl core::any::Provider for aya::programs::xdp::XdpError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::xdp::XdpError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::xdp::XdpError where U: core::convert::From pub fn aya::programs::xdp::XdpError::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpError where U: core::convert::Into @@ -4815,8 +4795,6 @@ impl core::marker::Sync for aya::programs::extension::ExtensionError impl core::marker::Unpin for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::extension::ExtensionError impl core::panic::unwind_safe::UnwindSafe for aya::programs::extension::ExtensionError -impl core::any::Provider for aya::programs::extension::ExtensionError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::extension::ExtensionError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::extension::ExtensionError where U: core::convert::From pub fn aya::programs::extension::ExtensionError::into(self) -> U impl core::convert::TryFrom for aya::programs::extension::ExtensionError where U: core::convert::Into @@ -4852,8 +4830,6 @@ impl core::marker::Sync for aya::programs::kprobe::KProbeError impl core::marker::Unpin for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::kprobe::KProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::kprobe::KProbeError -impl core::any::Provider for aya::programs::kprobe::KProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::kprobe::KProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::kprobe::KProbeError where U: core::convert::From pub fn aya::programs::kprobe::KProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::kprobe::KProbeError where U: core::convert::Into @@ -5237,8 +5213,6 @@ impl core::marker::Sync for aya::programs::ProgramError impl core::marker::Unpin for aya::programs::ProgramError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::ProgramError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::ProgramError -impl core::any::Provider for aya::programs::ProgramError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::ProgramError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::ProgramError where U: core::convert::From pub fn aya::programs::ProgramError::into(self) -> U impl core::convert::TryFrom for aya::programs::ProgramError where U: core::convert::Into @@ -5338,8 +5312,6 @@ impl core::marker::Sync for aya::programs::SocketFilterError impl core::marker::Unpin for aya::programs::SocketFilterError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::SocketFilterError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::SocketFilterError -impl core::any::Provider for aya::programs::SocketFilterError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::SocketFilterError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::SocketFilterError where U: core::convert::From pub fn aya::programs::SocketFilterError::into(self) -> U impl core::convert::TryFrom for aya::programs::SocketFilterError where U: core::convert::Into @@ -5416,8 +5388,6 @@ impl core::marker::Sync for aya::programs::tc::TcError impl core::marker::Unpin for aya::programs::tc::TcError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::tc::TcError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::tc::TcError -impl core::any::Provider for aya::programs::tc::TcError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::tc::TcError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::tc::TcError where U: core::convert::From pub fn aya::programs::tc::TcError::into(self) -> U impl core::convert::TryFrom for aya::programs::tc::TcError where U: core::convert::Into @@ -5453,8 +5423,6 @@ impl core::marker::Sync for aya::programs::trace_point::TracePointError impl core::marker::Unpin for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::trace_point::TracePointError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::trace_point::TracePointError -impl core::any::Provider for aya::programs::trace_point::TracePointError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::trace_point::TracePointError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::trace_point::TracePointError where U: core::convert::From pub fn aya::programs::trace_point::TracePointError::into(self) -> U impl core::convert::TryFrom for aya::programs::trace_point::TracePointError where U: core::convert::Into @@ -5497,8 +5465,6 @@ impl core::marker::Sync for aya::programs::uprobe::UProbeError impl core::marker::Unpin for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::uprobe::UProbeError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::uprobe::UProbeError -impl core::any::Provider for aya::programs::uprobe::UProbeError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::uprobe::UProbeError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::uprobe::UProbeError where U: core::convert::From pub fn aya::programs::uprobe::UProbeError::into(self) -> U impl core::convert::TryFrom for aya::programs::uprobe::UProbeError where U: core::convert::Into @@ -5533,8 +5499,6 @@ impl core::marker::Sync for aya::programs::xdp::XdpError impl core::marker::Unpin for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::RefUnwindSafe for aya::programs::xdp::XdpError impl !core::panic::unwind_safe::UnwindSafe for aya::programs::xdp::XdpError -impl core::any::Provider for aya::programs::xdp::XdpError where E: core::error::Error + core::marker::Sized -pub fn aya::programs::xdp::XdpError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::programs::xdp::XdpError where U: core::convert::From pub fn aya::programs::xdp::XdpError::into(self) -> U impl core::convert::TryFrom for aya::programs::xdp::XdpError where U: core::convert::Into @@ -7058,8 +7022,6 @@ impl core::marker::Sync for aya::BpfError impl core::marker::Unpin for aya::BpfError impl !core::panic::unwind_safe::RefUnwindSafe for aya::BpfError impl !core::panic::unwind_safe::UnwindSafe for aya::BpfError -impl core::any::Provider for aya::BpfError where E: core::error::Error + core::marker::Sized -pub fn aya::BpfError::provide<'a>(&'a self, demand: &mut core::any::Demand<'a>) impl core::convert::Into for aya::BpfError where U: core::convert::From pub fn aya::BpfError::into(self) -> U impl core::convert::TryFrom for aya::BpfError where U: core::convert::Into From ae6526e59b2875807524d466667e2d89c4cd4b8e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 15 Aug 2023 16:08:13 -0400 Subject: [PATCH 37/42] programs: `ProgramData::attach_prog_fd` is owned This prevents a file descriptor leak when extensions are used. This is an API breaking change. Updates #612. --- aya/src/programs/extension.rs | 17 +++++++++++------ aya/src/programs/mod.rs | 7 +++---- aya/src/sys/bpf.rs | 4 ++-- test/integration-test/src/tests/smoke.rs | 4 +++- xtask/public-api/aya.txt | 4 ++-- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/aya/src/programs/extension.rs b/aya/src/programs/extension.rs index fd955ddc..e1aab2c2 100644 --- a/aya/src/programs/extension.rs +++ b/aya/src/programs/extension.rs @@ -44,7 +44,7 @@ pub enum ExtensionError { /// let prog_fd = prog.fd().unwrap(); /// let prog_fd = prog_fd.try_clone().unwrap(); /// let ext: &mut Extension = bpf.program_mut("extension").unwrap().try_into()?; -/// ext.load(&prog_fd, "function_to_replace")?; +/// ext.load(prog_fd, "function_to_replace")?; /// ext.attach()?; /// Ok::<(), aya::BpfError>(()) /// ``` @@ -69,12 +69,11 @@ impl Extension { /// The extension code will be loaded but inactive until it's attached. /// There are no restrictions on what functions may be replaced, so you could replace /// the main entry point of your program with an extension. - pub fn load(&mut self, program: &ProgramFd, func_name: &str) -> Result<(), ProgramError> { - let target_prog_fd = program.as_fd(); - let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?; + pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> { + let (btf_fd, btf_id) = get_btf_info(program.as_fd(), func_name)?; self.data.attach_btf_obj_fd = Some(btf_fd); - self.data.attach_prog_fd = Some(target_prog_fd.as_raw_fd()); + self.data.attach_prog_fd = Some(program); self.data.attach_btf_id = Some(btf_id); load_program(BPF_PROG_TYPE_EXT, &mut self.data) } @@ -90,7 +89,13 @@ impl Extension { let prog_fd = self.fd()?; let prog_fd = prog_fd.as_fd(); let prog_fd = prog_fd.as_raw_fd(); - let target_fd = self.data.attach_prog_fd.ok_or(ProgramError::NotLoaded)?; + let target_fd = self + .data + .attach_prog_fd + .as_ref() + .ok_or(ProgramError::NotLoaded)?; + let target_fd = target_fd.as_fd(); + let target_fd = target_fd.as_raw_fd(); let btf_id = self.data.attach_btf_id.ok_or(ProgramError::NotLoaded)?; // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 51164f89..b79627a8 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -69,7 +69,7 @@ use std::{ ffi::CString, io, num::NonZeroU32, - os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}, + os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd}, path::{Path, PathBuf}, sync::Arc, time::{Duration, SystemTime}, @@ -382,7 +382,6 @@ impl Program { /// Returns the file descriptor of a program. /// /// Can be used to add a program to a [`crate::maps::ProgramArray`] or attach an [`Extension`] program. - /// Can be converted to [`RawFd`] using [`AsRawFd`]. pub fn fd(&self) -> Result<&ProgramFd, ProgramError> { match self { Program::KProbe(p) => p.fd(), @@ -422,7 +421,7 @@ pub(crate) struct ProgramData { pub(crate) expected_attach_type: Option, pub(crate) attach_btf_obj_fd: Option, pub(crate) attach_btf_id: Option, - pub(crate) attach_prog_fd: Option, + pub(crate) attach_prog_fd: Option, pub(crate) btf_fd: Option>, pub(crate) verifier_log_level: VerifierLogLevel, pub(crate) path: Option, @@ -613,7 +612,7 @@ fn load_program( prog_btf_fd: btf_fd.as_ref().map(|f| f.as_fd()), attach_btf_obj_fd: attach_btf_obj_fd.as_ref().map(|fd| fd.as_fd()), attach_btf_id: *attach_btf_id, - attach_prog_fd: *attach_prog_fd, + attach_prog_fd: attach_prog_fd.as_ref().map(|fd| fd.as_fd()), func_info_rec_size: *func_info_rec_size, func_info: func_info.clone(), line_info_rec_size: *line_info_rec_size, diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 9b9fab5b..9912e829 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -120,7 +120,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> { pub(crate) prog_btf_fd: Option>, pub(crate) attach_btf_obj_fd: Option>, pub(crate) attach_btf_id: Option, - pub(crate) attach_prog_fd: Option, + pub(crate) attach_prog_fd: Option>, pub(crate) func_info_rec_size: usize, pub(crate) func_info: FuncSecInfo, pub(crate) line_info_rec_size: usize, @@ -184,7 +184,7 @@ pub(crate) fn bpf_load_program( u.__bindgen_anon_1.attach_btf_obj_fd = v.as_raw_fd() as _; } if let Some(v) = aya_attr.attach_prog_fd { - u.__bindgen_anon_1.attach_prog_fd = v as u32; + u.__bindgen_anon_1.attach_prog_fd = v.as_raw_fd() as u32; } if let Some(v) = aya_attr.attach_btf_id { diff --git a/test/integration-test/src/tests/smoke.rs b/test/integration-test/src/tests/smoke.rs index 861e9661..48c1600b 100644 --- a/test/integration-test/src/tests/smoke.rs +++ b/test/integration-test/src/tests/smoke.rs @@ -63,7 +63,9 @@ fn extension() { .load(crate::EXT) .unwrap(); let drop_: &mut Extension = bpf.program_mut("xdp_drop").unwrap().try_into().unwrap(); - drop_.load(pass.fd().unwrap(), "xdp_pass").unwrap(); + drop_ + .load(pass.fd().unwrap().try_clone().unwrap(), "xdp_pass") + .unwrap(); } #[test] diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index a226a062..0b2a7374 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -2521,7 +2521,7 @@ impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> @@ -5855,7 +5855,7 @@ impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::attach(&mut self) -> core::result::Result pub fn aya::programs::extension::Extension::attach_to_program(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result pub fn aya::programs::extension::Extension::detach(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result<(), aya::programs::ProgramError> -pub fn aya::programs::extension::Extension::load(&mut self, program: &aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> +pub fn aya::programs::extension::Extension::load(&mut self, program: aya::programs::ProgramFd, func_name: &str) -> core::result::Result<(), aya::programs::ProgramError> pub fn aya::programs::extension::Extension::take_link(&mut self, link_id: aya::programs::extension::ExtensionLinkId) -> core::result::Result impl aya::programs::extension::Extension pub fn aya::programs::extension::Extension::fd(&self) -> core::result::Result<&aya::programs::ProgramFd, aya::programs::ProgramError> From 3d68fa32cba3dfadc6a611cf285c7f6733abd39a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 15 Aug 2023 16:18:56 -0400 Subject: [PATCH 38/42] aya: use RAII to close FDs --- aya/src/sys/bpf.rs | 69 ++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 9912e829..546bf0c4 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -3,12 +3,12 @@ use std::{ ffi::{CStr, CString}, io, iter, mem::{self, MaybeUninit}, - os::fd::{AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, OwnedFd, RawFd}, slice, }; use crate::util::KernelVersion; -use libc::{c_char, c_long, close, ENOENT, ENOSPC}; +use libc::{c_char, c_long, ENOENT, ENOSPC}; use obj::{ btf::{BtfEnum64, Enum64}, maps::{bpf_map_def, LegacyMap}, @@ -190,8 +190,7 @@ pub(crate) fn bpf_load_program( if let Some(v) = aya_attr.attach_btf_id { u.attach_btf_id = v; } - // SAFETY: BPF_PROG_LOAD returns a new file descriptor. - unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) } + bpf_prog_load(&mut attr) } fn lookup( @@ -633,14 +632,7 @@ pub(crate) fn is_prog_name_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_probe_read_kernel_supported() -> bool { @@ -664,14 +656,7 @@ pub(crate) fn is_probe_read_kernel_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_perf_link_supported() -> bool { @@ -691,18 +676,18 @@ pub(crate) fn is_perf_link_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_TRACEPOINT as u32; - if let Ok(fd) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - if let Err((_, e)) = + if let Ok(fd) = bpf_prog_load(&mut attr) { + let fd = fd.as_fd(); + let fd = fd.as_raw_fd(); + matches!( // Uses an invalid target FD so we get EBADF if supported. - bpf_link_create(fd as i32, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0) - { + bpf_link_create(fd, -1, bpf_attach_type::BPF_PERF_EVENT, None, 0), // Returns EINVAL if unsupported. EBADF if supported. - let res = e.raw_os_error() == Some(libc::EBADF); - unsafe { libc::close(fd as i32) }; - return res; - } + Err((_, e)) if e.raw_os_error() == Some(libc::EBADF), + ) + } else { + false } - false } pub(crate) fn is_bpf_global_data_supported() -> bool { @@ -746,16 +731,10 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER as u32; - if let Ok(v) = sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - let fd = v as RawFd; - - unsafe { close(fd) }; - - return true; - } + bpf_prog_load(&mut attr).is_ok() + } else { + false } - - false } pub(crate) fn is_bpf_cookie_supported() -> bool { @@ -775,14 +754,7 @@ pub(crate) fn is_bpf_cookie_supported() -> bool { u.insns = insns.as_ptr() as u64; u.prog_type = bpf_prog_type::BPF_PROG_TYPE_KPROBE as u32; - match sys_bpf(bpf_cmd::BPF_PROG_LOAD, &mut attr) { - Ok(v) => { - let fd = v as RawFd; - unsafe { close(fd) }; - true - } - Err(_) => false, - } + bpf_prog_load(&mut attr).is_ok() } pub(crate) fn is_btf_supported() -> bool { @@ -941,6 +913,11 @@ pub(crate) fn is_btf_type_tag_supported() -> bool { bpf_load_btf(btf_bytes.as_slice(), &mut [], Default::default()).is_ok() } +fn bpf_prog_load(attr: &mut bpf_attr) -> SysResult { + // SAFETY: BPF_PROG_LOAD returns a new file descriptor. + unsafe { fd_sys_bpf(bpf_cmd::BPF_PROG_LOAD, attr) } +} + fn sys_bpf(cmd: bpf_cmd, attr: &mut bpf_attr) -> SysResult { syscall(Syscall::Bpf { cmd, attr }) } From 89bc255f1d14d72a61064b9b40b641b58f8970e0 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 16 Aug 2023 11:54:07 -0400 Subject: [PATCH 39/42] aya: MapData::fd is non-optional The primary driver of change here is that `MapData::create` is now a factory function that returns `Result` rather than mutating `&mut self`. The remaining changes are consequences of that change, the most notable of which is the removal of several errors which are no longer possible. --- aya-obj/src/relocation.rs | 36 ++-- aya/src/bpf.rs | 34 +--- aya/src/maps/array/array.rs | 6 +- aya/src/maps/array/per_cpu_array.rs | 6 +- aya/src/maps/array/program_array.rs | 6 +- aya/src/maps/bloom_filter.rs | 125 +++++-------- aya/src/maps/hash_map/hash_map.rs | 214 ++++++---------------- aya/src/maps/hash_map/mod.rs | 4 +- aya/src/maps/hash_map/per_cpu_hash_map.rs | 6 +- aya/src/maps/lpm_trie.rs | 166 ++++++----------- aya/src/maps/mod.rs | 156 +++++++--------- aya/src/maps/perf/perf_event_array.rs | 4 +- aya/src/maps/queue.rs | 6 +- aya/src/maps/sock/sock_hash.rs | 5 +- aya/src/maps/sock/sock_map.rs | 8 +- aya/src/maps/stack.rs | 6 +- aya/src/maps/stack_trace.rs | 3 +- aya/src/sys/bpf.rs | 14 +- test/integration-test/src/tests/rbpf.rs | 2 +- xtask/public-api/aya-obj.txt | 7 +- xtask/public-api/aya.txt | 9 +- 21 files changed, 284 insertions(+), 539 deletions(-) diff --git a/aya-obj/src/relocation.rs b/aya-obj/src/relocation.rs index fc02a79f..8269f6ca 100644 --- a/aya-obj/src/relocation.rs +++ b/aya-obj/src/relocation.rs @@ -73,15 +73,6 @@ pub enum RelocationError { address: u64, }, - /// Referenced map not created yet - #[error("the map `{name}` at section `{section_index}` has not been created")] - MapNotCreated { - /// The section index - section_index: usize, - /// The map name - name: String, - }, - /// Invalid relocation offset #[error("invalid offset `{offset}` applying relocation #{relocation_number}")] InvalidRelocationOffset { @@ -114,7 +105,7 @@ pub(crate) struct Symbol { impl Object { /// Relocates the map references - pub fn relocate_maps<'a, I: Iterator, &'a Map)>>( + pub fn relocate_maps<'a, I: Iterator>( &mut self, maps: I, text_sections: &HashSet, @@ -187,8 +178,8 @@ impl Object { fn relocate_maps<'a, I: Iterator>( fun: &mut Function, relocations: I, - maps_by_section: &HashMap, &Map)>, - maps_by_symbol: &HashMap, &Map)>, + maps_by_section: &HashMap, + maps_by_symbol: &HashMap, symbol_table: &HashMap, text_sections: &HashSet, ) -> Result<(), RelocationError> { @@ -230,7 +221,7 @@ fn relocate_maps<'a, I: Iterator>( continue; } - let (name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) { + let (_name, fd, map) = if let Some(m) = maps_by_symbol.get(&rel.symbol_index) { let map = &m.2; debug!( "relocating map by symbol index {:?}, kind {:?} at insn {ins_index} in section {}", @@ -266,18 +257,13 @@ fn relocate_maps<'a, I: Iterator>( }; debug_assert_eq!(map.section_index(), section_index); - let map_fd = fd.ok_or_else(|| RelocationError::MapNotCreated { - name: (*name).into(), - section_index, - })?; - if !map.data().is_empty() { instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_VALUE as u8); instructions[ins_index + 1].imm = instructions[ins_index].imm + sym.address as i32; } else { instructions[ins_index].set_src_reg(BPF_PSEUDO_MAP_FD as u8); } - instructions[ins_index].imm = map_fd; + instructions[ins_index].imm = *fd; } Ok(()) @@ -588,7 +574,7 @@ mod test { let maps_by_section = HashMap::new(); let map = fake_legacy_map(1); - let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); + let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]); relocate_maps( &mut fun, @@ -642,8 +628,8 @@ mod test { let map_1 = fake_legacy_map(1); let map_2 = fake_legacy_map(2); let maps_by_symbol = HashMap::from([ - (1, ("test_map_1", Some(1), &map_1)), - (2, ("test_map_2", Some(2), &map_2)), + (1, ("test_map_1", 1, &map_1)), + (2, ("test_map_2", 2, &map_2)), ]); relocate_maps( @@ -683,7 +669,7 @@ mod test { let maps_by_section = HashMap::new(); let map = fake_btf_map(1); - let maps_by_symbol = HashMap::from([(1, ("test_map", Some(1), &map))]); + let maps_by_symbol = HashMap::from([(1, ("test_map", 1, &map))]); relocate_maps( &mut fun, @@ -737,8 +723,8 @@ mod test { let map_1 = fake_btf_map(1); let map_2 = fake_btf_map(2); let maps_by_symbol = HashMap::from([ - (1, ("test_map_1", Some(1), &map_1)), - (2, ("test_map_2", Some(2), &map_2)), + (1, ("test_map_1", 1, &map_1)), + (2, ("test_map_2", 2, &map_2)), ]); relocate_maps( diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index ee074dba..f5841f3f 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -4,7 +4,7 @@ use std::{ ffi::CString, fs, io, os::{ - fd::{AsFd as _, OwnedFd, RawFd}, + fd::{AsFd as _, OwnedFd}, raw::c_int, }, path::{Path, PathBuf}, @@ -475,35 +475,15 @@ impl<'a> BpfLoader<'a> { } } } - let mut map = MapData { - obj, - fd: None, - pinned: false, - }; - let fd = match map.obj.pinning() { + let btf_fd = btf_fd.as_deref().map(|fd| fd.as_fd()); + let mut map = match obj.pinning() { + PinningType::None => MapData::create(obj, &name, btf_fd)?, PinningType::ByName => { - let path = match &map_pin_path { - Some(p) => p, - None => return Err(BpfError::NoPinPath), - }; - // try to open map in case it's already pinned - match map.open_pinned(&name, path) { - Ok(fd) => { - map.pinned = true; - fd as RawFd - } - Err(_) => { - let fd = map.create(&name, btf_fd.as_deref().map(|f| f.as_fd()))?; - map.pin(&name, path).map_err(|error| MapError::PinError { - name: Some(name.to_string()), - error, - })?; - fd - } - } + let path = map_pin_path.as_ref().ok_or(BpfError::NoPinPath)?; + MapData::create_pinned(path, obj, &name, btf_fd)? } - PinningType::None => map.create(&name, btf_fd.as_deref().map(|f| f.as_fd()))?, }; + let fd = map.fd; if !map.obj.data().is_empty() && map.obj.section_kind() != BpfSectionKind::Bss { bpf_map_update_elem_ptr(fd, &0 as *const _, map.obj.data_mut().as_mut_ptr(), 0) .map_err(|(_, io_error)| SyscallError { diff --git a/aya/src/maps/array/array.rs b/aya/src/maps/array/array.rs index 7f242ccc..97bb46d6 100644 --- a/aya/src/maps/array/array.rs +++ b/aya/src/maps/array/array.rs @@ -39,8 +39,6 @@ impl, V: Pod> Array { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(Array { inner: map, _v: PhantomData, @@ -63,7 +61,7 @@ impl, V: Pod> Array { pub fn get(&self, index: &u32, flags: u64) -> Result { let data = self.inner.borrow(); check_bounds(data, *index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; let value = bpf_map_lookup_elem(fd, index, flags).map_err(|(_, io_error)| SyscallError { @@ -90,7 +88,7 @@ impl, V: Pod> Array { pub fn set(&mut self, index: u32, value: impl Borrow, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; bpf_map_update_elem(fd, Some(&index), value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/array/per_cpu_array.rs b/aya/src/maps/array/per_cpu_array.rs index 7cf1116a..6405af4a 100644 --- a/aya/src/maps/array/per_cpu_array.rs +++ b/aya/src/maps/array/per_cpu_array.rs @@ -58,8 +58,6 @@ impl, V: Pod> PerCpuArray { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(PerCpuArray { inner: map, _v: PhantomData, @@ -82,7 +80,7 @@ impl, V: Pod> PerCpuArray { pub fn get(&self, index: &u32, flags: u64) -> Result, MapError> { let data = self.inner.borrow(); check_bounds(data, *index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; let value = bpf_map_lookup_elem_per_cpu(fd, index, flags).map_err(|(_, io_error)| { SyscallError { @@ -110,7 +108,7 @@ impl, V: Pod> PerCpuArray { pub fn set(&mut self, index: u32, values: PerCpuValues, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; bpf_map_update_elem_per_cpu(fd, &index, &values, flags).map_err(|(_, io_error)| { SyscallError { diff --git a/aya/src/maps/array/program_array.rs b/aya/src/maps/array/program_array.rs index 7a708527..e2152b56 100644 --- a/aya/src/maps/array/program_array.rs +++ b/aya/src/maps/array/program_array.rs @@ -56,8 +56,6 @@ impl> ProgramArray { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(ProgramArray { inner: map }) } @@ -76,7 +74,7 @@ impl> ProgramArray { pub fn set(&mut self, index: u32, program: &ProgramFd, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, index)?; - let fd = data.fd_or_err()?; + let fd = data.fd; let prog_fd = program.as_fd(); let prog_fd = prog_fd.as_raw_fd(); @@ -96,7 +94,7 @@ impl> ProgramArray { pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { let data = self.inner.borrow_mut(); check_bounds(data, *index)?; - let fd = self.inner.borrow_mut().fd_or_err()?; + let fd = self.inner.borrow_mut().fd; bpf_map_delete_elem(fd, index) .map(|_| ()) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 03374b4e..6fc24ff4 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -41,8 +41,6 @@ impl, V: Pod> BloomFilter { let data = map.borrow(); check_v_size::(data)?; - let _ = data.fd_or_err()?; - Ok(BloomFilter { inner: map, _v: PhantomData, @@ -51,7 +49,7 @@ impl, V: Pod> BloomFilter { /// Query the existence of the element. pub fn contains(&self, mut value: &V, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_lookup_elem_ptr::(fd, None, &mut value, flags) .map_err(|(_, io_error)| SyscallError { @@ -64,7 +62,7 @@ impl, V: Pod> BloomFilter { /// Inserts a value into the map. pub fn insert(&self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, @@ -106,17 +104,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; + let map = new_map(new_obj_map()); assert_matches!( BloomFilter::<_, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -128,25 +133,21 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: None, - pinned: false, - }; - - let map = Map::PerfEventArray(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + + let map = Map::PerfEventArray(map); assert_matches!( BloomFilter::<_, u32>::try_from(&map), @@ -154,54 +155,28 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; - - assert_matches!( - BloomFilter::<_, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); - assert!(BloomFilter::<_, u32>::new(&mut map).is_ok()); + assert!(BloomFilter::<_, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); - let map = Map::BloomFilter(map_data); + let map = Map::BloomFilter(map); assert!(BloomFilter::<_, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let mut map = new_map(new_obj_map()); let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( bloom_filter.insert(1, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_push_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -210,6 +185,9 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -218,26 +196,16 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - - let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); assert!(bloom_filter.insert(0, 42).is_ok()); } #[test] fn test_contains_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( bloom_filter.contains(&1, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -246,6 +214,9 @@ mod tests { #[test] fn test_contains_not_found() { + let map = new_map(new_obj_map()); + let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -253,12 +224,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let bloom_filter = BloomFilter::<_, u32>::new(&map).unwrap(); assert_matches!(bloom_filter.contains(&1, 0), Err(MapError::ElementNotFound)); } diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index cbd2fc81..b2f9e547 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -42,7 +42,6 @@ impl, K: Pod, V: Pod> HashMap { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; Ok(HashMap { inner: map, @@ -53,7 +52,7 @@ impl, K: Pod, V: Pod> HashMap { /// Returns a copy of the value associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -137,17 +136,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_key_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; + let map = new_map(new_obj_map()); assert_matches!( HashMap::<_, u8, u32>::new(&map), Err(MapError::InvalidKeySize { @@ -159,11 +165,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; + let map = new_map(new_obj_map()); assert_matches!( HashMap::<_, u32, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -175,13 +177,8 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; - - let map = Map::Array(map_data); + let map = new_map(new_obj_map()); + let map = Map::Array(map); assert_matches!( HashMap::<_, u8, u32>::try_from(&map), Err(MapError::InvalidMapType { .. }) @@ -190,13 +187,8 @@ mod tests { #[test] fn test_try_from_wrong_map_values() { - let map_data = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; - - let map = Map::HashMap(map_data); + let map = new_map(new_obj_map()); + let map = Map::HashMap(map); assert_matches!( HashMap::<_, u32, u16>::try_from(&map), Err(MapError::InvalidValueSize { @@ -206,79 +198,46 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; - - assert_matches!( - HashMap::<_, u32, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - - assert!(HashMap::<_, u32, u32>::new(&mut map).is_ok()); + let map = new_map(new_obj_map()); + assert!(HashMap::<_, u32, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - - let map = Map::HashMap(map_data); + let map = new_map(new_obj_map()); + let map = Map::HashMap(map); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_try_from_ok_lru() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_LRU_HASH as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: Some(42), - pinned: false, - }; - - let map = Map::HashMap(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_LRU_HASH as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + let map = Map::HashMap(map); assert!(HashMap::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let mut map = new_map(new_obj_map()); let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( hm.insert(1, 42, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -287,6 +246,9 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -295,18 +257,14 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.insert(1, 42, 0).is_ok()); } #[test] fn test_insert_boxed_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -315,27 +273,16 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.insert(Box::new(1), Box::new(42), 0).is_ok()); } #[test] fn test_remove_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let mut map = new_map(new_obj_map()); let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( hm.remove(&1), Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -344,6 +291,9 @@ mod tests { #[test] fn test_remove_ok() { + let mut map = new_map(new_obj_map()); + let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_DELETE_ELEM, @@ -352,24 +302,13 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let mut hm = HashMap::<_, u32, u32>::new(&mut map).unwrap(); - assert!(hm.remove(&1).is_ok()); } #[test] fn test_get_syscall_error() { + let map = new_map(new_obj_map()); override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); assert_matches!( @@ -380,6 +319,7 @@ mod tests { #[test] fn test_get_not_found() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -387,11 +327,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); assert_matches!(hm.get(&1, 0), Err(MapError::KeyNotFound)); @@ -416,6 +351,7 @@ mod tests { #[test] fn test_keys_empty() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -423,11 +359,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let keys = hm.keys().collect::, _>>(); assert_matches!(keys, Ok(ks) if ks.is_empty()) @@ -463,6 +394,8 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_keys() { + let map = new_map(new_obj_map()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -471,11 +404,6 @@ mod tests { _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let keys = hm.keys().collect::, _>>().unwrap(); @@ -488,6 +416,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_keys_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -503,11 +432,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut keys = hm.keys(); @@ -529,6 +453,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -540,11 +465,6 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let items = hm.iter().collect::, _>>().unwrap(); assert_eq!(&items, &[(10, 100), (20, 200), (30, 300)]) @@ -556,6 +476,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_key_deleted() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -577,11 +498,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let items = hm.iter().collect::, _>>().unwrap(); @@ -594,6 +510,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_key_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -615,11 +532,6 @@ mod tests { } => lookup_elem(attr), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut iter = hm.iter(); @@ -641,6 +553,7 @@ mod tests { // to support stable as well. #[cfg_attr(miri, ignore)] fn test_iter_value_error() { + let map = new_map(new_obj_map()); override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_GET_NEXT_KEY, @@ -662,11 +575,6 @@ mod tests { } _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; let hm = HashMap::<_, u32, u32>::new(&map).unwrap(); let mut iter = hm.iter(); diff --git a/aya/src/maps/hash_map/mod.rs b/aya/src/maps/hash_map/mod.rs index 62d3fc55..87fc0d70 100644 --- a/aya/src/maps/hash_map/mod.rs +++ b/aya/src/maps/hash_map/mod.rs @@ -20,7 +20,7 @@ pub(crate) fn insert( value: &V, flags: u64, ) -> Result<(), MapError> { - let fd = map.fd_or_err()?; + let fd = map.fd; bpf_map_update_elem(fd, Some(key), value, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_update_elem", io_error, @@ -30,7 +30,7 @@ pub(crate) fn insert( } pub(crate) fn remove(map: &MapData, key: &K) -> Result<(), MapError> { - let fd = map.fd_or_err()?; + let fd = map.fd; bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs index 979970cc..7fd90ec0 100644 --- a/aya/src/maps/hash_map/per_cpu_hash_map.rs +++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs @@ -52,8 +52,6 @@ impl, K: Pod, V: Pod> PerCpuHashMap { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; - Ok(PerCpuHashMap { inner: map, _k: PhantomData, @@ -63,7 +61,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { /// Returns a slice of values - one for each CPU - associated with the key. pub fn get(&self, key: &K, flags: u64) -> Result, MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let values = bpf_map_lookup_elem_per_cpu(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", @@ -120,7 +118,7 @@ impl, K: Pod, V: Pod> PerCpuHashMap { values: PerCpuValues, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow_mut().fd_or_err()?; + let fd = self.inner.borrow_mut().fd; bpf_map_update_elem_per_cpu(fd, key.borrow(), &values, flags).map_err( |(_, io_error)| SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/lpm_trie.rs b/aya/src/maps/lpm_trie.rs index 864eb431..d05ec2cf 100644 --- a/aya/src/maps/lpm_trie.rs +++ b/aya/src/maps/lpm_trie.rs @@ -117,8 +117,6 @@ impl, K: Pod, V: Pod> LpmTrie { let data = map.borrow(); check_kv_size::, V>(data)?; - let _ = data.fd_or_err()?; - Ok(LpmTrie { inner: map, _k: PhantomData, @@ -128,7 +126,7 @@ impl, K: Pod, V: Pod> LpmTrie { /// Returns a copy of the value associated with the longest prefix matching key in the LpmTrie. pub fn get(&self, key: &Key, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -157,7 +155,7 @@ impl, K: Pod, V: Pod> LpmTrie { value: impl Borrow, flags: u64, ) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_update_elem(fd, Some(key), value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", @@ -172,7 +170,7 @@ impl, K: Pod, V: Pod> LpmTrie { /// /// Both the prefix and data must match exactly - this method does not do a longest prefix match. pub fn remove(&mut self, key: &Key) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_delete_elem(fd, key) .map(|_| ()) .map_err(|(_, io_error)| { @@ -228,17 +226,24 @@ mod tests { }) } + fn new_map(obj: obj::Map) -> MapData { + override_syscall(|call| match call { + Syscall::Bpf { + cmd: bpf_cmd::BPF_MAP_CREATE, + .. + } => Ok(1337), + call => panic!("unexpected syscall {:?}", call), + }); + MapData::create(obj, "foo", None).unwrap() + } + fn sys_error(value: i32) -> SysResult { Err((-1, io::Error::from_raw_os_error(value))) } #[test] fn test_wrong_key_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; + let map = new_map(new_obj_map()); assert_matches!( LpmTrie::<_, u16, u32>::new(&map), Err(MapError::InvalidKeySize { @@ -250,11 +255,7 @@ mod tests { #[test] fn test_wrong_value_size() { - let map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; + let map = new_map(new_obj_map()); assert_matches!( LpmTrie::<_, u32, u16>::new(&map), Err(MapError::InvalidValueSize { @@ -266,25 +267,21 @@ mod tests { #[test] fn test_try_from_wrong_map() { - let map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { - def: bpf_map_def { - map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, - key_size: 4, - value_size: 4, - max_entries: 1024, - ..Default::default() - }, - section_index: 0, - section_kind: BpfSectionKind::Maps, - symbol_index: None, - data: Vec::new(), - }), - fd: None, - pinned: false, - }; - - let map = Map::PerfEventArray(map_data); + let map = new_map(obj::Map::Legacy(LegacyMap { + def: bpf_map_def { + map_type: BPF_MAP_TYPE_PERF_EVENT_ARRAY as u32, + key_size: 4, + value_size: 4, + max_entries: 1024, + ..Default::default() + }, + section_index: 0, + section_kind: BpfSectionKind::Maps, + symbol_index: None, + data: Vec::new(), + })); + + let map = Map::PerfEventArray(map); assert_matches!( LpmTrie::<_, u32, u32>::try_from(&map), @@ -292,55 +289,30 @@ mod tests { ); } - #[test] - fn test_new_not_created() { - let mut map = MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - }; - - assert_matches!( - LpmTrie::<_, u32, u32>::new(&mut map), - Err(MapError::NotCreated { .. }) - ); - } - #[test] fn test_new_ok() { - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); - assert!(LpmTrie::<_, u32, u32>::new(&mut map).is_ok()); + assert!(LpmTrie::<_, u32, u32>::new(&map).is_ok()); } #[test] fn test_try_from_ok() { - let map_data = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); - let map = Map::LpmTrie(map_data); + let map = Map::LpmTrie(map); assert!(LpmTrie::<_, u32, u32>::try_from(&map).is_ok()) } #[test] fn test_insert_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let mut map = new_map(new_obj_map()); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.insert(&key, 1, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_update_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -349,6 +321,11 @@ mod tests { #[test] fn test_insert_ok() { + let mut map = new_map(new_obj_map()); + let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_UPDATE_ELEM, @@ -357,30 +334,18 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - - let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.insert(&key, 1, 0).is_ok()); } #[test] fn test_remove_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let mut map = new_map(new_obj_map()); let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.remove(&key), Err(MapError::SyscallError(SyscallError { call: "bpf_map_delete_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -389,6 +354,11 @@ mod tests { #[test] fn test_remove_ok() { + let mut map = new_map(new_obj_map()); + let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_DELETE_ELEM, @@ -397,29 +367,18 @@ mod tests { _ => sys_error(EFAULT), }); - let mut map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let mut trie = LpmTrie::<_, u32, u32>::new(&mut map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert!(trie.remove(&key).is_ok()); } #[test] fn test_get_syscall_error() { - override_syscall(|_| sys_error(EFAULT)); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; + let map = new_map(new_obj_map()); let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); let ipaddr = Ipv4Addr::new(8, 8, 8, 8); let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|_| sys_error(EFAULT)); + assert_matches!( trie.get(&key, 0), Err(MapError::SyscallError(SyscallError { call: "bpf_map_lookup_elem", io_error })) if io_error.raw_os_error() == Some(EFAULT) @@ -428,6 +387,11 @@ mod tests { #[test] fn test_get_not_found() { + let map = new_map(new_obj_map()); + let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); + let ipaddr = Ipv4Addr::new(8, 8, 8, 8); + let key = Key::new(16, u32::from(ipaddr).to_be()); + override_syscall(|call| match call { Syscall::Bpf { cmd: bpf_cmd::BPF_MAP_LOOKUP_ELEM, @@ -435,14 +399,6 @@ mod tests { } => sys_error(ENOENT), _ => sys_error(EFAULT), }); - let map = MapData { - obj: new_obj_map(), - fd: Some(42), - pinned: false, - }; - let trie = LpmTrie::<_, u32, u32>::new(&map).unwrap(); - let ipaddr = Ipv4Addr::new(8, 8, 8, 8); - let key = Key::new(16, u32::from(ipaddr).to_be()); assert_matches!(trie.get(&key, 0), Err(MapError::KeyNotFound)); } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 28fd688e..8458989c 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -103,17 +103,6 @@ pub enum MapError { name: String, }, - /// The map has not been created - #[error("the map has not been created")] - NotCreated, - - /// The map has already been created - #[error("the map `{name}` has already been created")] - AlreadyCreated { - /// Map name - name: String, - }, - /// Failed to create map #[error("failed to create map `{name}` with code {code}")] CreateError { @@ -480,7 +469,7 @@ pub(crate) fn check_v_size(map: &MapData) -> Result<(), MapError> { #[derive(Debug)] pub struct MapData { pub(crate) obj: obj::Map, - pub(crate) fd: Option, + pub(crate) fd: RawFd, /// Indicates if this map has been pinned to bpffs pub pinned: bool, } @@ -488,22 +477,18 @@ pub struct MapData { impl MapData { /// Creates a new map with the provided `name` pub fn create( - &mut self, + obj: obj::Map, name: &str, btf_fd: Option>, - ) -> Result { - if self.fd.is_some() { - return Err(MapError::AlreadyCreated { name: name.into() }); - } - + ) -> Result { let c_name = CString::new(name).map_err(|_| MapError::InvalidName { name: name.into() })?; #[cfg(not(test))] let kernel_version = KernelVersion::current().unwrap(); #[cfg(test)] let kernel_version = KernelVersion::new(0xff, 0xff, 0xff); - let fd = bpf_create_map(&c_name, &self.obj, btf_fd, kernel_version).map_err( - |(code, io_error)| { + let fd = + bpf_create_map(&c_name, &obj, btf_fd, kernel_version).map_err(|(code, io_error)| { if kernel_version < KernelVersion::new(5, 11, 0) { maybe_warn_rlimit(); } @@ -513,28 +498,42 @@ impl MapData { code, io_error, } - }, - )?; + })?; - Ok(*self.fd.insert(fd as RawFd)) + Ok(Self { + obj, + fd: fd as RawFd, + pinned: false, + }) } - pub(crate) fn open_pinned>( - &mut self, - name: &str, + pub(crate) fn create_pinned>( path: P, - ) -> Result { - if self.fd.is_some() { - return Err(MapError::AlreadyCreated { name: name.into() }); - } + obj: obj::Map, + name: &str, + btf_fd: Option>, + ) -> Result { + // try to open map in case it's already pinned let map_path = path.as_ref().join(name); let path_string = CString::new(map_path.to_str().unwrap()).unwrap(); - let fd = bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { + match bpf_get_object(&path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_GET", io_error, - })?; - - Ok(*self.fd.insert(fd.into_raw_fd())) + }) { + Ok(fd) => Ok(Self { + obj, + fd: fd.into_raw_fd(), + pinned: false, + }), + Err(_) => { + let mut map = Self::create(obj, name, btf_fd)?; + map.pin(name, path).map_err(|error| MapError::PinError { + name: Some(name.into()), + error, + })?; + Ok(map) + } + } } /// Loads a map from a pinned path in bpffs. @@ -558,7 +557,7 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::ByName), - fd: Some(fd.into_raw_fd()), + fd: fd.into_raw_fd(), pinned: true, }) } @@ -573,59 +572,54 @@ impl MapData { Ok(MapData { obj: parse_map_info(info, PinningType::None), - fd: Some(fd.into_raw_fd()), + fd: fd.into_raw_fd(), pinned: false, }) } - pub(crate) fn fd_or_err(&self) -> Result { - self.fd.ok_or(MapError::NotCreated) - } - pub(crate) fn pin>(&mut self, name: &str, path: P) -> Result<(), PinError> { - if self.pinned { + let Self { fd, pinned, obj: _ } = self; + if *pinned { return Err(PinError::AlreadyPinned { name: name.into() }); } let map_path = path.as_ref().join(name); - let fd = self.fd.ok_or(PinError::NoFd { - name: name.to_string(), - })?; let path_string = CString::new(map_path.to_string_lossy().into_owned()).map_err(|e| { PinError::InvalidPinPath { error: e.to_string(), } })?; - bpf_pin_object(fd, &path_string).map_err(|(_, io_error)| SyscallError { + bpf_pin_object(*fd, &path_string).map_err(|(_, io_error)| SyscallError { call: "BPF_OBJ_PIN", io_error, })?; - self.pinned = true; + *pinned = true; Ok(()) } /// Returns the file descriptor of the map. /// /// Can be converted to [`RawFd`] using [`AsRawFd`]. - pub fn fd(&self) -> Option { - self.fd.map(MapFd) + pub fn fd(&self) -> MapFd { + MapFd(self.fd) } } impl Drop for MapData { fn drop(&mut self) { // TODO: Replace this with an OwnedFd once that is stabilized. - if let Some(fd) = self.fd.take() { - unsafe { libc::close(fd) }; - } + // + // SAFETY: `drop` is only called once. + unsafe { libc::close(self.fd) }; } } impl Clone for MapData { - fn clone(&self) -> MapData { - MapData { - obj: self.obj.clone(), - fd: self.fd.map(|fd| unsafe { libc::dup(fd) }), - pinned: self.pinned, + fn clone(&self) -> Self { + let Self { obj, fd, pinned } = self; + Self { + obj: obj.clone(), + fd: unsafe { libc::dup(*fd) }, + pinned: *pinned, } } } @@ -664,14 +658,7 @@ impl Iterator for MapKeys<'_, K> { return None; } - let fd = match self.map.fd_or_err() { - Ok(fd) => fd, - Err(e) => { - self.err = true; - return Some(Err(e)); - } - }; - + let fd = self.map.fd; let key = bpf_map_get_next_key(fd, self.key.as_ref()).map_err(|(_, io_error)| SyscallError { call: "bpf_map_get_next_key", @@ -854,14 +841,6 @@ mod tests { }) } - fn new_map() -> MapData { - MapData { - obj: new_obj_map(), - fd: None, - pinned: false, - } - } - #[test] fn test_create() { override_syscall(|call| match call { @@ -872,12 +851,13 @@ mod tests { _ => Err((-1, io::Error::from_raw_os_error(EFAULT))), }); - let mut map = new_map(); - assert_matches!(map.create("foo", None), Ok(42)); - assert_eq!(map.fd, Some(42)); assert_matches!( - map.create("foo", None), - Err(MapError::AlreadyCreated { .. }) + MapData::create(new_obj_map(), "foo", None), + Ok(MapData { + obj: _, + fd: 42, + pinned: false + }) ); } @@ -885,19 +865,13 @@ mod tests { fn test_create_failed() { override_syscall(|_| Err((-42, io::Error::from_raw_os_error(EFAULT)))); - let mut map = new_map(); - let ret = map.create("foo", None); - assert_matches!(ret, Err(MapError::CreateError { .. })); - if let Err(MapError::CreateError { - name, - code, - io_error, - }) = ret - { - assert_eq!(name, "foo"); - assert_eq!(code, -42); - assert_eq!(io_error.raw_os_error(), Some(EFAULT)); - } - assert_eq!(map.fd, None); + assert_matches!( + MapData::create(new_obj_map(), "foo", None), + Err(MapError::CreateError { name, code, io_error }) => { + assert_eq!(name, "foo"); + assert_eq!(code, -42); + assert_eq!(io_error.raw_os_error(), Some(EFAULT)); + } + ); } } diff --git a/aya/src/maps/perf/perf_event_array.rs b/aya/src/maps/perf/perf_event_array.rs index 3d6a8103..7d647164 100644 --- a/aya/src/maps/perf/perf_event_array.rs +++ b/aya/src/maps/perf/perf_event_array.rs @@ -162,8 +162,6 @@ pub struct PerfEventArray { impl> PerfEventArray { pub(crate) fn new(map: T) -> Result, MapError> { - let _fd = map.borrow().fd_or_err()?; - Ok(PerfEventArray { map: Arc::new(map), page_size: page_size(), @@ -184,7 +182,7 @@ impl + Borrow> PerfEventArray { // this cannot fail as new() checks that the fd is open let map_data: &MapData = self.map.deref().borrow(); - let map_fd = map_data.fd_or_err().unwrap(); + let map_fd = map_data.fd; let buf = PerfBuffer::open(index, self.page_size, page_count.unwrap_or(2))?; bpf_map_update_elem(map_fd, Some(&index), &buf.as_raw_fd(), 0) .map_err(|(_, io_error)| io_error)?; diff --git a/aya/src/maps/queue.rs b/aya/src/maps/queue.rs index 6b635dcb..78b81ec2 100644 --- a/aya/src/maps/queue.rs +++ b/aya/src/maps/queue.rs @@ -38,8 +38,6 @@ impl, V: Pod> Queue { let data = map.borrow(); check_kv_size::<(), V>(data)?; - let _fd = data.fd_or_err()?; - Ok(Queue { inner: map, _v: PhantomData, @@ -62,7 +60,7 @@ impl, V: Pod> Queue { /// Returns [`MapError::ElementNotFound`] if the queue is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -79,7 +77,7 @@ impl, V: Pod> Queue { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, diff --git a/aya/src/maps/sock/sock_hash.rs b/aya/src/maps/sock/sock_hash.rs index 0e87aa98..1904ec1e 100644 --- a/aya/src/maps/sock/sock_hash.rs +++ b/aya/src/maps/sock/sock_hash.rs @@ -72,7 +72,6 @@ impl, K: Pod> SockHash { pub(crate) fn new(map: T) -> Result, MapError> { let data = map.borrow(); check_kv_size::(data)?; - let _ = data.fd_or_err()?; Ok(SockHash { inner: map, @@ -82,7 +81,7 @@ impl, K: Pod> SockHash { /// Returns the fd of the socket stored at the given key. pub fn get(&self, key: &K, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_lookup_elem", io_error, @@ -107,7 +106,7 @@ impl, K: Pod> SockHash { /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + Ok(SockMapFd(self.inner.borrow().fd)) } } diff --git a/aya/src/maps/sock/sock_map.rs b/aya/src/maps/sock/sock_map.rs index b6877827..52574f23 100644 --- a/aya/src/maps/sock/sock_map.rs +++ b/aya/src/maps/sock/sock_map.rs @@ -49,8 +49,6 @@ impl> SockMap { let data = map.borrow(); check_kv_size::(data)?; - let _fd = data.fd_or_err()?; - Ok(SockMap { inner: map }) } @@ -65,7 +63,7 @@ impl> SockMap { /// The returned file descriptor can be used to attach programs that work with /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb). pub fn fd(&self) -> Result { - Ok(SockMapFd(self.inner.borrow().fd_or_err()?)) + Ok(SockMapFd(self.inner.borrow().fd)) } } @@ -73,7 +71,7 @@ impl> SockMap { /// Stores a socket into the map. pub fn set(&mut self, index: u32, socket: &I, flags: u64) -> Result<(), MapError> { let data = self.inner.borrow_mut(); - let fd = data.fd_or_err()?; + let fd = data.fd; check_bounds(data, index)?; bpf_map_update_elem(fd, Some(&index), &socket.as_raw_fd(), flags).map_err( |(_, io_error)| SyscallError { @@ -87,7 +85,7 @@ impl> SockMap { /// Removes the socket stored at `index` from the map. pub fn clear_index(&mut self, index: &u32) -> Result<(), MapError> { let data = self.inner.borrow_mut(); - let fd = data.fd_or_err()?; + let fd = data.fd; check_bounds(data, *index)?; bpf_map_delete_elem(fd, index) .map(|_| ()) diff --git a/aya/src/maps/stack.rs b/aya/src/maps/stack.rs index 8004e486..0cc9b1d8 100644 --- a/aya/src/maps/stack.rs +++ b/aya/src/maps/stack.rs @@ -38,8 +38,6 @@ impl, V: Pod> Stack { let data = map.borrow(); check_kv_size::<(), V>(data)?; - let _fd = data.fd_or_err()?; - Ok(Stack { inner: map, _v: PhantomData, @@ -62,7 +60,7 @@ impl, V: Pod> Stack { /// Returns [`MapError::ElementNotFound`] if the stack is empty, [`MapError::SyscallError`] /// if `bpf_map_lookup_and_delete_elem` fails. pub fn pop(&mut self, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let value = bpf_map_lookup_and_delete_elem::(fd, None, flags).map_err( |(_, io_error)| SyscallError { @@ -79,7 +77,7 @@ impl, V: Pod> Stack { /// /// [`MapError::SyscallError`] if `bpf_map_update_elem` fails. pub fn push(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; bpf_map_update_elem(fd, None::<&u32>, value.borrow(), flags).map_err(|(_, io_error)| { SyscallError { call: "bpf_map_update_elem", diff --git a/aya/src/maps/stack_trace.rs b/aya/src/maps/stack_trace.rs index 8d3add5a..8f84a09e 100644 --- a/aya/src/maps/stack_trace.rs +++ b/aya/src/maps/stack_trace.rs @@ -89,7 +89,6 @@ impl> StackTraceMap { if size > max_stack_depth * mem::size_of::() { return Err(MapError::InvalidValueSize { size, expected }); } - let _fd = data.fd_or_err()?; Ok(StackTraceMap { inner: map, @@ -104,7 +103,7 @@ impl> StackTraceMap { /// Returns [`MapError::KeyNotFound`] if there is no stack trace with the /// given `stack_id`, or [`MapError::SyscallError`] if `bpf_map_lookup_elem` fails. pub fn get(&self, stack_id: &u32, flags: u64) -> Result { - let fd = self.inner.borrow().fd_or_err()?; + let fd = self.inner.borrow().fd; let mut frames = vec![0; self.max_stack_depth]; bpf_map_lookup_elem_ptr(fd, Some(stack_id), frames.as_mut_ptr(), flags) diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 546bf0c4..23fcf8e3 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -704,8 +704,8 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { let mut insns = copy_instructions(prog).unwrap(); - let mut map_data = MapData { - obj: obj::Map::Legacy(LegacyMap { + let map = MapData::create( + obj::Map::Legacy(LegacyMap { def: bpf_map_def { map_type: bpf_map_type::BPF_MAP_TYPE_ARRAY as u32, key_size: 4, @@ -718,12 +718,12 @@ pub(crate) fn is_bpf_global_data_supported() -> bool { symbol_index: None, data: Vec::new(), }), - fd: None, - pinned: false, - }; + "aya_global", + None, + ); - if let Ok(map_fd) = map_data.create("aya_global", None) { - insns[0].imm = map_fd; + if let Ok(map) = map { + insns[0].imm = map.fd; let gpl = b"GPL\0"; u.license = gpl.as_ptr() as u64; diff --git a/test/integration-test/src/tests/rbpf.rs b/test/integration-test/src/tests/rbpf.rs index 44e648d1..0a85adbf 100644 --- a/test/integration-test/src/tests/rbpf.rs +++ b/test/integration-test/src/tests/rbpf.rs @@ -74,7 +74,7 @@ fn use_map_with_rbpf() { object .relocate_maps( maps.iter() - .map(|(s, (fd, map))| (s.as_ref() as &str, Some(*fd), map)), + .map(|(s, (fd, map))| (s.as_ref() as &str, *fd, map)), &text_sections, ) .expect("Relocation failed"); diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index a2f9d001..574862f4 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -5972,7 +5972,7 @@ impl aya_obj::Object pub fn aya_obj::Object::relocate_btf(&mut self, target_btf: &aya_obj::btf::Btf) -> core::result::Result<(), aya_obj::btf::BtfRelocationError> impl aya_obj::Object pub fn aya_obj::Object::relocate_calls(&mut self, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> -pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator, &'a aya_obj::maps::Map)>>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> +pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> impl core::clone::Clone for aya_obj::Object pub fn aya_obj::Object::clone(&self) -> aya_obj::Object impl core::fmt::Debug for aya_obj::Object @@ -6288,9 +6288,6 @@ pub enum aya_obj::relocation::RelocationError pub aya_obj::relocation::RelocationError::InvalidRelocationOffset pub aya_obj::relocation::RelocationError::InvalidRelocationOffset::offset: u64 pub aya_obj::relocation::RelocationError::InvalidRelocationOffset::relocation_number: usize -pub aya_obj::relocation::RelocationError::MapNotCreated -pub aya_obj::relocation::RelocationError::MapNotCreated::name: alloc::string::String -pub aya_obj::relocation::RelocationError::MapNotCreated::section_index: usize pub aya_obj::relocation::RelocationError::SectionNotFound pub aya_obj::relocation::RelocationError::SectionNotFound::section_index: usize pub aya_obj::relocation::RelocationError::SectionNotFound::symbol_index: usize @@ -6687,7 +6684,7 @@ impl aya_obj::Object pub fn aya_obj::Object::relocate_btf(&mut self, target_btf: &aya_obj::btf::Btf) -> core::result::Result<(), aya_obj::btf::BtfRelocationError> impl aya_obj::Object pub fn aya_obj::Object::relocate_calls(&mut self, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> -pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator, &'a aya_obj::maps::Map)>>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> +pub fn aya_obj::Object::relocate_maps<'a, I: core::iter::traits::iterator::Iterator>(&mut self, maps: I, text_sections: &std::collections::hash::set::HashSet) -> core::result::Result<(), aya_obj::relocation::BpfRelocationError> impl core::clone::Clone for aya_obj::Object pub fn aya_obj::Object::clone(&self) -> aya_obj::Object impl core::fmt::Debug for aya_obj::Object diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 0b2a7374..28813796 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -966,8 +966,6 @@ pub fn aya::maps::Map::borrow_mut(&mut self) -> &mut T impl core::convert::From for aya::maps::Map pub fn aya::maps::Map::from(t: T) -> T pub enum aya::maps::MapError -pub aya::maps::MapError::AlreadyCreated -pub aya::maps::MapError::AlreadyCreated::name: alloc::string::String pub aya::maps::MapError::CreateError pub aya::maps::MapError::CreateError::code: libc::unix::linux_like::linux::gnu::b64::x86_64::not_x32::c_long pub aya::maps::MapError::CreateError::io_error: std::io::error::Error @@ -984,7 +982,6 @@ pub aya::maps::MapError::InvalidValueSize pub aya::maps::MapError::InvalidValueSize::expected: usize pub aya::maps::MapError::InvalidValueSize::size: usize pub aya::maps::MapError::KeyNotFound -pub aya::maps::MapError::NotCreated pub aya::maps::MapError::OutOfBounds pub aya::maps::MapError::OutOfBounds::index: u32 pub aya::maps::MapError::OutOfBounds::max_entries: u32 @@ -1226,12 +1223,12 @@ pub fn aya::maps::lpm_trie::LpmTrie::from(t: T) -> T pub struct aya::maps::MapData pub aya::maps::MapData::pinned: bool impl aya::maps::MapData -pub fn aya::maps::MapData::create(&mut self, name: &str, btf_fd: core::option::Option>) -> core::result::Result -pub fn aya::maps::MapData::fd(&self) -> core::option::Option +pub fn aya::maps::MapData::create(obj: aya_obj::maps::Map, name: &str, btf_fd: core::option::Option>) -> core::result::Result +pub fn aya::maps::MapData::fd(&self) -> aya::maps::MapFd pub fn aya::maps::MapData::from_fd(fd: std::os::fd::owned::OwnedFd) -> core::result::Result pub fn aya::maps::MapData::from_pin>(path: P) -> core::result::Result impl core::clone::Clone for aya::maps::MapData -pub fn aya::maps::MapData::clone(&self) -> aya::maps::MapData +pub fn aya::maps::MapData::clone(&self) -> Self impl core::ops::drop::Drop for aya::maps::MapData pub fn aya::maps::MapData::drop(&mut self) impl core::fmt::Debug for aya::maps::MapData From a31544b6e77d6868d950820ad31fc1fe8ed3666b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 16 Aug 2023 12:20:32 -0400 Subject: [PATCH 40/42] maps: BloomFilter::insert takes &mut self This is consistent with all the other maps. --- aya/src/maps/bloom_filter.rs | 15 ++++++++++----- xtask/public-api/aya.txt | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/aya/src/maps/bloom_filter.rs b/aya/src/maps/bloom_filter.rs index 6fc24ff4..84bff986 100644 --- a/aya/src/maps/bloom_filter.rs +++ b/aya/src/maps/bloom_filter.rs @@ -1,5 +1,8 @@ //! A Bloom Filter. -use std::{borrow::Borrow, marker::PhantomData}; +use std::{ + borrow::{Borrow, BorrowMut}, + marker::PhantomData, +}; use crate::{ maps::{check_v_size, MapData, MapError}, @@ -59,10 +62,12 @@ impl, V: Pod> BloomFilter { .ok_or(MapError::ElementNotFound)?; Ok(()) } +} +impl, V: Pod> BloomFilter { /// Inserts a value into the map. - pub fn insert(&self, value: impl Borrow, flags: u64) -> Result<(), MapError> { - let fd = self.inner.borrow().fd; + pub fn insert(&mut self, value: impl Borrow, flags: u64) -> Result<(), MapError> { + let fd = self.inner.borrow_mut().fd; bpf_map_push_elem(fd, value.borrow(), flags).map_err(|(_, io_error)| SyscallError { call: "bpf_map_push_elem", io_error, @@ -173,7 +178,7 @@ mod tests { #[test] fn test_insert_syscall_error() { let mut map = new_map(new_obj_map()); - let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + let mut bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); override_syscall(|_| sys_error(EFAULT)); @@ -186,7 +191,7 @@ mod tests { #[test] fn test_insert_ok() { let mut map = new_map(new_obj_map()); - let bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); + let mut bloom_filter = BloomFilter::<_, u32>::new(&mut map).unwrap(); override_syscall(|call| match call { Syscall::Bpf { diff --git a/xtask/public-api/aya.txt b/xtask/public-api/aya.txt index 28813796..ebf7699f 100644 --- a/xtask/public-api/aya.txt +++ b/xtask/public-api/aya.txt @@ -126,7 +126,8 @@ pub mod aya::maps::bloom_filter pub struct aya::maps::bloom_filter::BloomFilter impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, flags: u64) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::bloom_filter::BloomFilter::insert(&self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::insert(&mut self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::Error = aya::maps::MapError pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> @@ -1101,7 +1102,8 @@ pub fn aya::maps::perf::AsyncPerfEventArray::from(t: T) -> T pub struct aya::maps::BloomFilter impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter pub fn aya::maps::bloom_filter::BloomFilter::contains(&self, value: &V, flags: u64) -> core::result::Result<(), aya::maps::MapError> -pub fn aya::maps::bloom_filter::BloomFilter::insert(&self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> +impl, V: aya::Pod> aya::maps::bloom_filter::BloomFilter +pub fn aya::maps::bloom_filter::BloomFilter::insert(&mut self, value: impl core::borrow::Borrow, flags: u64) -> core::result::Result<(), aya::maps::MapError> impl<'a, V: aya::Pod> core::convert::TryFrom<&'a aya::maps::Map> for aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V> pub type aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::Error = aya::maps::MapError pub fn aya::maps::bloom_filter::BloomFilter<&'a aya::maps::MapData, V>::try_from(map: &'a aya::maps::Map) -> core::result::Result, aya::maps::MapError> From 9ba0b042076cb97635797ef07f031b45cd164b9e Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Aug 2023 11:03:00 -0400 Subject: [PATCH 41/42] github: use gnubin rather than bespoke symlinks --- .github/workflows/ci.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a078ee35..7d2e941c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,12 +188,18 @@ jobs: - name: Install prerequisites if: runner.os == 'macOS' + # The xargs shipped on macOS always exits 0 with -P0, so we need GNU findutils. + # + # The tar shipped on macOS doesn't support --wildcards, so we need GNU tar. + # # The clang shipped on macOS doesn't support BPF, so we need LLVM from brew. # # We also need LLVM for bpf-linker, see comment below. run: | set -euxo pipefail - brew install findutils qemu dpkg pkg-config llvm + brew install dpkg findutils gnu-tar llvm pkg-config qemu + echo /usr/local/opt/findutils/libexec/gnubin >> $GITHUB_PATH + echo /usr/local/opt/gnu-tar/libexec/gnubin >> $GITHUB_PATH echo /usr/local/opt/llvm/bin >> $GITHUB_PATH - name: bpf-linker @@ -201,11 +207,6 @@ jobs: # NB: rustc doesn't ship libLLVM.so on macOS, so disable proxying (default feature). run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git --no-default-features - - name: Alias gxargs as xargs - if: runner.os == 'macOS' - # macOS xargs always exits 0 with -P0. - run: mkdir xargs-is-gxargs && ln -s "$(which gxargs)" xargs-is-gxargs/xargs && echo "$PWD"/xargs-is-gxargs >> $GITHUB_PATH - - name: Download debian kernels if: runner.arch == 'ARM64' run: | @@ -232,11 +233,6 @@ jobs: linux-image-6.4.0-2-cloud-amd64-unsigned_6.4.4-3_amd64.deb \ | xargs -0 -t -P0 -I {} wget -nd -nv -P test/.tmp/debian-kernels/amd64 ftp://ftp.us.debian.org/debian/pool/main/l/linux/{} - - name: Alias gtar as tar - if: runner.os == 'macOS' - # macOS tar doesn't support --wildcards which we use below. - run: mkdir tar-is-gtar && ln -s "$(which gtar)" tar-is-gtar/tar && echo "$PWD"/tar-is-gtar >> $GITHUB_PATH - - name: Extract debian kernels run: | set -euxo pipefail From 756e6b979a0b473847e48c1de765c1ed6527b2ef Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 18 Aug 2023 10:51:09 -0400 Subject: [PATCH 42/42] github: brew reinstall qemu See https://github.com/Homebrew/homebrew-core/pull/139492. --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d2e941c..fdb8b994 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,7 +197,10 @@ jobs: # We also need LLVM for bpf-linker, see comment below. run: | set -euxo pipefail - brew install dpkg findutils gnu-tar llvm pkg-config qemu + brew update + brew install dpkg findutils gnu-tar llvm pkg-config + # Workaround for https://github.com/Homebrew/homebrew-core/pull/139492. + brew reinstall qemu echo /usr/local/opt/findutils/libexec/gnubin >> $GITHUB_PATH echo /usr/local/opt/gnu-tar/libexec/gnubin >> $GITHUB_PATH echo /usr/local/opt/llvm/bin >> $GITHUB_PATH