-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(libebpfdiscoveryskel): Add sending BPF logging events to userspace #42
Changes from 4 commits
c5167b4
a399576
839faa6
7215b6e
9235857
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,41 @@ | ||||||
// SPDX-License-Identifier: Apache-2.0 | ||||||
#pragma once | ||||||
|
||||||
#include "Config.h" | ||||||
#include "DiscoveryBpf.h" | ||||||
#include "ebpfdiscoveryshared/Types.h" | ||||||
|
||||||
#include <bpf/libbpf.h> | ||||||
|
||||||
#include <atomic> | ||||||
#include <thread> | ||||||
|
||||||
namespace ebpfdiscovery { | ||||||
|
||||||
class DiscoveryBpfLogHandler { | ||||||
public: | ||||||
DiscoveryBpfLogHandler(DiscoveryBpf discoveryBpf, const DiscoveryConfig config); | ||||||
DiscoveryBpfLogHandler(const DiscoveryBpfLogHandler&) = delete; | ||||||
DiscoveryBpfLogHandler(DiscoveryBpfLogHandler&&) = delete; | ||||||
DiscoveryBpfLogHandler& operator=(const DiscoveryBpfLogHandler&) = default; | ||||||
DiscoveryBpfLogHandler& operator=(DiscoveryBpfLogHandler&&) = delete; | ||||||
~DiscoveryBpfLogHandler() = default; | ||||||
hparzych marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
void start(); | ||||||
void stop(); | ||||||
void wait(); | ||||||
|
||||||
DiscoveryConfig config; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
DiscoveryBpf discoveryBpf; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
private: | ||||||
void run(); | ||||||
|
||||||
std::atomic<bool> running{false}; | ||||||
std::atomic<bool> stopReceived{false}; | ||||||
std::thread workerThread; | ||||||
|
||||||
struct perf_buffer* logPb; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this to |
||||||
}; | ||||||
|
||||||
} // namespace ebpfdiscovery |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
#include "ebpfdiscovery/DiscoveryBpfLogHandler.h" | ||
|
||
#include <bpf/libbpf.h> | ||
|
||
#include "ebpfdiscoveryshared/Types.h" | ||
#include "logging/Logger.h" | ||
|
||
namespace ebpfdiscovery { | ||
|
||
logging::LogLevel severityToLogLevel(const DiscoveryLogLevel severity) { | ||
switch (severity) { | ||
case DISCOVERY_LOG_LEVEL_TRACE: | ||
return logging::LogLevel::Trace; | ||
case DISCOVERY_LOG_LEVEL_DEBUG: | ||
return logging::LogLevel::Debug; | ||
case DISCOVERY_LOG_LEVEL_INFO: | ||
return logging::LogLevel::Info; | ||
case DISCOVERY_LOG_LEVEL_WARN: | ||
return logging::LogLevel::Warn; | ||
case DISCOVERY_LOG_LEVEL_ERROR: | ||
return logging::LogLevel::Err; | ||
case DISCOVERY_LOG_LEVEL_CRITICAL: | ||
return logging::LogLevel::Critical; | ||
case DISCOVERY_LOG_LEVEL_OFF: | ||
return logging::LogLevel::Off; | ||
} | ||
return logging::LogLevel::Off; | ||
} | ||
|
||
static void handleLogEvent(const DiscoveryLogEvent* event) { | ||
const logging::LogLevel level{severityToLogLevel(event->severity)}; | ||
hparzych marked this conversation as resolved.
Show resolved
Hide resolved
|
||
std::string message(DISCOVERY_LOG_MAX_MESSAGE_LENGTH, '\0'); | ||
hparzych marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const int resultLength{snprintf( | ||
hparzych marked this conversation as resolved.
Show resolved
Hide resolved
|
||
message.data(), | ||
message.size() + 1, | ||
event->format, | ||
event->args[0], | ||
event->args[1], | ||
event->args[2], | ||
event->args[3], | ||
event->args[4], | ||
event->args[5], | ||
event->args[6], | ||
event->args[7])}; | ||
if (resultLength < 0) { | ||
LOG_DEBUG("Failed to format BPF log message."); | ||
return; | ||
} | ||
logging::Logger::getInstance().log(level, "[BPF] [{}] [{}] [{}] {}", event->timestamp, event->pidTgid >> 32, event->cpuId, message); | ||
}; | ||
|
||
static void handlePerfLogEvent(void* ctx, int cpu, void* data, __u32 dataSize) { | ||
if (dataSize < sizeof(DiscoveryLogEvent)) { | ||
LOG_TRACE( | ||
"Received event on BPF log per buffer with unexpected data size. (received: {}, expected at least: {})", | ||
dataSize, | ||
sizeof(DiscoveryLogEvent)); | ||
return; | ||
} | ||
|
||
handleLogEvent(static_cast<DiscoveryLogEvent*>(data)); | ||
} | ||
|
||
static void handlePerfLogLostEvents(void* ctx, int cpu, __u64 lostEventsCount) { | ||
LOG_DEBUG("{} BPF logging events have been lost.", lostEventsCount); | ||
} | ||
|
||
DiscoveryBpfLogHandler::DiscoveryBpfLogHandler(DiscoveryBpf discoveryBpf, const DiscoveryConfig config) | ||
: config(config), discoveryBpf(discoveryBpf) { | ||
} | ||
|
||
void DiscoveryBpfLogHandler::start() { | ||
if (running) { | ||
return; | ||
} | ||
running = true; | ||
|
||
logPb = perf_buffer__new( | ||
bpf_map__fd(discoveryBpf.skel->maps.logEventsPerfMap), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. discoveryBpf is not synchronized across threads. Is it safe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After discussion we're going to refactor this so that we pass the map itself to BpfLogHandler instead of skel. |
||
config.logPerfBufferPages, | ||
handlePerfLogEvent, | ||
handlePerfLogLostEvents, | ||
nullptr, | ||
nullptr); | ||
if (logPb == nullptr) { | ||
throw std::runtime_error("Could not open perf buffer: " + std::to_string(-errno)); | ||
} | ||
|
||
workerThread = std::thread([&]() { run(); }); | ||
} | ||
|
||
void DiscoveryBpfLogHandler::run() { | ||
if (logPb == nullptr) { | ||
return; | ||
} | ||
|
||
LOG_TRACE("Discovery BPF log event handler loop is starting."); | ||
int err{0}; | ||
while (!stopReceived) { | ||
err = perf_buffer__poll(logPb, config.logPerfPollInterval.count()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. config is not synchronized |
||
if (err < 0 && errno != -EINTR) { | ||
LOG_ERROR("Error polling BPF perf buffer for logging: {}", std::strerror(-err)); | ||
break; | ||
} | ||
} | ||
|
||
LOG_TRACE("Discovery BPF log event handler loop has finished running."); | ||
perf_buffer__free(logPb); | ||
} | ||
|
||
void DiscoveryBpfLogHandler::stop() { | ||
stopReceived = true; | ||
} | ||
|
||
void DiscoveryBpfLogHandler::wait() { | ||
if (workerThread.joinable()) { | ||
workerThread.join(); | ||
} | ||
} | ||
|
||
} // namespace ebpfdiscovery |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,3 +28,13 @@ __attribute__((always_inline)) inline static bool dataProbeIsBeginningOfHttpRequ | |
return len >= DISCOVERY_MIN_HTTP_REQUEST_LENGTH && | ||
(dataProbeEqualToString(ptr, "GET /", 5) == 5 || dataProbeEqualToString(ptr, "POST /", 6) == 6); | ||
} | ||
|
||
__attribute__((always_inline)) inline static int dataCopyString(const char* src, char* dest, size_t len) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't it be possible to use strcpy? |
||
for (size_t i = 0; i < len; ++i) { | ||
if (src[i] == '\0') { | ||
return i + 1; | ||
} | ||
dest[i] = src[i]; | ||
} | ||
return len; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#pragma once | ||
|
||
#include "vmlinux.h" | ||
|
||
#include <bpf/bpf_core_read.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
struct trace_event_raw_bpf_trace_printk___log {}; | ||
|
||
#define DEBUG_PRINTLN(fmt, ...) \ | ||
({ \ | ||
static char newFmt[] = "[ebpf-discovery] " fmt "\0"; \ | ||
if (bpf_core_type_exists(struct trace_event_raw_bpf_trace_printk___log)) { \ | ||
bpf_trace_printk(newFmt, sizeof(newFmt) - 1, ##__VA_ARGS__); \ | ||
} else { \ | ||
newFmt[sizeof(newFmt) - 2] = '\n'; \ | ||
bpf_trace_printk(newFmt, sizeof(newFmt), ##__VA_ARGS__); \ | ||
} \ | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.