Skip to content

Commit 0a3002a

Browse files
d-e-s-oinsearchoflosttime
authored andcommitted
libbpf-rs: Plumb through support for USDT options
When attaching to USDT, users can optionally provide some option struct object that may change the behavior or provide additional data. So far we have not supported doing that in libbpf-rs, but with this change we add such support. Closes: #308 Signed-off-by: Daniel Müller <deso@posteo.net>
1 parent 050408c commit 0a3002a

File tree

5 files changed

+144
-13
lines changed

5 files changed

+144
-13
lines changed

libbpf-rs/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub use crate::map::{Map, MapFlags, MapType, OpenMap};
9797
pub use crate::object::{Object, ObjectBuilder, OpenObject};
9898
pub use crate::perf_buffer::{PerfBuffer, PerfBufferBuilder};
9999
pub use crate::print::{get_print, set_print, PrintCallback, PrintLevel};
100-
pub use crate::program::{OpenProgram, Program, ProgramAttachType, ProgramType};
100+
pub use crate::program::{OpenProgram, Program, ProgramAttachType, ProgramType, UsdtOpts};
101101
pub use crate::ringbuf::{RingBuffer, RingBufferBuilder};
102102
pub use crate::tc::{
103103
TcAttachPoint, TcHook, TcHookBuilder, TC_CUSTOM, TC_EGRESS, TC_H_CLSACT, TC_H_INGRESS,

libbpf-rs/src/program.rs

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::convert::TryFrom;
22
use std::ffi::CStr;
3+
use std::mem;
34
use std::path::Path;
45
use std::ptr;
56

@@ -9,6 +10,28 @@ use strum_macros::Display;
910

1011
use crate::*;
1112

13+
/// Options to optionally be provided when attaching to a USDT.
14+
#[derive(Clone, Debug, Default)]
15+
pub struct UsdtOpts {
16+
/// Custom user-provided value accessible through `bpf_usdt_cookie`.
17+
pub cookie: u64,
18+
#[doc(hidden)]
19+
pub _non_exhaustive: (),
20+
}
21+
22+
impl From<UsdtOpts> for libbpf_sys::bpf_usdt_opts {
23+
fn from(opts: UsdtOpts) -> Self {
24+
let UsdtOpts {
25+
cookie,
26+
_non_exhaustive,
27+
} = opts;
28+
libbpf_sys::bpf_usdt_opts {
29+
sz: mem::size_of::<Self>() as u64,
30+
usdt_cookie: cookie,
31+
}
32+
}
33+
}
34+
1235
/// Represents a parsed but not yet loaded BPF program.
1336
///
1437
/// This object exposes operations that need to happen before the program is loaded.
@@ -488,30 +511,34 @@ impl Program {
488511
}
489512
}
490513

491-
/// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe
492-
/// point. The entry point of the program must be defined with
493-
/// `SEC("usdt")`.
494-
pub fn attach_usdt(
514+
fn attach_usdt_impl(
495515
&mut self,
496516
pid: i32,
497-
binary_path: impl AsRef<Path>,
498-
usdt_provider: impl AsRef<str>,
499-
usdt_name: impl AsRef<str>,
517+
binary_path: &Path,
518+
usdt_provider: &str,
519+
usdt_name: &str,
520+
usdt_opts: Option<UsdtOpts>,
500521
) -> Result<Link> {
501-
let path = util::path_to_cstring(binary_path.as_ref())?;
522+
let path = util::path_to_cstring(binary_path)?;
502523
let path_ptr = path.as_ptr();
503-
let usdt_provider = util::str_to_cstring(usdt_provider.as_ref())?;
524+
let usdt_provider = util::str_to_cstring(usdt_provider)?;
504525
let usdt_provider_ptr = usdt_provider.as_ptr();
505-
let usdt_name = util::str_to_cstring(usdt_name.as_ref())?;
526+
let usdt_name = util::str_to_cstring(usdt_name)?;
506527
let usdt_name_ptr = usdt_name.as_ptr();
528+
let usdt_opts = usdt_opts.map(libbpf_sys::bpf_usdt_opts::from);
529+
let usdt_opts_ptr = usdt_opts
530+
.as_ref()
531+
.map(|opts| opts as *const _)
532+
.unwrap_or_else(ptr::null);
533+
507534
let ptr = unsafe {
508535
libbpf_sys::bpf_program__attach_usdt(
509536
self.ptr,
510537
pid,
511538
path_ptr,
512539
usdt_provider_ptr,
513540
usdt_name_ptr,
514-
ptr::null(),
541+
usdt_opts_ptr,
515542
)
516543
};
517544
let err = unsafe { libbpf_sys::libbpf_get_error(ptr as *const _) };
@@ -522,6 +549,45 @@ impl Program {
522549
}
523550
}
524551

552+
/// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe
553+
/// point. The entry point of the program must be defined with
554+
/// `SEC("usdt")`.
555+
pub fn attach_usdt(
556+
&mut self,
557+
pid: i32,
558+
binary_path: impl AsRef<Path>,
559+
usdt_provider: impl AsRef<str>,
560+
usdt_name: impl AsRef<str>,
561+
) -> Result<Link> {
562+
self.attach_usdt_impl(
563+
pid,
564+
binary_path.as_ref(),
565+
usdt_provider.as_ref(),
566+
usdt_name.as_ref(),
567+
None,
568+
)
569+
}
570+
571+
/// Attach this program to a [USDT](https://lwn.net/Articles/753601/) probe
572+
/// point, providing additional options. The entry point of the program must
573+
/// be defined with `SEC("usdt")`.
574+
pub fn attach_usdt_with_opts(
575+
&mut self,
576+
pid: i32,
577+
binary_path: impl AsRef<Path>,
578+
usdt_provider: impl AsRef<str>,
579+
usdt_name: impl AsRef<str>,
580+
usdt_opts: UsdtOpts,
581+
) -> Result<Link> {
582+
self.attach_usdt_impl(
583+
pid,
584+
binary_path.as_ref(),
585+
usdt_provider.as_ref(),
586+
usdt_name.as_ref(),
587+
Some(usdt_opts),
588+
)
589+
}
590+
525591
/// Returns the number of instructions that form the program.
526592
///
527593
/// Please see note in [`OpenProgram::insn_cnt`].

libbpf-rs/tests/bin/src/usdt.bpf.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,18 @@ int handle__usdt(void *ctx)
2323
return 0;
2424
}
2525

26+
SEC("usdt")
27+
int handle__usdt_with_cookie(void *ctx)
28+
{
29+
int *value;
30+
31+
value = bpf_ringbuf_reserve(&ringbuf, sizeof(int), 0);
32+
if (value) {
33+
*value = bpf_usdt_cookie(ctx);
34+
bpf_ringbuf_submit(value, 0);
35+
}
36+
37+
return 0;
38+
}
39+
2640
char LICENSE[] SEC("license") = "GPL";

libbpf-rs/tests/bin/usdt.bpf.o

-352 Bytes
Binary file not shown.

libbpf-rs/tests/test.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use probe::probe;
1313
use scopeguard::defer;
1414

1515
use libbpf_rs::{
16-
num_possible_cpus, Iter, Map, MapFlags, MapType, Object, ObjectBuilder, OpenObject, ProgramType,
16+
num_possible_cpus, Iter, Map, MapFlags, MapType, Object, ObjectBuilder, OpenObject,
17+
ProgramType, UsdtOpts,
1718
};
1819

1920
fn get_test_object_path(filename: &str) -> PathBuf {
@@ -783,6 +784,56 @@ fn test_object_usdt() {
783784
unsafe { assert_eq!(V, 1) };
784785
}
785786

787+
#[test]
788+
fn test_object_usdt_cookie() {
789+
bump_rlimit_mlock();
790+
791+
let cookie_val = 1337u16;
792+
let mut obj = get_test_object("usdt.bpf.o");
793+
let prog = obj
794+
.prog_mut("handle__usdt_with_cookie")
795+
.expect("Failed to find program");
796+
797+
let path = std::env::current_exe().expect("Failed to find executable name");
798+
let _link = prog
799+
.attach_usdt_with_opts(
800+
unsafe { libc::getpid() },
801+
&path,
802+
"test_provider",
803+
"test_function",
804+
UsdtOpts {
805+
cookie: cookie_val.into(),
806+
..UsdtOpts::default()
807+
},
808+
)
809+
.expect("Failed to attach prog");
810+
811+
let mut builder = libbpf_rs::RingBufferBuilder::new();
812+
let map = obj.map("ringbuf").expect("Failed to get ringbuf map");
813+
814+
static mut V: i32 = 0;
815+
fn callback(data: &[u8]) -> i32 {
816+
let mut value: i32 = 0;
817+
plain::copy_from_bytes(&mut value, data).expect("Wrong size");
818+
819+
unsafe {
820+
V = value;
821+
}
822+
823+
0
824+
}
825+
826+
builder.add(map, callback).expect("Failed to add ringbuf");
827+
let mgr = builder.build().expect("Failed to build");
828+
829+
// Define a USDT probe point and exercise it as we are attaching to self.
830+
probe!(test_provider, test_function, 1);
831+
832+
mgr.consume().expect("Failed to consume ringbuf");
833+
834+
unsafe { assert_eq!(V, cookie_val.into()) };
835+
}
836+
786837
#[test]
787838
fn test_object_map_probes() {
788839
bump_rlimit_mlock();

0 commit comments

Comments
 (0)