0
0
Fork 0
mirror of https://github.com/netdata/netdata.git synced 2025-04-28 06:32:30 +00:00

eBPF unittest + bug fix ()

This commit is contained in:
thiagoftsm 2023-06-12 14:35:21 +00:00 committed by GitHub
parent 3e30218863
commit 132e31ce9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 180 additions and 21 deletions

View file

@ -620,6 +620,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
collectors/ebpf.plugin/ebpf_apps.h
collectors/ebpf.plugin/ebpf_cgroup.c
collectors/ebpf.plugin/ebpf_cgroup.h
collectors/ebpf.plugin/ebpf_unittest.c
collectors/ebpf.plugin/ebpf_unittest.h
)
set(PROC_PLUGIN_FILES

View file

@ -360,6 +360,8 @@ EBPF_PLUGIN_FILES = \
collectors/ebpf.plugin/ebpf_apps.h \
collectors/ebpf.plugin/ebpf_cgroup.c \
collectors/ebpf.plugin/ebpf_cgroup.h \
collectors/ebpf.plugin/ebpf_unittest.c \
collectors/ebpf.plugin/ebpf_unittest.h \
$(LIBNETDATA_FILES) \
$(NULL)

View file

@ -6,6 +6,7 @@
#include "ebpf.h"
#include "ebpf_socket.h"
#include "ebpf_unittest.h"
#include "libnetdata/required_dummies.h"
/*****************************************************************
@ -578,7 +579,7 @@ static void ebpf_exit()
* @param objects objects loaded from eBPF programs
* @param probe_links links from loader
*/
static void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links)
void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links)
{
if (!probe_links || !objects)
return;
@ -2059,6 +2060,48 @@ static inline void ebpf_load_thread_config()
}
}
/**
* Check Conditions
*
* This function checks kernel that plugin is running and permissions.
*
* @return It returns 0 on success and -1 otherwise
*/
int ebpf_check_conditions()
{
if (!has_condition_to_run(running_on_kernel)) {
error("The current collector cannot run on this kernel.");
return -1;
}
if (!am_i_running_as_root()) {
error(
"ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
(unsigned int)getuid(), (unsigned int)geteuid());
return -1;
}
return 0;
}
/**
* Adjust memory
*
* Adjust memory values to load eBPF programs.
*
* @return It returns 0 on success and -1 otherwise
*/
int ebpf_adjust_memory_limit()
{
struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
if (setrlimit(RLIMIT_MEMLOCK, &r)) {
error("Setrlimit(RLIMIT_MEMLOCK)");
return -1;
}
return 0;
}
/**
* Parse arguments given from user.
*
@ -2097,6 +2140,7 @@ static void ebpf_parse_args(int argc, char **argv)
{"return", no_argument, 0, 0 },
{"legacy", no_argument, 0, 0 },
{"core", no_argument, 0, 0 },
{"unittest", no_argument, 0, 0 },
{0, 0, 0, 0}
};
@ -2287,6 +2331,33 @@ static void ebpf_parse_args(int argc, char **argv)
#endif
break;
}
case EBPF_OPTION_UNITTEST: {
// if we cannot run until the end, we will cancel the unittest
int exit_code = ECANCELED;
if (ebpf_check_conditions())
goto unittest;
if (ebpf_adjust_memory_limit())
goto unittest;
// Load binary in entry mode
ebpf_ut_initialize_structure(MODE_ENTRY);
if (ebpf_ut_load_real_binary())
goto unittest;
ebpf_ut_cleanup_memory();
// Do not load a binary in entry mode
ebpf_ut_initialize_structure(MODE_ENTRY);
if (ebpf_ut_load_fake_binary())
goto unittest;
ebpf_ut_cleanup_memory();
exit_code = 0;
unittest:
exit(exit_code);
}
default: {
break;
}
@ -2505,17 +2576,8 @@ int main(int argc, char **argv)
ebpf_parse_args(argc, argv);
ebpf_manage_pid(getpid());
if (!has_condition_to_run(running_on_kernel)) {
error("The current collector cannot run on this kernel.");
if (ebpf_check_conditions())
return 2;
}
if (!am_i_running_as_root()) {
error(
"ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
(unsigned int)getuid(), (unsigned int)geteuid());
return 3;
}
// set name
program_name = "ebpf.plugin";
@ -2527,11 +2589,8 @@ int main(int argc, char **argv)
error_log_errors_per_period = 100;
error_log_throttle_period = 3600;
struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
if (setrlimit(RLIMIT_MEMLOCK, &r)) {
error("Setrlimit(RLIMIT_MEMLOCK)");
return 4;
}
if (ebpf_adjust_memory_limit())
return 3;
signal(SIGINT, ebpf_stop_threads);
signal(SIGQUIT, ebpf_stop_threads);

View file

@ -119,7 +119,8 @@ enum ebpf_main_index {
EBPF_OPTION_GLOBAL_CHART,
EBPF_OPTION_RETURN_MODE,
EBPF_OPTION_LEGACY,
EBPF_OPTION_CORE
EBPF_OPTION_CORE,
EBPF_OPTION_UNITTEST
};
typedef struct ebpf_tracepoint {
@ -308,6 +309,8 @@ void ebpf_write_chart_obsolete(char *type, char *id, char *title, char *units, c
void write_histogram_chart(char *family, char *name, const netdata_idx_t *hist, char **dimensions, uint32_t end);
void ebpf_update_disabled_plugin_stats(ebpf_module_t *em);
ARAL *ebpf_allocate_pid_aral(char *name, size_t size);
void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links);
extern ebpf_filesystem_partitions_t localfs[];
extern ebpf_sync_syscalls_t local_syscalls[];
extern int ebpf_exit_plugin;

View file

@ -1265,8 +1265,7 @@ void *ebpf_process_thread(void *ptr)
set_local_pointers();
em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
if (!em->probe_links) {
pthread_mutex_unlock(&lock);
goto endprocess;
em->enabled = em->global_charts = em->apps_charts = em->cgroup_charts = NETDATA_THREAD_EBPF_STOPPING;
}
int algorithms[NETDATA_KEY_PUBLISH_PROCESS_END] = {
@ -1295,7 +1294,6 @@ void *ebpf_process_thread(void *ptr)
process_collector(em);
endprocess:
pthread_mutex_lock(&ebpf_exit_cleanup);
if (em->enabled == NETDATA_THREAD_EBPF_RUNNING)
ebpf_update_disabled_plugin_stats(em);

View file

@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "ebpf_unittest.h"
ebpf_module_t test_em;
/**
* Initialize structure
*
* Initialize structure used to run unittests
*/
void ebpf_ut_initialize_structure(netdata_run_mode_t mode)
{
memset(&test_em, 0, sizeof(ebpf_module_t));
test_em.thread_name = strdupz("process");
test_em.config_name = test_em.thread_name;
test_em.kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 |
NETDATA_V5_14;
test_em.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE;
test_em.apps_level = NETDATA_APPS_LEVEL_REAL_PARENT;
test_em.mode = mode;
}
/**
* Clean UP Memory
*
* Clean up allocated data during unit test;
*/
void ebpf_ut_cleanup_memory()
{
freez((void *)test_em.thread_name);
}
/**
* Load Binary
*
* Test load of legacy eBPF programs.
*
* @return It returns 0 on success and -1 otherwise.
*/
static int ebpf_ut_load_binary()
{
test_em.probe_links = ebpf_load_program(ebpf_plugin_dir, &test_em, running_on_kernel, isrh, &test_em.objects);
if (!test_em.probe_links)
return -1;
ebpf_unload_legacy_code(test_em.objects, test_em.probe_links);
return 0;
}
/**
* Load Real Binary
*
* Load an existent binary inside plugin directory.
*
* @return It returns 0 on success and -1 otherwise.
*/
int ebpf_ut_load_real_binary()
{
return ebpf_ut_load_binary();
}
/**
* Load fake Binary
*
* Try to load a binary not generated by netdata.
*
* @return It returns 0 on success and -1 otherwise. The success for this function means we could work properly with
* expected fails.
*/
int ebpf_ut_load_fake_binary()
{
const char *original = test_em.thread_name;
test_em.thread_name = strdupz("I_am_not_here");
int ret = ebpf_ut_load_binary();
ebpf_ut_cleanup_memory();
test_em.thread_name = original;
return !ret;
}

View file

@ -0,0 +1,10 @@
#ifndef NETDATA_EBPF_PLUGIN_UNITTEST_H_
# define NETDATA_EBPF_PLUGIN_UNITTEST_H_ 1
#include "ebpf.h"
void ebpf_ut_initialize_structure(netdata_run_mode_t mode);
int ebpf_ut_load_real_binary();
int ebpf_ut_load_fake_binary();
void ebpf_ut_cleanup_memory();
#endif

View file

@ -856,8 +856,10 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, int kv
em->load |= EBPF_LOAD_LEGACY;
*obj = bpf_object__open_file(lpath, NULL);
if (!*obj)
return NULL;
if (libbpf_get_error(obj)) {
error("Cannot open BPF object %s", lpath);
bpf_object__close(*obj);
return NULL;
}