From 366015dd1ef8589a69a3bd054288a76f04195191 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Wed, 22 Oct 2025 10:10:38 +0200 Subject: [PATCH 1/3] fix(fact-ebpf): improve kernel compatibility In the context of ROX-30439, I started testing fact on some RHCOS versions and found some issues that are addressed by this PR, namely: * The relocation of kernfs_node for the renamed parent field was wrong, causing cgroups to not be captured correctly. * Some missing null checks that are not necessary on newer kernels. * path_unlink LSM hook is not allowed to call bpf_d_path on older kernels. This last point is the most involved part of the PR, I couldn't find a precise way to check if this call is allowed on the running kernel, so instead I created a small checks BPF object that can try to load a small probe and check if the load was successful, then use a constant loaded at runtime to exclude the call when needed. --- fact-ebpf/build.rs | 56 +++++++++++++---------- fact-ebpf/src/bpf/bound_path.h | 16 ++++++- fact-ebpf/src/bpf/checks.c | 15 ++++++ fact-ebpf/src/bpf/d_path.h | 81 +++++++++++++++++++++++++++++++++ fact-ebpf/src/bpf/events.h | 6 +++ fact-ebpf/src/bpf/file.h | 67 +-------------------------- fact-ebpf/src/bpf/main.c | 18 ++++++-- fact-ebpf/src/bpf/maps.h | 7 ++- fact-ebpf/src/bpf/process.h | 15 ++---- fact-ebpf/src/lib.rs | 1 + fact/src/bpf/checks.rs | 26 +++++++++++ fact/src/{bpf.rs => bpf/mod.rs} | 20 ++++++-- fact/src/event/process.rs | 42 +++++++++++++++++ fact/src/lib.rs | 7 ++- 14 files changed, 263 insertions(+), 114 deletions(-) create mode 100644 fact-ebpf/src/bpf/checks.c create mode 100644 fact-ebpf/src/bpf/d_path.h create mode 100644 fact/src/bpf/checks.rs rename fact/src/{bpf.rs => bpf/mod.rs} (95%) diff --git a/fact-ebpf/build.rs b/fact-ebpf/build.rs index b22d6194..b9c35887 100644 --- a/fact-ebpf/build.rs +++ b/fact-ebpf/build.rs @@ -6,35 +6,41 @@ use std::{ }; fn compile_bpf(out_dir: &Path) -> anyhow::Result<()> { - let obj = match out_dir.join("main.o").into_os_string().into_string() { - Ok(s) => s, - Err(os_string) => anyhow::bail!("Failed to convert path to string {:?}", os_string), - }; - let target_arch = format!("-D__TARGET_ARCH_{}", env::var("CARGO_CFG_TARGET_ARCH")?); + let base_args = [ + "-target", + "bpf", + "-O2", + "-g", + "-c", + "-Wall", + "-Werror", + &target_arch, + ]; + + for name in ["main", "checks"] { + let obj = match out_dir + .join(format!("{name}.o")) + .into_os_string() + .into_string() + { + Ok(s) => s, + Err(os_string) => anyhow::bail!("Failed to convert path to string {:?}", os_string), + }; - match Command::new("clang") - .args([ - "-target", - "bpf", - "-O2", - "-g", - "-c", - "-Wall", - "-Werror", - &target_arch, - "src/bpf/main.c", - "-o", - &obj, - ]) - .status() - { - Ok(status) => { - if !status.success() { - anyhow::bail!("Failed to compile eBPF. See stderr for details."); + match Command::new("clang") + .args(base_args) + .arg(format!("src/bpf/{name}.c")) + .args(["-o", &obj]) + .status() + { + Ok(status) => { + if !status.success() { + anyhow::bail!("Failed to compile eBPF. See stderr for details."); + } } + Err(e) => anyhow::bail!("Failed to execute clang: {}", e), } - Err(e) => anyhow::bail!("Failed to execute clang: {}", e), } Ok(()) } diff --git a/fact-ebpf/src/bpf/bound_path.h b/fact-ebpf/src/bpf/bound_path.h index 3dbe7efc..c222a8ac 100644 --- a/fact-ebpf/src/bpf/bound_path.h +++ b/fact-ebpf/src/bpf/bound_path.h @@ -3,6 +3,7 @@ // clang-format off #include "types.h" #include "maps.h" +#include "d_path.h" #include "vmlinux.h" @@ -21,10 +22,13 @@ __always_inline static void path_write_char(char* p, unsigned int offset, char c *path_safe_access(p, offset) = c; } -__always_inline static struct bound_path_t* path_read(struct path* path) { +__always_inline static struct bound_path_t* _path_read(struct path* path, bool use_bpf_d_path) { struct bound_path_t* bound_path = get_bound_path(); + if (bound_path == NULL) { + return NULL; + } - bound_path->len = bpf_d_path(path, bound_path->path, PATH_MAX); + bound_path->len = use_bpf_d_path ? bpf_d_path(path, bound_path->path, PATH_MAX) : d_path(path, bound_path->path, PATH_MAX); if (bound_path->len <= 0) { return NULL; } @@ -35,6 +39,14 @@ __always_inline static struct bound_path_t* path_read(struct path* path) { return bound_path; } +__always_inline static struct bound_path_t* path_read(struct path* path) { + return _path_read(path, true); +} + +__always_inline static struct bound_path_t* path_read_alternate(struct path* path) { + return _path_read(path, false); +} + enum path_append_status_t { PATH_APPEND_SUCCESS = 0, PATH_APPEND_INVALID_LENGTH, diff --git a/fact-ebpf/src/bpf/checks.c b/fact-ebpf/src/bpf/checks.c new file mode 100644 index 00000000..1b3623a2 --- /dev/null +++ b/fact-ebpf/src/bpf/checks.c @@ -0,0 +1,15 @@ +// clang-format off +#include "vmlinux.h" + +#include "bound_path.h" + +#include +#include +// clang-format on + +SEC("lsm/path_unlink") +int BPF_PROG(check_path_unlink_supports_bpf_d_path, struct path* dir, struct dentry* dentry) { + struct bound_path_t* p = path_read(dir); + bpf_printk("dir: %s", p->path); + return 0; +} diff --git a/fact-ebpf/src/bpf/d_path.h b/fact-ebpf/src/bpf/d_path.h new file mode 100644 index 00000000..53269a4c --- /dev/null +++ b/fact-ebpf/src/bpf/d_path.h @@ -0,0 +1,81 @@ +#pragma once + +// clang-format off +#include "maps.h" +#include "vmlinux.h" + +#include +#include +// clang-format on + +/** + * Reimplementation of the kernel d_path function. + * + * We should attempt to use bpf_d_path when possible, but you can't on + * values that have been read using the bpf_probe_* helpers. + */ +__always_inline static long d_path(const struct path* path, char* buf, int buflen) { + if (buflen <= 0) { + return -1; + } + + struct helper_t* helper = get_helper(); + if (helper == NULL) { + return -1; + } + + struct task_struct* task = (struct task_struct*)bpf_get_current_task(); + int offset = (buflen - 1) & (PATH_MAX - 1); + helper->buf[offset] = '\0'; // Ensure null termination + + struct path root; + BPF_CORE_READ_INTO(&root, task, fs, root); + struct mount* mnt = container_of(path->mnt, struct mount, mnt); + struct dentry* dentry = BPF_CORE_READ(path, dentry); + + for (int i = 0; i < 16 && (dentry != root.dentry || &mnt->mnt != root.mnt); i++) { + struct dentry* parent = BPF_CORE_READ(dentry, d_parent); + struct dentry* mnt_root = BPF_CORE_READ(mnt, mnt.mnt_root); + + if (dentry == mnt_root) { + struct mount* m = BPF_CORE_READ(mnt, mnt_parent); + if (m != mnt) { + dentry = BPF_CORE_READ(mnt, mnt_mountpoint); + mnt = m; + continue; + } + break; + } + + if (dentry == parent) { + return -1; + } + + struct qstr d_name; + BPF_CORE_READ_INTO(&d_name, dentry, d_name); + int len = d_name.len; + if (len <= 0 || len >= buflen) { + return -1; + } + + offset -= len; + if (offset <= 0) { + return -1; + } + + if (bpf_probe_read_kernel(&helper->buf[offset], len, d_name.name) != 0) { + return -1; + } + + offset--; + if (offset <= 0) { + return -1; + } + helper->buf[offset] = '/'; + + dentry = parent; + } + + bpf_probe_read_str(buf, buflen, &helper->buf[offset]); + return buflen - offset; +} diff --git a/fact-ebpf/src/bpf/events.h b/fact-ebpf/src/bpf/events.h index 38395132..a15c18fa 100644 --- a/fact-ebpf/src/bpf/events.h +++ b/fact-ebpf/src/bpf/events.h @@ -1,3 +1,5 @@ +#pragma once + #include #include "maps.h" @@ -17,6 +19,10 @@ __always_inline static void submit_event(struct metrics_by_hook_t* m, file_activ bpf_probe_read_str(event->filename, PATH_MAX, filename); struct helper_t* helper = get_helper(); + if (helper == NULL) { + goto error; + } + const char* p = get_host_path(helper->buf, dentry); if (p != NULL) { bpf_probe_read_str(event->host_file, PATH_MAX, p); diff --git a/fact-ebpf/src/bpf/file.h b/fact-ebpf/src/bpf/file.h index 1e3516c4..5edbbc36 100644 --- a/fact-ebpf/src/bpf/file.h +++ b/fact-ebpf/src/bpf/file.h @@ -5,6 +5,7 @@ #include "bound_path.h" #include "builtins.h" +#include "d_path.h" #include "types.h" #include "maps.h" @@ -12,72 +13,6 @@ #include // clang-format on -/** - * Reimplementation of the kernel d_path function. - * - * We should attempt to use bpf_d_path when possible, but you can't on - * values that have been read using the bpf_probe_* helpers. - */ -__always_inline static char* d_path(const struct path* path, char* buf, int buflen) { - if (buflen <= 0) { - return NULL; - } - - struct task_struct* task = (struct task_struct*)bpf_get_current_task(); - int offset = (buflen - 1) & (PATH_MAX - 1); - buf[offset] = '\0'; // Ensure null termination - - struct path root; - BPF_CORE_READ_INTO(&root, task, fs, root); - struct mount* mnt = container_of(path->mnt, struct mount, mnt); - struct dentry* dentry = BPF_CORE_READ(path, dentry); - - for (int i = 0; i < 16 && (dentry != root.dentry || &mnt->mnt != root.mnt); i++) { - struct dentry* parent = BPF_CORE_READ(dentry, d_parent); - struct dentry* mnt_root = BPF_CORE_READ(mnt, mnt.mnt_root); - - if (dentry == mnt_root) { - struct mount* m = BPF_CORE_READ(mnt, mnt_parent); - if (m != mnt) { - dentry = BPF_CORE_READ(mnt, mnt_mountpoint); - mnt = m; - continue; - } - return &buf[offset]; - } - - if (dentry == parent) { - return NULL; - } - - struct qstr d_name; - BPF_CORE_READ_INTO(&d_name, dentry, d_name); - int len = d_name.len; - if (len <= 0 || len >= buflen) { - return NULL; - } - - offset -= len; - if (offset <= 0) { - return NULL; - } - - if (bpf_probe_read_kernel(&buf[offset], len, d_name.name) != 0) { - return NULL; - } - - offset--; - if (offset <= 0) { - return NULL; - } - buf[offset] = '/'; - - dentry = parent; - } - - return &buf[offset]; -} - __always_inline static char* get_host_path(char buf[PATH_MAX * 2], struct dentry* d) { int offset = PATH_MAX - 1; buf[PATH_MAX - 1] = '\0'; diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 8a05e389..373588ed 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -1,4 +1,6 @@ // clang-format off +#include "vmlinux.h" + #include "file.h" #include "types.h" #include "process.h" @@ -6,8 +8,6 @@ #include "events.h" #include "bound_path.h" -#include "vmlinux.h" - #include #include #include @@ -22,6 +22,9 @@ char _license[] SEC("license") = "Dual MIT/GPL"; SEC("lsm/file_open") int BPF_PROG(trace_file_open, struct file* file) { struct metrics_t* m = get_metrics(); + if (m == NULL) { + return 0; + } m->file_open.total++; @@ -58,10 +61,19 @@ int BPF_PROG(trace_file_open, struct file* file) { SEC("lsm/path_unlink") int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { struct metrics_t* m = get_metrics(); + if (m == NULL) { + return 0; + } m->path_unlink.total++; - struct bound_path_t* path = path_read(dir); + struct bound_path_t* path = NULL; + if (path_unlink_supports_bpf_d_path) { + path = path_read(dir); + } else { + path = path_read_alternate(dir); + } + if (path == NULL) { bpf_printk("Failed to read path"); goto error; diff --git a/fact-ebpf/src/bpf/maps.h b/fact-ebpf/src/bpf/maps.h index 3a3d20a6..dc46f819 100644 --- a/fact-ebpf/src/bpf/maps.h +++ b/fact-ebpf/src/bpf/maps.h @@ -38,7 +38,10 @@ struct { __always_inline static bool filter_by_prefix() { unsigned int zero = 0; char* res = bpf_map_lookup_elem(&filter_by_prefix_map, &zero); - return *res != 0; + + // The NULL check is simply here to satisfy some verifiers, the result + // will never actually be NULL. + return res == NULL || *res != 0; } struct { @@ -82,6 +85,7 @@ __always_inline static struct bound_path_t* get_bound_path() { struct { __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 8 * 1024 * 1024); } rb SEC(".maps"); struct { @@ -97,5 +101,6 @@ __always_inline static struct metrics_t* get_metrics() { } uint64_t host_mount_ns; +volatile const bool path_unlink_supports_bpf_d_path; // clang-format on diff --git a/fact-ebpf/src/bpf/process.h b/fact-ebpf/src/bpf/process.h index 0032d3b2..c54aafcf 100644 --- a/fact-ebpf/src/bpf/process.h +++ b/fact-ebpf/src/bpf/process.h @@ -32,9 +32,10 @@ __always_inline static const char* get_memory_cgroup(struct helper_t* helper) { if (bpf_core_field_exists(kn->__parent)) { kn = BPF_CORE_READ(kn, __parent); } else { - struct { + struct kernfs_node___pre6_15 { struct kernfs_node* parent; - }* kn_old = (void*)kn; + }; + struct kernfs_node___pre6_15* kn_old = (void*)kn; kn = BPF_CORE_READ(kn_old, parent); } if (kn == NULL) { @@ -91,8 +92,7 @@ __always_inline static void process_fill_lineage(process_t* p, struct helper_t* p->lineage[i].uid = BPF_CORE_READ(task, cred, uid.val); BPF_CORE_READ_INTO(&path, task, mm, exe_file, f_path); - char* exe_path = d_path(&path, helper->buf, PATH_MAX); - bpf_probe_read_kernel_str(p->lineage[i].exe_path, PATH_MAX, exe_path); + d_path(&path, p->lineage[i].exe_path, PATH_MAX); p->lineage_len++; } } @@ -137,12 +137,7 @@ __always_inline static int64_t process_fill(process_t* p) { struct path path; BPF_CORE_READ_INTO(&path, task, mm, exe_file, f_path); - const char* exe_path = d_path(&path, helper->buf, PATH_MAX); - if (exe_path == NULL) { - bpf_printk("failed to get exe_path"); - return -1; - } - bpf_probe_read_str(p->exe_path, PATH_MAX, exe_path); + d_path(&path, p->exe_path, PATH_MAX); const char* cg = get_memory_cgroup(helper); if (cg != NULL) { diff --git a/fact-ebpf/src/lib.rs b/fact-ebpf/src/lib.rs index 210683d1..da25ef83 100644 --- a/fact-ebpf/src/lib.rs +++ b/fact-ebpf/src/lib.rs @@ -88,3 +88,4 @@ impl metrics_t { unsafe impl Pod for metrics_t {} pub const EBPF_OBJ: &[u8] = aya::include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.o")); +pub const CHECKS_OBJ: &[u8] = aya::include_bytes_aligned!(concat!(env!("OUT_DIR"), "/checks.o")); diff --git a/fact/src/bpf/checks.rs b/fact/src/bpf/checks.rs new file mode 100644 index 00000000..238cf306 --- /dev/null +++ b/fact/src/bpf/checks.rs @@ -0,0 +1,26 @@ +use anyhow::Context; +use aya::{programs::Lsm, Btf}; +use log::debug; + +pub(super) struct Checks { + pub(super) path_unlink_supports_bpf_d_path: bool, +} + +impl Checks { + pub(super) fn new(btf: &Btf) -> anyhow::Result { + let mut obj = aya::EbpfLoader::new() + .load(fact_ebpf::CHECKS_OBJ) + .context("Failed to load checks.o")?; + + let prog = obj + .program_mut("check_path_unlink_supports_bpf_d_path") + .context("Failed to find 'check_path_unlink_supports_bpf_d_path' program")?; + let prog: &mut Lsm = prog.try_into()?; + let path_unlink_supports_bpf_d_path = prog.load("path_unlink", btf).is_ok(); + debug!("path_unlink_supports_bpf_d_path: {path_unlink_supports_bpf_d_path}"); + + Ok(Checks { + path_unlink_supports_bpf_d_path, + }) + } +} diff --git a/fact/src/bpf.rs b/fact/src/bpf/mod.rs similarity index 95% rename from fact/src/bpf.rs rename to fact/src/bpf/mod.rs index b1b24e44..3b6e27ec 100644 --- a/fact/src/bpf.rs +++ b/fact/src/bpf/mod.rs @@ -6,6 +6,7 @@ use aya::{ programs::Lsm, Btf, Ebpf, }; +use checks::Checks; use libc::c_char; use log::{debug, error, info}; use tokio::{ @@ -18,6 +19,8 @@ use crate::{event::Event, host_info, metrics::EventCounter}; use fact_ebpf::{event_t, metrics_t, path_prefix_t, LPM_SIZE_MAX}; +mod checks; + const RINGBUFFER_NAME: &str = "rb"; pub struct Bpf { @@ -36,10 +39,18 @@ impl Bpf { ) -> anyhow::Result { Bpf::bump_memlock_rlimit()?; + let btf = Btf::from_sys_fs()?; + let checks = Checks::new(&btf)?; + // Include the BPF object as raw bytes at compile-time and load it // at runtime. let obj = aya::EbpfLoader::new() .set_global("host_mount_ns", &host_info::get_host_mount_ns(), true) + .set_global( + "path_unlink_supports_bpf_d_path", + &(checks.path_unlink_supports_bpf_d_path as u8), + true, + ) .set_max_entries(RINGBUFFER_NAME, ringbuf_size * 1024) .load(fact_ebpf::EBPF_OBJ)?; @@ -53,7 +64,7 @@ impl Bpf { }; bpf.load_paths()?; - bpf.load_progs()?; + bpf.load_progs(&btf)?; Ok(bpf) } @@ -136,10 +147,9 @@ impl Bpf { Ok(()) } - fn load_progs(&mut self) -> anyhow::Result<()> { - let btf = Btf::from_sys_fs()?; - self.load_lsm_prog("trace_file_open", "file_open", &btf)?; - self.load_lsm_prog("trace_path_unlink", "path_unlink", &btf) + fn load_progs(&mut self, btf: &Btf) -> anyhow::Result<()> { + self.load_lsm_prog("trace_file_open", "file_open", btf)?; + self.load_lsm_prog("trace_path_unlink", "path_unlink", btf) } fn attach_progs(&mut self) -> anyhow::Result<()> { diff --git a/fact/src/event/process.rs b/fact/src/event/process.rs index 67e1056d..bda63d34 100644 --- a/fact/src/event/process.rs +++ b/fact/src/event/process.rs @@ -228,3 +228,45 @@ impl From for fact_api::ProcessSignal { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn extract_container_id() { + let tests = [ + ("", None), + ("init.scope", None), + ( + "/docker/951e643e3c241b225b6284ef2b79a37c13fc64cbf65b5d46bda95fcb98fe63a4", + Some("951e643e3c24".to_string()), + ), + ( + "/kubepods/kubepods/besteffort/pod690705f9-df6e-11e9-8dc5-025000000001/c3bfd81b7da0be97190a74a7d459f4dfa18f57c88765cde2613af112020a1c4b", + Some("c3bfd81b7da0".to_string()), + ), + ( + "/kubepods/burstable/pod7cd3dba6-e475-11e9-8f99-42010a8a00d2/2bc55a8cae1704a733ba5d785d146bbed9610483380507cbf00c96b32bb637e1", + Some("2bc55a8cae17".to_string()), + ), + ( + "/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podce705797_e47e_11e9_bd71_42010a000002.slice/docker-6525e65814a99d431b6978e8f8c895013176c6c58173b56639d4b020c14e6022.scope", + Some("6525e65814a9".to_string()), + ), + ( + "/machine.slice/libpod-b6e375cfe46efa5cd90d095603dec2de888c28b203285819233040b5cf1212ac.scope/container", + Some("b6e375cfe46e".to_string()), + ), + ( + "/machine.slice/libpod-cbdfa0f1f08763b1963c30d98e11e1f052cb67f1e9b7c0ab8a6ca6c70cbcad69.scope/container/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-pod6eab3b7b_f0a6_4bb8_bff2_d5bc9017c04b.slice/cri-containerd-5ebf11e02dbde102cda4b76bc0e3849a65f9edac7a12bdabfd34db01b9556101.scope", + Some("5ebf11e02dbd".to_string()), + ), + ]; + + for (input, expected) in tests { + let id = Process::extract_container_id(input); + assert_eq!(id, expected); + } + } +} diff --git a/fact/src/lib.rs b/fact/src/lib.rs index 7d07c584..d198f67a 100644 --- a/fact/src/lib.rs +++ b/fact/src/lib.rs @@ -98,8 +98,11 @@ pub async fn run(config: FactConfig) -> anyhow::Result<()> { _ = sigterm.recv() => break, _ = sighup.recv() => config_trigger.notify_one(), res = bpf_handle.borrow_mut() => { - if let Err(e) = res { - warn!("BPF worker errored out: {e}"); + match res { + Ok(res) => if let Err(e) = res { + warn!("BPF worker errored out: {e:?}"); + } + Err(e) => warn!("BPF task errored out: {e:?}"), } break; } From 85e17ef8bc0bc239af9a2f96c47b4ef566b397a4 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 31 Oct 2025 15:06:18 +0100 Subject: [PATCH 2/3] Rename path_read_alternate to path_read_no_d_path --- fact-ebpf/src/bpf/bound_path.h | 2 +- fact-ebpf/src/bpf/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fact-ebpf/src/bpf/bound_path.h b/fact-ebpf/src/bpf/bound_path.h index c222a8ac..1a18c275 100644 --- a/fact-ebpf/src/bpf/bound_path.h +++ b/fact-ebpf/src/bpf/bound_path.h @@ -43,7 +43,7 @@ __always_inline static struct bound_path_t* path_read(struct path* path) { return _path_read(path, true); } -__always_inline static struct bound_path_t* path_read_alternate(struct path* path) { +__always_inline static struct bound_path_t* path_read_no_d_path(struct path* path) { return _path_read(path, false); } diff --git a/fact-ebpf/src/bpf/main.c b/fact-ebpf/src/bpf/main.c index 373588ed..42533507 100644 --- a/fact-ebpf/src/bpf/main.c +++ b/fact-ebpf/src/bpf/main.c @@ -71,7 +71,7 @@ int BPF_PROG(trace_path_unlink, struct path* dir, struct dentry* dentry) { if (path_unlink_supports_bpf_d_path) { path = path_read(dir); } else { - path = path_read_alternate(dir); + path = path_read_no_d_path(dir); } if (path == NULL) { From b801e9189f0f588d0f5a37e9fc15c3ef97a7a5c5 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 17 Nov 2025 12:24:23 +0100 Subject: [PATCH 3/3] Add small comment on filter_by_prefix_map usage --- fact-ebpf/src/bpf/maps.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fact-ebpf/src/bpf/maps.h b/fact-ebpf/src/bpf/maps.h index dc46f819..0e9ae4c5 100644 --- a/fact-ebpf/src/bpf/maps.h +++ b/fact-ebpf/src/bpf/maps.h @@ -27,6 +27,10 @@ __always_inline static struct helper_t* get_helper() { return bpf_map_lookup_elem(&helper_map, &zero); } +/** + * A map with a single entry, determining whether prefix filtering + * should be done based on the `path_prefix` map. + */ struct { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, __u32);