Skip to content

Commit

Permalink
Preflight checks for BTF support (#1120)
Browse files Browse the repository at this point in the history
If any dependency is missing, we *abort* with a message explaining what's missing.

Checks include:
- BPF support (using the existing kernel version heuristic)
- BTF symbols availability (either from kernel or files as copied from libbpf)
- RingBuffer availability
- tracepoint BPF program type

Co-authored-by: Dmitrii Dolgov <[email protected]>
  • Loading branch information
ovalenti and erthalion authored Apr 26, 2023
1 parent 830df86 commit a7d03a7
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 7 deletions.
3 changes: 3 additions & 0 deletions ansible/group_vars/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ runtime_command: docker
runtime_as_root: false
runtime_socket: /var/run/docker.sock

excluded_pairs:
- ['ubuntu-1804-lts', 'core_bpf']

virtual_machines:
rhel:
project: rhel-cloud
Expand Down
3 changes: 2 additions & 1 deletion ansible/roles/create-vm/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
loop_control:
loop_var: gcp_zone
register: instance_result
when: not condition
when: >
not condition and [vm_family, vm_collection_method] not in excluded_pairs
vars:
condition: "{{ (instance_result | default({'changed': false})).changed }}"

Expand Down
2 changes: 1 addition & 1 deletion collector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ else()
target_link_libraries(collector_lib libprotobuf.a libcares.a)
endif()

target_link_libraries(collector_lib z ssl crypto curl)
target_link_libraries(collector_lib z ssl crypto curl bpf)

add_executable(collector collector.cpp)
target_link_libraries(collector collector_lib)
Expand Down
40 changes: 35 additions & 5 deletions collector/lib/HostHeuristics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,42 @@ class Heuristic {
};

class CollectionHeuristic : public Heuristic {
// If we're configured to use eBPF but the host we're running on
// does not support it, we can try to use kernel modules instead.
// The exception to this is COS, where third party modules are not
// supported, so there is nothing we can do and must exit.
void Process(HostInfo& host, const CollectorConfig& config, HostConfig* hconfig) const {
if (config.UseEbpf() && !host.HasEBPFSupport()) {
// If we're configured to use eBPF with BTF, we try to be conservative
// and fail instead of falling-back to other methods.
if (config.GetCollectionMethod() == CORE_BPF) {
if (!host.HasEBPFSupport()) {
CLOG(FATAL) << host.GetDistro() << " " << host.GetKernelVersion().release
<< " does not support eBPF, which is a requirement for core_bpf collection. "
<< "HINT: You may want to use kernel module based collection "
<< "with collector.collectionMethod=KERNEL_MODULE.";
}

if (!host.HasBTFSymbols()) {
CLOG(FATAL) << "Missing BTF symbols, core_bpf is not available. "
<< "They can be provided by the kernel when configured with DEBUG_INFO_BTF, "
<< "or as file. "
<< "HINT: You may alternatively want to use eBPF based collection "
<< "with collector.collectionMethod=EBPF.";
;
}

if (!host.HasBPFRingBufferSupport()) {
CLOG(FATAL) << "Missing RingBuffer support, core_bpf is not available. "
<< "HINT: You may alternatively want to use eBPF based collection "
<< "with collector.collectionMethod=EBPF.";
}

if (!host.HasBPFTracingSupport()) {
CLOG(FATAL) << "Missing BPF tracepoint support.";
}
}

// If we're configured to use eBPF but the host we're running on
// does not support it, we can try to use kernel modules instead.
// The exception to this is COS, where third party modules are not
// supported, so there is nothing we can do and must exit.
if ((config.GetCollectionMethod() == EBPF) && !host.HasEBPFSupport()) {
if (host.IsCOS()) {
CLOG(FATAL) << host.GetDistro() << " does not support third-party kernel modules or the required eBPF features.";
}
Expand Down
69 changes: 69 additions & 0 deletions collector/lib/HostInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ You should have received a copy of the GNU General Public License along with thi

#include <fstream>

#include <bpf/libbpf.h>
#include <linux/bpf.h>

#include "Logging.h"

namespace collector {
Expand Down Expand Up @@ -179,6 +182,72 @@ bool HostInfo::HasEBPFSupport() {
return collector::hasEBPFSupport(kernel, GetOSID());
}

bool HostInfo::HasBTFSymbols() {
// This list is taken from libbpf
const char* locations[] = {
/* try canonical vmlinux BTF through sysfs first */
"/sys/kernel/btf/vmlinux",
/* fall back to trying to find vmlinux on disk otherwise */
"/boot/vmlinux-%1$s",
"/lib/modules/%1$s/vmlinux-%1$s",
"/lib/modules/%1$s/build/vmlinux",
"/usr/lib/modules/%1$s/kernel/vmlinux",
"/usr/lib/debug/boot/vmlinux-%1$s",
"/usr/lib/debug/boot/vmlinux-%1$s.debug",
"/usr/lib/debug/lib/modules/%1$s/vmlinux",
0};

char path[PATH_MAX + 1];
const char* const* location;

for (location = locations; *location; location++) {
snprintf(path, PATH_MAX, *location, kernel_version_.release.c_str());
std::string host_path = GetHostPath(path);

if (faccessat(AT_FDCWD, host_path.c_str(), R_OK, AT_EACCESS) == 0) {
CLOG(DEBUG) << "BTF symbols found in " << host_path;
return true;

} else {
if (errno == ENOTDIR || errno == ENOENT) {
CLOG(DEBUG) << host_path << " does not exist";
} else {
CLOG(WARNING) << "Unable to access " << host_path << ": " << StrError();
}
}
}

CLOG(DEBUG) << "Unable to find BTF symbols in any of the usual locations.";

return false;
}

bool HostInfo::HasBPFRingBufferSupport() {
int res;

res = libbpf_probe_bpf_map_type(BPF_MAP_TYPE_RINGBUF, NULL);

if (res < 0) {
CLOG(WARNING) << "Unable to check for the BPF RingBuffer availability. "
<< "Assuming it is available.";
}

return res != 0;
}

bool HostInfo::HasBPFTracingSupport() {
int res;

res = libbpf_probe_bpf_prog_type(BPF_PROG_TYPE_TRACING, NULL);

if (res < 0) {
CLOG(WARNING) << "Unable to check for the BPF tracepoint program type support. "
<< "Assuming it is available.";
}

return res != 0;
}

bool HostInfo::IsUEFI() {
struct stat sb;
std::string efi_path = GetHostPath("/sys/firmware/efi");
Expand Down
9 changes: 9 additions & 0 deletions collector/lib/HostInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ class HostInfo {
// not support eBPF)
bool HasEBPFSupport();

// Search for a source of BTF symbols (similar to what libbpf does)
bool HasBTFSymbols();

// Check for RingBuffer support, which is required by the modern probe.
bool HasBPFRingBufferSupport();

// Check for BPF tracepoint program type support
bool HasBPFTracingSupport();

// The system was booted in UEFI mode.
virtual bool IsUEFI();

Expand Down

0 comments on commit a7d03a7

Please sign in to comment.