summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libnetdata/config/appconfig.c26
-rw-r--r--libnetdata/config/appconfig.h1
-rw-r--r--libnetdata/ebpf/ebpf.c392
-rw-r--r--libnetdata/ebpf/ebpf.h76
-rw-r--r--libnetdata/json/jsmn.c2
-rw-r--r--libnetdata/libnetdata.h7
-rw-r--r--libnetdata/log/log.h2
-rw-r--r--libnetdata/procfile/procfile.c4
-rw-r--r--libnetdata/socket/security.c1
-rw-r--r--libnetdata/storage_number/storage_number.c18
-rw-r--r--libnetdata/storage_number/storage_number.h17
-rw-r--r--libnetdata/storage_number/tests/test_storage_number.c2
12 files changed, 485 insertions, 63 deletions
diff --git a/libnetdata/config/appconfig.c b/libnetdata/config/appconfig.c
index 6e4df2d09..37e9e7688 100644
--- a/libnetdata/config/appconfig.c
+++ b/libnetdata/config/appconfig.c
@@ -225,6 +225,31 @@ void appconfig_section_destroy_non_loaded(struct config *root, const char *secti
error("Cannot remove section '%s' from config.", section);
return;
}
+
+ appconfig_wrlock(root);
+
+ if (root->first_section == co) {
+ root->first_section = co->next;
+
+ if (root->last_section == co)
+ root->last_section = root->first_section;
+ } else {
+ struct section *co_cur = root->first_section, *co_prev = NULL;
+
+ while(co_cur && co_cur != co) {
+ co_prev = co_cur;
+ co_cur = co_cur->next;
+ }
+
+ if (co_cur) {
+ co_prev->next = co_cur->next;
+
+ if (root->last_section == co_cur)
+ root->last_section = co_prev;
+ }
+ }
+
+ appconfig_unlock(root);
avl_destroy_lock(&co->values_index);
freez(co->name);
@@ -771,6 +796,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
|| !strcmp(co->name, CONFIG_SECTION_BACKEND)
|| !strcmp(co->name, CONFIG_SECTION_STREAM)
|| !strcmp(co->name, CONFIG_SECTION_HOST_LABEL)
+ || !strcmp(co->name, CONFIG_SECTION_ML)
)
pri = 0;
else if(!strncmp(co->name, "plugin:", 7)) pri = 1;
diff --git a/libnetdata/config/appconfig.h b/libnetdata/config/appconfig.h
index 246d1d5b9..bfc927353 100644
--- a/libnetdata/config/appconfig.h
+++ b/libnetdata/config/appconfig.h
@@ -91,6 +91,7 @@
#define CONFIG_SECTION_HEALTH "health"
#define CONFIG_SECTION_BACKEND "backend"
#define CONFIG_SECTION_STREAM "stream"
+#define CONFIG_SECTION_ML "ml"
#define CONFIG_SECTION_EXPORTING "exporting:global"
#define CONFIG_SECTION_PROMETHEUS "prometheus:exporter"
#define CONFIG_SECTION_HOST_LABEL "host labels"
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c
index 1f71f6a24..1ccaa7b41 100644
--- a/libnetdata/ebpf/ebpf.c
+++ b/libnetdata/ebpf/ebpf.c
@@ -64,13 +64,19 @@ int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr)
//----------------------------------------------------------------------------------------------------------------------
-int get_kernel_version(char *out, int size)
+/**
+ * Get Kernel version
+ *
+ * Get the current kernel from /proc and returns an integer value representing it
+ *
+ * @return it returns a value representing the kernel version.
+ */
+int ebpf_get_kernel_version()
{
char major[16], minor[16], patch[16];
char ver[VERSION_STRING_LEN];
char *version = ver;
- out[0] = '\0';
int fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
if (fd < 0)
return -1;
@@ -104,10 +110,6 @@ int get_kernel_version(char *out, int size)
*move++ = *version++;
*move = '\0';
- fd = snprintf(out, (size_t)size, "%s.%s.%s", major, minor, patch);
- if (fd > size)
- error("The buffer to store kernel version is not smaller than necessary.");
-
return ((int)(str2l(major) * 65536) + (int)(str2l(minor) * 256) + (int)str2l(patch));
}
@@ -272,14 +274,24 @@ char *ebpf_kernel_suffix(int version, int isrh)
//----------------------------------------------------------------------------------------------------------------------
-int ebpf_update_kernel(ebpf_data_t *ed)
+/**
+ * Update Kernel
+ *
+ * Update string used to load eBPF programs
+ *
+ * @param ks vector to store the value
+ * @param length available length to store kernel
+ * @param isrh Is a Red Hat distribution?
+ * @param version the kernel version
+ */
+void ebpf_update_kernel(char *ks, size_t length, int isrh, int version)
{
- char *kernel = ebpf_kernel_suffix(ed->running_on_kernel, (ed->isrh < 0) ? 0 : 1);
- size_t length = strlen(kernel);
- strncpyz(ed->kernel_string, kernel, length);
- ed->kernel_string[length] = '\0';
-
- return 0;
+ char *kernel = ebpf_kernel_suffix(version, (isrh < 0) ? 0 : 1);
+ size_t len = strlen(kernel);
+ if (len > length)
+ len = length - 1;
+ strncpyz(ks, kernel, len);
+ ks[len] = '\0';
}
static int select_file(char *name, const char *program, size_t length, int mode, char *kernel_string)
@@ -307,18 +319,27 @@ void ebpf_update_map_sizes(struct bpf_object *program, ebpf_module_t *em)
if (!maps)
return;
+ uint32_t apps_type = NETDATA_EBPF_MAP_PID | NETDATA_EBPF_MAP_RESIZABLE;
bpf_map__for_each(map, program)
{
const char *map_name = bpf_map__name(map);
int i = 0; ;
while (maps[i].name) {
ebpf_local_maps_t *w = &maps[i];
- if (w->user_input != w->internal_input && !strcmp(w->name, map_name)) {
+ if (w->type & NETDATA_EBPF_MAP_RESIZABLE) {
+ if (!strcmp(w->name, map_name)) {
+ if (w->user_input && w->user_input != w->internal_input) {
#ifdef NETDATA_INTERNAL_CHECKS
- info("Changing map %s from size %u to %u ", map_name, w->internal_input, w->user_input);
+ info("Changing map %s from size %u to %u ", map_name, w->internal_input, w->user_input);
#endif
- bpf_map__resize(map, w->user_input);
+ bpf_map__resize(map, w->user_input);
+ } else if (((w->type & apps_type) == apps_type) && (!em->apps_charts) && (!em->cgroup_charts)) {
+ w->user_input = ND_EBPF_DEFAULT_MIN_PID;
+ bpf_map__resize(map, w->user_input);
+ }
+ }
}
+
i++;
}
}
@@ -377,8 +398,59 @@ static struct bpf_link **ebpf_attach_programs(struct bpf_object *obj, size_t len
return links;
}
+static void ebpf_update_maps(ebpf_module_t *em, struct bpf_object *obj)
+{
+ if (!em->maps)
+ return;
+
+ ebpf_local_maps_t *maps = em->maps;
+ struct bpf_map *map;
+ bpf_map__for_each(map, obj)
+ {
+ int fd = bpf_map__fd(map);
+ if (maps) {
+ const char *map_name = bpf_map__name(map);
+ int j = 0; ;
+ while (maps[j].name) {
+ ebpf_local_maps_t *w = &maps[j];
+ if (w->map_fd == ND_EBPF_MAP_FD_NOT_INITIALIZED && !strcmp(map_name, w->name))
+ w->map_fd = fd;
+
+ j++;
+ }
+ }
+ }
+}
+
+static void ebpf_update_controller(ebpf_module_t *em, struct bpf_object *obj)
+{
+ ebpf_local_maps_t *maps = em->maps;
+ if (!maps)
+ return;
+
+ struct bpf_map *map;
+ bpf_map__for_each(map, obj)
+ {
+ size_t i = 0;
+ while (maps[i].name) {
+ ebpf_local_maps_t *w = &maps[i];
+ if (w->map_fd != ND_EBPF_MAP_FD_NOT_INITIALIZED && (w->type & NETDATA_EBPF_MAP_CONTROLLER)) {
+ w->type &= ~NETDATA_EBPF_MAP_CONTROLLER;
+ w->type |= NETDATA_EBPF_MAP_CONTROLLER_UPDATED;
+
+ uint32_t key = NETDATA_CONTROLLER_APPS_ENABLED;
+ int value = em->apps_charts | em->cgroup_charts;
+ int ret = bpf_map_update_elem(w->map_fd, &key, &value, 0);
+ if (ret)
+ error("Add key(%u) for controller table failed.", key);
+ }
+ i++;
+ }
+ }
+}
+
struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *kernel_string,
- struct bpf_object **obj, int *map_fd)
+ struct bpf_object **obj)
{
char lpath[4096];
char lname[128];
@@ -403,13 +475,8 @@ struct bpf_link **ebpf_load_program(char *plugins_dir, ebpf_module_t *em, char *
return NULL;
}
- struct bpf_map *map;
- size_t i = 0;
- bpf_map__for_each(map, *obj)
- {
- map_fd[i] = bpf_map__fd(map);
- i++;
- }
+ ebpf_update_maps(em, *obj);
+ ebpf_update_controller(em, *obj);
size_t count_programs = ebpf_count_programs(*obj);
@@ -462,7 +529,7 @@ void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em)
//----------------------------------------------------------------------------------------------------------------------
-void ebpf_mount_config_name(char *filename, size_t length, char *path, char *config)
+void ebpf_mount_config_name(char *filename, size_t length, char *path, const char *config)
{
snprintf(filename, length, "%s/ebpf.d/%s", path, config);
}
@@ -475,7 +542,7 @@ int ebpf_load_config(struct config *config, char *filename)
static netdata_run_mode_t ebpf_select_mode(char *mode)
{
- if (!strcasecmp(mode, "return"))
+ if (!strcasecmp(mode,EBPF_CFG_LOAD_MODE_RETURN ))
return MODE_RETURN;
else if (!strcasecmp(mode, "dev"))
return MODE_DEVMODE;
@@ -483,17 +550,31 @@ static netdata_run_mode_t ebpf_select_mode(char *mode)
return MODE_ENTRY;
}
-void ebpf_update_module_using_config(ebpf_module_t *modules, struct config *cfg)
+static void ebpf_select_mode_string(char *output, size_t len, netdata_run_mode_t sel)
{
- char *mode = appconfig_get(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, EBPF_CFG_LOAD_MODE_DEFAULT);
+ if (sel == MODE_RETURN)
+ strncpyz(output, EBPF_CFG_LOAD_MODE_RETURN, len);
+ else
+ strncpyz(output, EBPF_CFG_LOAD_MODE_DEFAULT, len);
+}
+
+/**
+ * @param modules structure that will be updated
+ */
+void ebpf_update_module_using_config(ebpf_module_t *modules)
+{
+ char default_value[EBPF_MAX_MODE_LENGTH + 1];
+ ebpf_select_mode_string(default_value, EBPF_MAX_MODE_LENGTH, modules->mode);
+ char *mode = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE, default_value);
modules->mode = ebpf_select_mode(mode);
- modules->update_time = (int)appconfig_get_number(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY, 1);
+ modules->update_every = (int)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION,
+ EBPF_CFG_UPDATE_EVERY, modules->update_every);
- modules->apps_charts = appconfig_get_boolean(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION,
- CONFIG_BOOLEAN_YES);
+ modules->apps_charts = appconfig_get_boolean(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION,
+ modules->apps_charts);
- modules->pid_map_size = (uint32_t)appconfig_get_number(cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE,
+ modules->pid_map_size = (uint32_t)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE,
modules->pid_map_size);
}
@@ -507,20 +588,249 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, struct config *cfg)
* update the variables.
*
* @param em the module structure
- * @param cfg the configuration structure
- * @param cfg_file the filename to load
*/
-void ebpf_update_module(ebpf_module_t *em, struct config *cfg, char *cfg_file)
+void ebpf_update_module(ebpf_module_t *em)
{
char filename[FILENAME_MAX+1];
- ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_user_config_dir, cfg_file);
- if (!ebpf_load_config(cfg, filename)) {
- ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_stock_config_dir, cfg_file);
- if (!ebpf_load_config(cfg, filename)) {
- error("Cannot load the ebpf configuration file %s", cfg_file);
+ ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_user_config_dir, em->config_file);
+ if (!ebpf_load_config(em->cfg, filename)) {
+ ebpf_mount_config_name(filename, FILENAME_MAX, ebpf_stock_config_dir, em->config_file);
+ if (!ebpf_load_config(em->cfg, filename)) {
+ error("Cannot load the ebpf configuration file %s", em->config_file);
return;
}
}
- ebpf_update_module_using_config(em, cfg);
+ ebpf_update_module_using_config(em);
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Load Address
+ *
+ * Helper used to get address from /proc/kallsym
+ *
+ * @param fa address structure
+ * @param fd file descriptor loaded inside kernel.
+ */
+void ebpf_load_addresses(ebpf_addresses_t *fa, int fd)
+{
+ if (fa->addr)
+ return ;
+
+ procfile *ff = procfile_open("/proc/kallsyms", " \t:", PROCFILE_FLAG_DEFAULT);
+ if (!ff)
+ return;
+
+ ff = procfile_readall(ff);
+ if (!ff)
+ return;
+
+ fa->hash = simple_hash(fa->function);
+
+ size_t lines = procfile_lines(ff), l;
+ for(l = 0; l < lines ;l++) {
+ char *fcnt = procfile_lineword(ff, l, 2);
+ uint32_t hash = simple_hash(fcnt);
+ if (fa->hash == hash && !strcmp(fcnt, fa->function)) {
+ char addr[128];
+ snprintf(addr, 127, "0x%s", procfile_lineword(ff, l, 0));
+ fa->addr = (unsigned long) strtoul(addr, NULL, 16);
+ uint32_t key = 0;
+ bpf_map_update_elem(fd, &key, &fa->addr, BPF_ANY);
+ }
+ }
+
+ procfile_close(ff);
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Fill Algorithms
+ *
+ * Set one unique dimension for all vector position.
+ *
+ * @param algorithms the output vector
+ * @param length number of elements of algorithms vector
+ * @param algorithm algorithm used on charts.
+*/
+void ebpf_fill_algorithms(int *algorithms, size_t length, int algorithm)
+{
+ size_t i;
+ for (i = 0; i < length; i++) {
+ algorithms[i] = algorithm;
+ }
+}
+
+/**
+ * Fill Histogram dimension
+ *
+ * Fill the histogram dimension with the specified ranges
+ */
+char **ebpf_fill_histogram_dimension(size_t maximum)
+{
+ char *dimensions[] = { "us", "ms", "s"};
+ int previous_dim = 0, current_dim = 0;
+ uint32_t previous_level = 1000, current_level = 1000;
+ uint32_t previous_divisor = 1, current_divisor = 1;
+ uint32_t current = 1, previous = 0;
+ uint32_t selector;
+ char **out = callocz(maximum, sizeof(char *));
+ char range[128];
+ size_t end = maximum - 1;
+ for (selector = 0; selector < end; selector++) {
+ snprintf(range, 127, "%u%s->%u%s", previous/previous_divisor, dimensions[previous_dim],
+ current/current_divisor, dimensions[current_dim]);
+ out[selector] = strdupz(range);
+ previous = current;
+ current <<= 1;
+
+ if (previous_dim != 2 && previous > previous_level) {
+ previous_dim++;
+
+ previous_divisor *= 1000;
+ previous_level *= 1000;
+ }
+
+ if (current_dim != 2 && current > current_level) {
+ current_dim++;
+
+ current_divisor *= 1000;
+ current_level *= 1000;
+ }
+ }
+ snprintf(range, 127, "%u%s->+Inf", previous/previous_divisor, dimensions[previous_dim]);
+ out[selector] = strdupz(range);
+
+ return out;
+}
+
+/**
+ * Histogram dimension cleanup
+ *
+ * Cleanup dimensions allocated with function ebpf_fill_histogram_dimension
+ *
+ * @param ptr
+ * @param length
+ */
+void ebpf_histogram_dimension_cleanup(char **ptr, size_t length)
+{
+ size_t i;
+ for (i = 0; i < length; i++) {
+ freez(ptr[i]);
+ }
+ freez(ptr);
+}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+/**
+ * Open tracepoint path
+ *
+ * @param filename pointer to store the path
+ * @param length file length
+ * @param subsys is the name of your subsystem.
+ * @param eventname is the name of the event to trace.
+ * @param flags flags used with syscall open
+ *
+ * @return it returns a positive value on success and a negative otherwise.
+ */
+static inline int ebpf_open_tracepoint_path(char *filename, size_t length, char *subsys, char *eventname, int flags)
+{
+ snprintfz(filename, length, "%s/events/%s/%s/enable", NETDATA_DEBUGFS, subsys, eventname);
+ return open(filename, flags, 0);
+}
+
+/**
+ * Is tracepoint enabled
+ *
+ * Check whether the tracepoint is enabled.
+ *
+ * @param subsys is the name of your subsystem.
+ * @param eventname is the name of the event to trace.
+ *
+ * @return it returns 1 when it is enabled, 0 when it is disabled and -1 on error.
+ */
+int ebpf_is_tracepoint_enabled(char *subsys, char *eventname)
+{
+ char text[FILENAME_MAX + 1];
+ int fd = ebpf_open_tracepoint_path(text, FILENAME_MAX, subsys, eventname, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ ssize_t length = read(fd, text, 1);
+ if (length != 1) {
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ return (text[0] == '1') ? CONFIG_BOOLEAN_YES : CONFIG_BOOLEAN_NO;
+}
+
+/**
+ * Change Tracing values
+ *
+ * Change value for specific tracepoint enabling or disabling it according value given.
+ *
+ * @param subsys is the name of your subsystem.
+ * @param eventname is the name of the event to trace.
+ * @param value a value to enable (1) or disable (0) a tracepoint.
+ *
+ * @return It returns 0 on success and -1 otherwise
+ */
+static int ebpf_change_tracing_values(char *subsys, char *eventname, char *value)
+{
+ if (strcmp("0", value) && strcmp("1", value)) {
+ error("Invalid value given to either enable or disable a tracepoint.");
+ return -1;
+ }
+
+ char filename[1024];
+ int fd = ebpf_open_tracepoint_path(filename, 1023, subsys, eventname, O_WRONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ ssize_t written = write(fd, value, strlen(value));
+ if (written < 0) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+/**
+ * Enable tracing values
+ *
+ * Enable a tracepoint on a system
+ *
+ * @param subsys is the name of your subsystem.
+ * @param eventname is the name of the event to trace.
+ *
+ * @return It returns 0 on success and -1 otherwise
+ */
+int ebpf_enable_tracing_values(char *subsys, char *eventname)
+{
+ return ebpf_change_tracing_values(subsys, eventname, "1");
+}
+
+/**
+ * Disable tracing values
+ *
+ * Disable tracing points enabled by collector
+ *
+ * @param subsys is the name of your subsystem.
+ * @param eventname is the name of the event to trace.
+ *
+ * @return It returns 0 on success and -1 otherwise
+ */
+int ebpf_disable_tracing_values(char *subsys, char *eventname)
+{
+ return ebpf_change_tracing_values(subsys, eventname, "0");
}
diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h
index bc55d9595..73128f529 100644
--- a/libnetdata/ebpf/ebpf.h
+++ b/libnetdata/ebpf/ebpf.h
@@ -5,6 +5,7 @@
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
+#include <stdlib.h> // Necessary for stdtoul
#define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/"
#define NETDATA_KALLSYMS "/proc/kallsyms"
@@ -14,10 +15,12 @@
#define EBPF_CFG_LOAD_MODE "ebpf load mode"
#define EBPF_CFG_LOAD_MODE_DEFAULT "entry"
#define EBPF_CFG_LOAD_MODE_RETURN "return"
+#define EBPF_MAX_MODE_LENGTH 6
#define EBPF_CFG_UPDATE_EVERY "update every"
#define EBPF_CFG_PID_SIZE "pid table size"
#define EBPF_CFG_APPLICATION "apps"
+#define EBPF_CFG_CGROUP "cgroups"
/**
* The next magic number is got doing the following math:
@@ -57,6 +60,13 @@
#define NETDATA_EBPF_KERNEL_5_10 330240
/**
+ * Kernel 5.0
+ *
+ * 327680 = 5*65536 +256*0
+ */
+#define NETDATA_EBPF_KERNEL_5_0 327680
+
+/**
* Kernel 4.17
*
* 266496 = 4*65536 + 17*256
@@ -80,6 +90,16 @@
#define VERSION_STRING_LEN 256
#define EBPF_KERNEL_REJECT_LIST_FILE "ebpf_kernel_reject_list.txt"
+#define ND_EBPF_DEFAULT_MIN_PID 1U
+#define ND_EBPF_MAP_FD_NOT_INITIALIZED (int)-1
+
+typedef struct ebpf_addresses {
+ char *function;
+ uint32_t hash;
+ // We use long as address, because it matches system length
+ unsigned long addr;
+} ebpf_addresses_t;
+
extern char *ebpf_user_config_dir;
extern char *ebpf_stock_config_dir;
@@ -99,10 +119,26 @@ typedef enum {
#define ND_EBPF_DEFAULT_PID_SIZE 32768U
+enum netdata_ebpf_map_type {
+ NETDATA_EBPF_MAP_STATIC = 0,
+ NETDATA_EBPF_MAP_RESIZABLE = 1,
+ NETDATA_EBPF_MAP_CONTROLLER = 2,
+ NETDATA_EBPF_MAP_CONTROLLER_UPDATED = 4,
+ NETDATA_EBPF_MAP_PID = 8
+};
+
+enum netdata_controller {
+ NETDATA_CONTROLLER_APPS_ENABLED,
+
+ NETDATA_CONTROLLER_END
+};
+
typedef struct ebpf_local_maps {
char *name;
uint32_t internal_input;
uint32_t user_input;
+ uint32_t type;
+ int map_fd;
} ebpf_local_maps_t;
typedef struct ebpf_specify_name {
@@ -117,9 +153,10 @@ typedef struct ebpf_module {
const char *config_name;
int enabled;
void *(*start_routine)(void *);
- int update_time;
+ int update_every;
int global_charts;
int apps_charts;
+ int cgroup_charts;
netdata_run_mode_t mode;
uint32_t thread_id;
int optional;
@@ -127,23 +164,46 @@ typedef struct ebpf_module {
ebpf_local_maps_t *maps;
ebpf_specify_name_t *names;
uint32_t pid_map_size;
+ struct config *cfg;
+ const char *config_file;
} ebpf_module_t;
-extern int get_kernel_version(char *out, int size);
+extern int ebpf_get_kernel_version();
extern int get_redhat_release();
extern int has_condition_to_run(int version);
extern char *ebpf_kernel_suffix(int version, int isrh);
-extern int ebpf_update_kernel(ebpf_data_t *ef);
+extern void ebpf_update_kernel(char *ks, size_t length, int isrh, int version);
extern struct bpf_link **ebpf_load_program(char *plugins_dir,
ebpf_module_t *em,
char *kernel_string,
- struct bpf_object **obj,
- int *map_fd);
+ struct bpf_object **obj);
-extern void ebpf_mount_config_name(char *filename, size_t length, char *path, char *config);
+extern void ebpf_mount_config_name(char *filename, size_t length, char *path, const char *config);
extern int ebpf_load_config(struct config *config, char *filename);
-extern void ebpf_update_module_using_config(ebpf_module_t *modules, struct config *cfg);
-extern void ebpf_update_module(ebpf_module_t *em, struct config *cfg, char *cfg_file);
+extern void ebpf_update_module(ebpf_module_t *em);
extern void ebpf_update_names(ebpf_specify_name_t *opt, ebpf_module_t *em);
+extern void ebpf_load_addresses(ebpf_addresses_t *fa, int fd);
+extern void ebpf_fill_algorithms(int *algorithms, size_t length, int algorithm);
+extern char **ebpf_fill_histogram_dimension(size_t maximum);
+
+// Histogram
+#define NETDATA_EBPF_HIST_MAX_BINS 24UL
+#define NETDATA_DISK_MAX 256U
+#define NETDATA_DISK_HISTOGRAM_LENGTH (NETDATA_DISK_MAX * NETDATA_EBPF_HIST_MAX_BINS)
+
+typedef struct netdata_ebpf_histogram {
+ char *name;
+ char *title;
+ int order;
+ uint64_t histogram[NETDATA_EBPF_HIST_MAX_BINS];
+} netdata_ebpf_histogram_t;
+
+extern void ebpf_histogram_dimension_cleanup(char **ptr, size_t length);
+
+// Tracepoint helpers
+// For more information related to tracepoints read https://www.kernel.org/doc/html/latest/trace/tracepoints.html
+extern int ebpf_is_tracepoint_enabled(char *subsys, char *eventname);
+extern int ebpf_enable_tracing_values(char *subsys, char *eventname);
+extern int ebpf_disable_tracing_values(char *subsys, char *eventname);
#endif /* NETDATA_EBPF_H */
diff --git a/libnetdata/json/jsmn.c b/libnetdata/json/jsmn.c
index 952535897..2f48bd65a 100644
--- a/libnetdata/json/jsmn.c
+++ b/libnetdata/json/jsmn.c
@@ -183,7 +183,7 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
*
* Parse JSON string and fill tokens.
*
- * @param parser the auxiliar vector used to parser
+ * @param parser the auxiliary vector used to parser
* @param js the string to parse
* @param len the string length
* @param tokens the place to map the tokens
diff --git a/libnetdata/libnetdata.h b/libnetdata/libnetdata.h
index 77a1bbe7f..b49ab21a0 100644
--- a/libnetdata/libnetdata.h
+++ b/libnetdata/libnetdata.h
@@ -53,6 +53,7 @@ extern "C" {
#include <pthread.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -90,6 +91,12 @@ extern "C" {
#include <uv.h>
#include <assert.h>
+// CentOS 7 has older version that doesn't define this
+// same goes for MacOS
+#ifndef UUID_STR_LEN
+#define UUID_STR_LEN (37)
+#endif
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
diff --git a/libnetdata/log/log.h b/libnetdata/log/log.h
index 58cc0d26c..c8380d0c1 100644
--- a/libnetdata/log/log.h
+++ b/libnetdata/log/log.h
@@ -44,7 +44,7 @@ extern "C" {
#define D_RRDENGINE 0x0000000100000000
#define D_ACLK 0x0000000200000000
#define D_METADATALOG 0x0000000400000000
-#define D_GUIDLOG 0x0000000800000000
+#define D_ACLK_SYNC 0x0000000800000000
#define D_SYSTEM 0x8000000000000000
//#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
diff --git a/libnetdata/procfile/procfile.c b/libnetdata/procfile/procfile.c
index 9867c19f6..ce412f4b0 100644
--- a/libnetdata/procfile/procfile.c
+++ b/libnetdata/procfile/procfile.c
@@ -69,7 +69,7 @@ static inline pfwords *pfwords_new(void) {
}
static inline void pfwords_reset(pfwords *fw) {
- // debug(D_PROCFILE, PF_PREFIX ": reseting words");
+ // debug(D_PROCFILE, PF_PREFIX ": resetting words");
fw->len = 0;
}
@@ -115,7 +115,7 @@ static inline pflines *pflines_new(void) {
}
static inline void pflines_reset(pflines *fl) {
- // debug(D_PROCFILE, PF_PREFIX ": reseting lines");
+ // debug(D_PROCFILE, PF_PREFIX ": resetting lines");
fl->len = 0;
}
diff --git a/libnetdata/socket/security.c b/libnetdata/socket/security.c
index 63a71bcbd..6ac512de5 100644
--- a/libnetdata/socket/security.c
+++ b/libnetdata/socket/security.c
@@ -213,6 +213,7 @@ void security_start_ssl(int selector) {
}
netdata_srv_ctx = security_initialize_openssl_server();
+ SSL_CTX_set_mode(netdata_srv_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
break;
}
case NETDATA_SSL_CONTEXT_STREAMING: {
diff --git a/libnetdata/storage_number/storage_number.c b/libnetdata/storage_number/storage_number.c
index 8ef1353b0..3e6a9f45c 100644
--- a/libnetdata/storage_number/storage_number.c
+++ b/libnetdata/storage_number/storage_number.c
@@ -2,17 +2,23 @@
#include "../libnetdata.h"
+#define get_storage_number_flags(value) \
+ ((((storage_number)(value)) & (1 << 24)) | \
+ (((storage_number)(value)) & (1 << 25)) | \
+ (((storage_number)(value)) & (1 << 26)))
+
storage_number pack_storage_number(calculated_number value, uint32_t flags) {
// bit 32 = sign 0:positive, 1:negative
// bit 31 = 0:divide, 1:multiply
// bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
// bit 27 SN_EXISTS_100
// bit 26 SN_EXISTS_RESET
- // bit 25 SN_EXISTS
+ // bit 25 SN_ANOMALY_BIT = 0: anomalous, 1: not anomalous
// bit 24 to bit 1 = the value
storage_number r = get_storage_number_flags(flags);
- if(!value) return r;
+ if(!value)
+ goto RET_SN;
int m = 0;
calculated_number n = value, factor = 10;
@@ -47,7 +53,7 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags) {
error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
#endif
r += 0x00ffffff;
- return r;
+ goto RET_SN;
}
}
else {
@@ -78,6 +84,10 @@ storage_number pack_storage_number(calculated_number value, uint32_t flags) {
r += (storage_number)n;
#endif
+RET_SN:
+ if (r == SN_EMPTY_SLOT)
+ r = SN_ANOMALOUS_ZERO;
+
return r;
}
@@ -100,7 +110,7 @@ calculated_number unpack_storage_number(storage_number value) {
factor = 100;
// bit 26 SN_EXISTS_RESET
- // bit 25 SN_EXISTS
+ // bit 25 SN_ANOMALY_BIT
// bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
int mul = (value & ((1<<29)|(1<<28)|(1<<27))) >> 27;
diff --git a/libnetdata/storage_number/storage_number.h b/libnetdata/storage_number/storage_number.h
index 4ad7ff624..4101f69e0 100644
--- a/libnetdata/storage_number/storage_number.h
+++ b/libnetdata/storage_number/storage_number.h
@@ -60,17 +60,24 @@ typedef long double collected_number;
typedef uint32_t storage_number;
#define STORAGE_NUMBER_FORMAT "%u"
-#define SN_EXISTS (1 << 24) // the value exists
+#define SN_ANOMALY_BIT (1 << 24) // the anomaly bit of the value
#define SN_EXISTS_RESET (1 << 25) // the value has been overflown
#define SN_EXISTS_100 (1 << 26) // very large value (multiplier is 100 instead of 10)
-// extract the flags
-#define get_storage_number_flags(value) ((((storage_number)(value)) & (1 << 24)) | (((storage_number)(value)) & (1 << 25)) | (((storage_number)(value)) & (1 << 26)))
+#define SN_DEFAULT_FLAGS SN_ANOMALY_BIT
+
#define SN_EMPTY_SLOT 0x00000000
+// When the calculated number is zero and the value is anomalous (ie. it's bit
+// is zero) we want to return a storage_number representation that is
+// different from the empty slot. We achieve this by mapping zero to
+// SN_EXISTS_100. Unpacking the SN_EXISTS_100 value will return zero because
+// its fraction field (as well as its exponent factor field) will be zero.
+#define SN_ANOMALOUS_ZERO SN_EXISTS_100
+
// checks
-#define does_storage_number_exist(value) ((get_storage_number_flags(value) != 0)?1:0)
-#define did_storage_number_reset(value) ((get_storage_number_flags(value) == SN_EXISTS_RESET)?1:0)
+#define does_storage_number_exist(value) (((storage_number) (value)) != SN_EMPTY_SLOT)
+#define did_storage_number_reset(value) ((((storage_number) (value)) & SN_EXISTS_RESET) != 0)
storage_number pack_storage_number(calculated_number value, uint32_t flags);
calculated_number unpack_storage_number(storage_number value);
diff --git a/libnetdata/storage_number/tests/test_storage_number.c b/libnetdata/storage_number/tests/test_storage_number.c
index 7ef18b1de..f90521cab 100644
--- a/libnetdata/storage_number/tests/test_storage_number.c
+++ b/libnetdata/storage_number/tests/test_storage_number.c
@@ -38,7 +38,7 @@ static void test_number_printing(void **state)
print_calculated_number(value, -9999.9999999);
assert_string_equal(value, "-9999.9999999");
- print_calculated_number(value, unpack_storage_number(pack_storage_number(16.777218L, SN_EXISTS)));
+ print_calculated_number(value, unpack_storage_number(pack_storage_number(16.777218L, SN_DEFAULT_FLAGS)));
assert_string_equal(value, "16.77722");
}