summaryrefslogtreecommitdiffstats
path: root/collectors/ebpf.plugin
diff options
context:
space:
mode:
authorthiagoftsm <thiagoftsm@gmail.com>2023-06-12 14:35:21 +0000
committerGitHub <noreply@github.com>2023-06-12 14:35:21 +0000
commit132e31ce9e9a56c40c481071ee8993a0607508cc (patch)
treedf8f3a3ca95833f2d5a67ac77f1380070f73ef62 /collectors/ebpf.plugin
parent3e302188637fca7dc1fc676e5672d14730efbd84 (diff)
eBPF unittest + bug fix (#15146)
Diffstat (limited to 'collectors/ebpf.plugin')
-rw-r--r--collectors/ebpf.plugin/ebpf.c91
-rw-r--r--collectors/ebpf.plugin/ebpf.h5
-rw-r--r--collectors/ebpf.plugin/ebpf_process.c4
-rw-r--r--collectors/ebpf.plugin/ebpf_unittest.c83
-rw-r--r--collectors/ebpf.plugin/ebpf_unittest.h10
5 files changed, 173 insertions, 20 deletions
diff --git a/collectors/ebpf.plugin/ebpf.c b/collectors/ebpf.plugin/ebpf.c
index ea53a3ba59..45303574fa 100644
--- a/collectors/ebpf.plugin/ebpf.c
+++ b/collectors/ebpf.plugin/ebpf.c
@@ -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;
@@ -2060,6 +2061,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.
*
* @param argc the number of arguments
@@ -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);
diff --git a/collectors/ebpf.plugin/ebpf.h b/collectors/ebpf.plugin/ebpf.h
index f9a19233c3..ae24c302c5 100644
--- a/collectors/ebpf.plugin/ebpf.h
+++ b/collectors/ebpf.plugin/ebpf.h
@@ -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;
diff --git a/collectors/ebpf.plugin/ebpf_process.c b/collectors/ebpf.plugin/ebpf_process.c
index 2878dbe2db..17a9809d3c 100644
--- a/collectors/ebpf.plugin/ebpf_process.c
+++ b/collectors/ebpf.plugin/ebpf_process.c
@@ -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);
diff --git a/collectors/ebpf.plugin/ebpf_unittest.c b/collectors/ebpf.plugin/ebpf_unittest.c
new file mode 100644
index 0000000000..3e1443ad37
--- /dev/null
+++ b/collectors/ebpf.plugin/ebpf_unittest.c
@@ -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;
+}
diff --git a/collectors/ebpf.plugin/ebpf_unittest.h b/collectors/ebpf.plugin/ebpf_unittest.h
new file mode 100644
index 0000000000..429cbe6288
--- /dev/null
+++ b/collectors/ebpf.plugin/ebpf_unittest.h
@@ -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