From a2651d20a63ded69605ec262d006e4351299e5df Mon Sep 17 00:00:00 2001 From: 0xb10c Date: Wed, 6 Nov 2024 17:39:56 +0100 Subject: [PATCH] update: libbpf-rs 0.23 -> 0.24 This includes a bit of refactoring due to breaking changes. While doing so, I noticed it's possible to only add the maps to the ringbuffer when we actually want to read from them, so I did that. --- Cargo.lock | 151 ++++++++---------------------------------- extractor/Cargo.toml | 4 +- extractor/src/main.rs | 135 ++++++++++++++++++++++++++----------- 3 files changed, 125 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b48e6b..0a1b33a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,9 +404,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -414,6 +417,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clap" version = "4.5.13" @@ -994,20 +1003,16 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libbpf-cargo" -version = "0.23.0" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d230f1634d0ef9f5708bcf644c3644c357ee324649c3001d50ef4250fb3af9df" +checksum = "df118348a241dbaaa2f425856250f0d0c041be172ddbacdbf7b8a08af8dffb0c" dependencies = [ "anyhow", "cargo_metadata", "clap", "libbpf-rs", - "libbpf-sys", "memmap2", - "num_enum", "regex", - "scroll", - "scroll_derive", "semver", "serde", "serde_json", @@ -1016,36 +1021,32 @@ dependencies = [ [[package]] name = "libbpf-rs" -version = "0.23.0" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e289c054443e63d3f09d4ee53044c4311166f3df31b7835a29995a6c3b03c18d" +checksum = "8ca94724a0be3a72789582a9139b2547623b9fc9b40776aba49290303032a285" dependencies = [ "bitflags 2.4.0", "libbpf-sys", "libc", - "num_enum", - "strum_macros", - "thiserror", "vsprintf", ] [[package]] name = "libbpf-sys" -version = "1.4.0+v1.4.0" +version = "1.5.0+v1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ee5f6d35341ad5d492fd92466c45ff11d6e8104ffa8208f62450875c93e258" +checksum = "2d8306b516a70a129cb6afed17c1e51e162d35aadfcc6339364addcebe32de90" dependencies = [ "cc", "nix", - "num_cpus", "pkg-config", ] [[package]] name = "libc" -version = "0.2.147" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" @@ -1126,12 +1127,13 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "nix" -version = "0.27.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.4.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -1161,37 +1163,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num_threads" version = "0.1.7" @@ -1323,16 +1294,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - [[package]] name = "proc-macro2" version = "1.0.84" @@ -1522,12 +1483,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - [[package]] name = "ryu" version = "1.0.15" @@ -1540,23 +1495,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" - -[[package]] -name = "scroll_derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "secp256k1" version = "0.29.0" @@ -1643,6 +1581,12 @@ dependencies = [ "simple_logger", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "simple_logger" version = "5.0.0" @@ -1686,19 +1630,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - [[package]] name = "syn" version = "1.0.109" @@ -1802,23 +1733,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - [[package]] name = "tracing" version = "0.1.40" @@ -2190,12 +2104,3 @@ name = "windows_x86_64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" - -[[package]] -name = "winnow" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" -dependencies = [ - "memchr", -] diff --git a/extractor/Cargo.toml b/extractor/Cargo.toml index 5a7e4e7..e057c58 100644 --- a/extractor/Cargo.toml +++ b/extractor/Cargo.toml @@ -9,10 +9,10 @@ edition = "2021" shared = { path = "../shared" } prost = "0.10" -libbpf-rs = "0.23" +libbpf-rs = "0.24" [build-dependencies] -libbpf-cargo = "0.23" +libbpf-cargo = "0.24" [features] # Treat warnings as a build error. diff --git a/extractor/src/main.rs b/extractor/src/main.rs index 6adb04f..6cb89a1 100644 --- a/extractor/src/main.rs +++ b/extractor/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "strict", deny(warnings))] -use libbpf_rs::skel::SkelBuilder; -use libbpf_rs::RingBufferBuilder; +use libbpf_rs::skel::{OpenSkel, Skel, SkelBuilder}; +use libbpf_rs::{Map, MapCore, Object, ProgramMut, RingBufferBuilder}; use prost::Message; use shared::clap; use shared::clap::Parser; @@ -16,6 +16,7 @@ use shared::log; use shared::nng::{Protocol, Socket}; use shared::simple_logger; use shared::{addrman, mempool, net_conn, net_msg, validation}; +use std::mem::MaybeUninit; use std::time::Duration; use std::time::SystemTime; @@ -151,6 +152,28 @@ struct Args { log_level: log::Level, } +/// Find the BPF program with the given name, panic if it does not exist. +// inspired by https://github.com/libbpf/libbpf-rs/blob/18581bc5fb85bbbfd2c6ca6424a56f7b5d438470/libbpf-rs/tests/common/mod.rs#L70-L77 +// TODO: this currently panics +// We can probably be a bit nicer with the error handling here. +pub fn find_prog_mut<'obj>(object: &'obj Object, name: &str) -> ProgramMut<'obj> { + object + .progs_mut() + .find(|map| map.name() == name) + .unwrap_or_else(|| panic!("failed to find BPF program `{name}`")) +} + +/// Find the BPF map with the given name, panic if it does not exist. +// inspired by https://github.com/libbpf/libbpf-rs/blob/18581bc5fb85bbbfd2c6ca6424a56f7b5d438470/libbpf-rs/tests/common/mod.rs#L63-L68 +// TODO: this currently panics +// We can probably be a bit nicer with the error handling here. +pub fn find_map<'obj>(object: &'obj Object, name: &str) -> Map<'obj> { + object + .maps() + .find(|map| map.name() == name) + .unwrap_or_else(|| panic!("failed to find BPF map `{name}`")) +} + fn main() -> Result<(), libbpf_rs::Error> { let args = Args::parse(); @@ -159,39 +182,102 @@ fn main() -> Result<(), libbpf_rs::Error> { let mut skel_builder = tracing::TracingSkelBuilder::default(); skel_builder.obj_builder.debug(true); - let open_skel: tracing::OpenTracingSkel = skel_builder.open().unwrap(); - let mut obj: libbpf_rs::Object = match open_skel.obj.load() { - Ok(skel) => skel, + let mut uninit = MaybeUninit::uninit(); + // We can probably be a bit nicer with the error handling here. + let open_skel: tracing::OpenTracingSkel = skel_builder.open(&mut uninit).unwrap(); + let skel: tracing::TracingSkel = open_skel.load()?; + let obj = skel.object(); + + let socket: Socket = Socket::new(Protocol::Pub0).unwrap(); + match socket.listen(&args.address) { + Ok(()) => { + log::info!("listening on {}", args.address); + } Err(e) => { - panic!("Could not load skeleton file: {}", e); + panic!("Could not listen on {}: {}", args.address, e); } - }; + } let mut active_tracepoints = vec![]; + let mut ringbuff_builder = RingBufferBuilder::new(); + + // P2P net msgs tracepoints + let map_net_msg_small = find_map(&obj, "net_msg_small"); + let map_net_msg_medium = find_map(&obj, "net_msg_medium"); + let map_net_msg_large = find_map(&obj, "net_msg_large"); + let map_net_msg_huge = find_map(&obj, "net_msg_huge"); if !args.no_p2pmsg_tracepoints { active_tracepoints.extend(&TRACEPOINTS_NET_MESSAGE); + #[cfg_attr(rustfmt, rustfmt_skip)] + ringbuff_builder + .add(&map_net_msg_small, |data| { handle_net_message(data, socket.clone()) })? + .add(&map_net_msg_medium, |data| { handle_net_message(data, socket.clone()) })? + .add(&map_net_msg_large, |data| { handle_net_message(data, socket.clone()) })? + .add(&map_net_msg_huge, |data| { handle_net_message(data, socket.clone()) })?; } + + // P2P connection tracepoints + let map_net_conn_inbound = find_map(&obj, "net_conn_inbound"); + let map_net_conn_outbound = find_map(&obj, "net_conn_outbound"); + let map_net_conn_closed = find_map(&obj, "net_conn_closed"); + let map_net_conn_inbound_evicted = find_map(&obj, "net_conn_inbound_evicted"); + let map_net_conn_misbehaving = find_map(&obj, "net_conn_misbehaving"); if !args.no_connection_tracepoints { active_tracepoints.extend(&TRACEPOINTS_NET_CONN); + #[cfg_attr(rustfmt, rustfmt_skip)] + ringbuff_builder + .add(&map_net_conn_inbound, |data| { handle_net_conn_inbound(data, socket.clone()) })? + .add(&map_net_conn_outbound, |data| { handle_net_conn_outbound(data, socket.clone()) })? + .add(&map_net_conn_closed, |data| { handle_net_conn_closed(data, socket.clone()) })? + .add(&map_net_conn_inbound_evicted, |data| { handle_net_conn_inbound_evicted(data, socket.clone()) })? + .add(&map_net_conn_misbehaving, |data| { handle_net_conn_misbehaving(data, socket.clone()) })?; } + + // validation tracepoints + let map_validation_block_connected = find_map(&obj, "validation_block_connected"); if !args.no_validation_tracepoints { active_tracepoints.extend(&TRACEPOINTS_VALIDATION); + ringbuff_builder.add(&map_validation_block_connected, |data| { + handle_validation_block_connected(data, socket.clone()) + })?; } + + // mempool tracepoints + let map_mempool_added = find_map(&obj, "mempool_added"); + let map_mempool_removed = find_map(&obj, "mempool_removed"); + let map_mempool_rejected = find_map(&obj, "mempool_rejected"); + let map_mempool_replaced = find_map(&obj, "mempool_replaced"); if !args.no_mempool_tracepoints { active_tracepoints.extend(&TRACEPOINTS_MEMPOOL); + #[cfg_attr(rustfmt, rustfmt_skip)] + ringbuff_builder + .add(&map_mempool_added, |data| { handle_mempool_added(data, socket.clone()) })? + .add(&map_mempool_removed, |data| { handle_mempool_removed(data, socket.clone()) })? + .add(&map_mempool_rejected, |data| { handle_mempool_rejected(data, socket.clone()) })? + .add(&map_mempool_replaced, |data| { handle_mempool_replaced(data, socket.clone()) })?; } + // addrman tracepoints + let map_addrman_insert_new = find_map(&obj, "addrman_insert_new"); + let map_addrman_insert_tried = find_map(&obj, "addrman_insert_tried"); if args.addrman_tracepoints { active_tracepoints.extend(&TRACEPOINTS_ADDRMAN); + #[cfg_attr(rustfmt, rustfmt_skip)] + ringbuff_builder + .add(&map_addrman_insert_new, |data| { handle_addrman_new(data, socket.clone()) })? + .add(&map_addrman_insert_tried, |data| { handle_addrman_tried(data, socket.clone()) })?; } if active_tracepoints.is_empty() { log::error!("No tracepoints enabled."); return Ok(()); } - let mut links = Vec::new(); + + // attach tracepoints + let mut _links = Vec::new(); for tracepoint in active_tracepoints { - links.push(obj.prog_mut(tracepoint.function).unwrap().attach_usdt( + let prog = find_prog_mut(&obj, tracepoint.function); + _links.push(prog.attach_usdt( -1, &args.bitcoind_path, tracepoint.context, @@ -199,38 +285,7 @@ fn main() -> Result<(), libbpf_rs::Error> { )?) } - let socket: Socket = Socket::new(Protocol::Pub0).unwrap(); - match socket.listen(&args.address) { - Ok(()) => { - log::info!("listening on {}", args.address); - } - Err(e) => { - panic!("Could not listen on {}: {}", args.address, e); - } - } - - let mut ringbuff_builder = RingBufferBuilder::new(); - - #[cfg_attr(rustfmt, rustfmt_skip)] - ringbuff_builder - .add(obj.map("net_msg_small").unwrap(), |data| { handle_net_message(data, socket.clone()) })? - .add(obj.map("net_msg_medium").unwrap(), |data| { handle_net_message(data, socket.clone()) })? - .add(obj.map("net_msg_large").unwrap(), |data| { handle_net_message(data, socket.clone()) })? - .add(obj.map("net_msg_huge").unwrap(), |data| { handle_net_message(data, socket.clone()) })? - .add(obj.map("net_conn_inbound").unwrap(), |data| { handle_net_conn_inbound(data, socket.clone()) })? - .add(obj.map("net_conn_outbound").unwrap(), |data| { handle_net_conn_outbound(data, socket.clone()) })? - .add(obj.map("net_conn_closed").unwrap(), |data| { handle_net_conn_closed(data, socket.clone()) })? - .add(obj.map("net_conn_inbound_evicted").unwrap(), |data| { handle_net_conn_inbound_evicted(data, socket.clone()) })? - .add(obj.map("net_conn_misbehaving").unwrap(), |data| { handle_net_conn_misbehaving(data, socket.clone()) })? - .add(obj.map("addrman_insert_new").unwrap(), |data| { handle_addrman_new(data, socket.clone()) })? - .add(obj.map("addrman_insert_tried").unwrap(), |data| { handle_addrman_tried(data, socket.clone()) })? - .add(obj.map("mempool_added").unwrap(), |data| { handle_mempool_added(data, socket.clone()) })? - .add(obj.map("mempool_removed").unwrap(), |data| { handle_mempool_removed(data, socket.clone()) })? - .add(obj.map("mempool_rejected").unwrap(), |data| { handle_mempool_rejected(data, socket.clone()) })? - .add(obj.map("mempool_replaced").unwrap(), |data| { handle_mempool_replaced(data, socket.clone()) })? - .add(obj.map("validation_block_connected").unwrap(), |data| { handle_validation_block_connected(data, socket.clone()) })?; let ring_buffers = ringbuff_builder.build()?; - loop { match ring_buffers.poll(Duration::from_millis(1)) { Ok(_) => (),