scx_utils/libbpf_clap_opts.rs
1// Copyright (c) Meta Platforms, Inc. and affiliates.
2
3// This software may be used and distributed according to the terms of the
4// GNU General Public License version 2.
5use clap::Parser;
6use libbpf_rs::libbpf_sys::bpf_object_open_opts;
7use libbpf_rs::libbpf_sys::size_t;
8
9use std::ffi::c_char;
10use std::ffi::CString;
11use std::mem;
12
13#[derive(Debug, Clone, Parser)]
14pub struct LibbpfOpts {
15 /// Parse map definitions non-strictly, allowing extra attributes/data.
16 #[clap(long)]
17 pub relaxed_maps: Option<bool>,
18
19 /// Maps that set the 'pinning' attribute in their definition will have their pin_path
20 /// attribute set to a file in this directory, and be auto-pinned to that path on load;
21 /// defaults to "/sys/fs/bpf".
22 #[clap(long)]
23 pub pin_root_path: Option<String>,
24
25 /// Additional kernel config content that augments and overrides system Kconfig for CONFIG_xxx
26 /// externs.
27 #[clap(long)]
28 pub kconfig: Option<String>,
29
30 /// Path to the custom BTF to be used for BPF CO-RE relocations. This custom BTF completely
31 /// replaces the use of vmlinux BTF for the purpose of CO-RE relocations. NOTE: any other BPF
32 /// feature (e.g., fentry/fexit programs, struct_ops, etc) will need actual kernel BTF at
33 /// /sys/kernel/btf/vmlinux.
34 #[clap(long)]
35 pub btf_custom_path: Option<String>,
36
37 /// Path to BPF FS mount point to derive BPF token from. Created BPF token will be used for
38 /// all bpf() syscall operations that accept BPF token (e.g., map creation, BTF and program
39 /// loads, etc) automatically within instantiated BPF object. If bpf_token_path is not
40 /// specified, libbpf will consult LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will
41 /// be taken as a value of bpf_token_path option and will force libbpf to either create BPF
42 /// token from provided custom BPF FS path, or will disable implicit BPF token creation, if
43 /// envvar value is an empty string. bpf_token_path overrides LIBBPF_BPF_TOKEN_PATH, if both
44 /// are set at the same time. Setting bpf_token_path option to empty string disables libbpf's
45 /// automatic attempt to create BPF token from default BPF FS mount point (/sys/fs/bpf), in
46 /// case this default behavior is undesirable.
47 #[clap(long)]
48 pub bpf_token_path: Option<String>,
49}
50
51impl Default for LibbpfOpts {
52 fn default() -> Self {
53 Self {
54 relaxed_maps: None,
55 pin_root_path: None,
56 kconfig: None,
57 btf_custom_path: None,
58 bpf_token_path: None,
59 }
60 }
61}
62
63impl LibbpfOpts {
64 /// Helper method to convert `LibbpfOpts` into an `Option<bpf_object_open_opts>`.
65 ///
66 /// Returns `Some(bpf_object_open_opts)` if any field in `LibbpfOpts` is set,
67 /// otherwise returns `None`.
68 pub fn into_bpf_open_opts(self) -> Option<bpf_object_open_opts> {
69 if self.relaxed_maps.is_some()
70 || self.pin_root_path.is_some()
71 || self.kconfig.is_some()
72 || self.btf_custom_path.is_some()
73 || self.bpf_token_path.is_some()
74 {
75 let mut opts: bpf_object_open_opts = unsafe { mem::zeroed() };
76 opts.sz = mem::size_of::<bpf_object_open_opts>() as size_t;
77
78 if let Some(relaxed) = self.relaxed_maps {
79 opts.relaxed_maps = relaxed;
80 }
81
82 // Using CString to ensure the strings are null-terminated.
83 // The Box::into_raw() converts the CString into a raw C-style pointer.
84 if let Some(pin_path) = self.pin_root_path {
85 let c_string = CString::new(pin_path).ok()?;
86 let boxed = c_string.into_boxed_c_str();
87 opts.pin_root_path = Box::into_raw(boxed) as *const c_char;
88 }
89
90 if let Some(kconfig_str) = self.kconfig {
91 let file_data = std::fs::read_to_string(kconfig_str).ok()?;
92 let c_string = CString::new(file_data).ok()?;
93 let boxed = c_string.into_boxed_c_str();
94 opts.kconfig = Box::into_raw(boxed) as *const c_char;
95 }
96
97 if let Some(btf_path) = self.btf_custom_path {
98 let c_string = CString::new(btf_path).ok()?;
99 let boxed = c_string.into_boxed_c_str();
100 opts.btf_custom_path = Box::into_raw(boxed) as *const c_char;
101 }
102
103 if let Some(token_path) = self.bpf_token_path {
104 let c_string = CString::new(token_path).ok()?;
105 let boxed = c_string.into_boxed_c_str();
106 opts.bpf_token_path = Box::into_raw(boxed) as *const c_char;
107 }
108
109 Some(opts)
110 } else {
111 None
112 }
113 }
114}