Skip to main content

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::CString;
10use std::ffi::c_char;
11use std::mem;
12
13#[derive(Debug, Clone, Parser, Default)]
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 LibbpfOpts {
52    /// Helper method to convert `LibbpfOpts` into an `Option<bpf_object_open_opts>`.
53    ///
54    /// Returns `Some(bpf_object_open_opts)` if any field in `LibbpfOpts` is set,
55    /// otherwise returns `None`.
56    pub fn into_bpf_open_opts(self) -> Option<bpf_object_open_opts> {
57        if self.relaxed_maps.is_some()
58            || self.pin_root_path.is_some()
59            || self.kconfig.is_some()
60            || self.btf_custom_path.is_some()
61            || self.bpf_token_path.is_some()
62        {
63            let mut opts: bpf_object_open_opts = unsafe { mem::zeroed() };
64            opts.sz = mem::size_of::<bpf_object_open_opts>() as size_t;
65
66            if let Some(relaxed) = self.relaxed_maps {
67                opts.relaxed_maps = relaxed;
68            }
69
70            // Using CString to ensure the strings are null-terminated.
71            // The Box::into_raw() converts the CString into a raw C-style pointer.
72            if let Some(pin_path) = self.pin_root_path {
73                let c_string = CString::new(pin_path).ok()?;
74                let boxed = c_string.into_boxed_c_str();
75                opts.pin_root_path = Box::into_raw(boxed) as *const c_char;
76            }
77
78            if let Some(kconfig_str) = self.kconfig {
79                let file_data = std::fs::read_to_string(kconfig_str).ok()?;
80                let c_string = CString::new(file_data).ok()?;
81                let boxed = c_string.into_boxed_c_str();
82                opts.kconfig = Box::into_raw(boxed) as *const c_char;
83            }
84
85            if let Some(btf_path) = self.btf_custom_path {
86                let c_string = CString::new(btf_path).ok()?;
87                let boxed = c_string.into_boxed_c_str();
88                opts.btf_custom_path = Box::into_raw(boxed) as *const c_char;
89            }
90
91            if let Some(token_path) = self.bpf_token_path {
92                let c_string = CString::new(token_path).ok()?;
93                let boxed = c_string.into_boxed_c_str();
94                opts.bpf_token_path = Box::into_raw(boxed) as *const c_char;
95            }
96
97            Some(opts)
98        } else {
99            None
100        }
101    }
102}