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}