@cryptotaxi247 / netdata-1 / commits / edeb82fac

install and enable eBPF Plugin by default (#8665)

* netdata_installer_kernels: New kernels This commit brings new kernels for our netdata-installer * RH detection This commit brings the RH detection to netdata-installer, but it cannot be tested yet until we merge a PR on kernel-collector * netdata_installer_kernels: RH kernels This commit brings updates that allows to install and run the collectors on RH * netdata_installer_kernels: Kernel variables This commit brings definitions instead magic number to the isntaller * netdata_installer_kernels: remove echo This commit removes echo to avoid new line * netdata_installer_kernels: Move C code This commit removes the C code that will be inserted in another PR * Update eBPF install to use released version. This updates the install code for the eBPF plugin to properly utilize (and verify) a tagged release of the plugin instead of pulling the upstream master branch. It also adds support for using a local copy of the tarball, and switchs the default behavior to install the eBPF plugin instead of not installing it. * Tidy-up messages relating to eBPF. * Fix typos in error handling functions. * ebpf-release: New kernels This commit brings the kernels necessary to support Debian 10.0 * ebpf-release: Bring support for new package format * ebpf-release: collector as loader This commit brings the necessary changes for the collector loads all the nfiles depending of the kernel it is running * Update eBPF install to use released version. This updates the install code for the eBPF plugin to properly utilize (and verify) a tagged release of the plugin instead of pulling the upstream master branch. It also adds support for using a local copy of the tarball, and switchs the default behavior to install the eBPF plugin instead of not installing it. * netdata_installer_kernels: New kernels This commit brings new kernels for our netdata-installer * RH detection This commit brings the RH detection to netdata-installer, but it cannot be tested yet until we merge a PR on kernel-collector * netdata_installer_kernels: RH kernels This commit brings updates that allows to install and run the collectors on RH * netdata_installer_kernels: Kernel variables This commit brings definitions instead magic number to the isntaller * netdata_installer_kernels: remove echo This commit removes echo to avoid new line * netdata_installer_kernels: Move C code This commit removes the C code that will be inserted in another PR * Tidy-up messages relating to eBPF. * Fix typos in error handling functions. * ebpf-release: New kernels This commit brings the kernels necessary to support Debian 10.0 * ebpf-release: Bring support for new package format * ebpf-release: collector as loader This commit brings the necessary changes for the collector loads all the nfiles depending of the kernel it is running * Fix package name handling. * Bump eBPF kernel-collector to v0.1.0 * Update --help to state eBPF is enabled by default and add --disable-ebpf option in --help output * Remove deprecated kernel version compatibility checks * Fix EBPF_TARBALL * Remove libc path detection logic (deprecated0 * Use the new package structure of kernel-collector * Relax the glob on netdata_ebpf as we may develop/distirbute other types of ebpf programs * Fix ownership of ebpf libraries/programs * Make the check-kernel-config.sh local to the installer * Make plugins.ebpf = yes (by default) Co-authored-by: Thiago Marques <thiagoftsm@gmail.com> Co-authored-by: James Mills <prologic@shortcircuit.net.au>

Austin S. Hemmelgarn committed May 18, 2020 at 21:03 UTC edeb82fac99246b7d572744fe1d732fd6d9cb34e
8 files changed +549 -424
collectors/ebpf.plugin/ebpf.c
+66 -18
@@ -71,6 +71,7 @@ static int debug_log = 0;
71 static int use_stdout = 0;
72 struct config collector_config;
73 static int mykernel = 0;
74 +static char kernel_string[64];
75 static int nprocs;
76 static int isrh;
77 netdata_idx_t *hash_values;
@@ -684,28 +685,69 @@ static int ebpf_load_libraries()
685 {
686 char *err = NULL;
687 char lpath[4096];
688 + char netdatasl[128];
689 + char *libbase = { "libnetdata_ebpf.so" };
690
688 - build_complete_path(lpath, 4096, plugin_dir, "libnetdata_ebpf.so");
691 + snprintf(netdatasl, 127, "%s.%s", libbase, kernel_string);
692 + build_complete_path(lpath, 4096, plugin_dir, netdatasl);
693 libnetdata = dlopen(lpath, RTLD_LAZY);
694 if (!libnetdata) {
691 - error("[EBPF_PROCESS] Cannot load %s.", lpath);
692 - return -1;
695 + info("[EBPF_PROCESS] Cannot load library %s for the current kernel.", lpath);
696 +
697 + //Update kernel
698 + char *library = ebpf_library_suffix(mykernel, (isrh < 0)?0:1);
699 + size_t length = strlen(library);
700 + strncpyz(kernel_string, library, length);
701 + kernel_string[length] = '\0';
702 +
703 + //Try to load the default version
704 + snprintf(netdatasl, 127, "%s.%s", libbase, kernel_string);
705 + build_complete_path(lpath, 4096, plugin_dir, netdatasl);
706 + libnetdata = dlopen(lpath, RTLD_LAZY);
707 + if (!libnetdata) {
708 + error("[EBPF_PROCESS] Cannot load %s default library.", lpath);
709 + return -1;
710 + } else {
711 + info("[EBPF_PROCESS] Default shared library %s loaded with success.", lpath);
712 + }
713 } else {
694 - load_bpf_file = dlsym(libnetdata, "load_bpf_file");
714 + info("[EBPF_PROCESS] Current shared library %s loaded with success.", lpath);
715 + }
716 +
717 + load_bpf_file = dlsym(libnetdata, "load_bpf_file");
718 + if ((err = dlerror()) != NULL) {
719 + error("[EBPF_PROCESS] Cannot find load_bpf_file: %s", err);
720 + return -1;
721 + }
722 +
723 + map_fd = dlsym(libnetdata, "map_fd");
724 + if ((err = dlerror()) != NULL) {
725 + error("[EBPF_PROCESS] Cannot find map_fd: %s", err);
726 + return -1;
727 + }
728 +
729 + bpf_map_lookup_elem = dlsym(libnetdata, "bpf_map_lookup_elem");
730 + if ((err = dlerror()) != NULL) {
731 + error("[EBPF_PROCESS] Cannot find bpf_map_lookup_elem: %s", err);
732 + return -1;
733 + }
734 +
735 + if(mode == 1) {
736 + set_bpf_perf_event = dlsym(libnetdata, "set_bpf_perf_event");
737 if ((err = dlerror()) != NULL) {
696 - error("[EBPF_PROCESS] Cannot find load_bpf_file: %s", err);
738 + error("[EBPF_PROCESS] Cannot find set_bpf_perf_event: %s", err);
739 return -1;
740 }
741
700 - map_fd = dlsym(libnetdata, "map_fd");
742 + perf_event_unmap = dlsym(libnetdata, "perf_event_unmap");
743 if ((err = dlerror()) != NULL) {
702 - error("[EBPF_PROCESS] Cannot find map_fd: %s", err);
744 + error("[EBPF_PROCESS] Cannot find perf_event_unmap: %s", err);
745 return -1;
746 }
747
706 - bpf_map_lookup_elem = dlsym(libnetdata, "bpf_map_lookup_elem");
748 + perf_event_mmap_header = dlsym(libnetdata, "perf_event_mmap_header");
749 if ((err = dlerror()) != NULL) {
708 - error("[EBPF_PROCESS] Cannot find bpf_map_lookup_elem: %s", err);
750 + error("[EBPF_PROCESS] Cannot find perf_event_mmap_header: %s", err);
751 return -1;
752 }
753
@@ -739,24 +781,30 @@ static int ebpf_load_libraries()
781 return 0;
782 }
783
742 -char *select_file() {
743 - if(!mode)
744 - return "rnetdata_ebpf_process.o";
745 - if(mode == MODE_DEVMODE)
746 - return "dnetdata_ebpf_process.o";
784 +int select_file(char *name, int length) {
785 + int ret = -1;
786 + if (!mode)
787 + ret = snprintf(name, (size_t)length, "rnetdata_ebpf_process.%s.o", kernel_string);
788 + else if(mode == 1)
789 + ret = snprintf(name, (size_t)length, "dnetdata_ebpf_process.%s.o", kernel_string);
790 + else if(mode == 2)
791 + ret = snprintf(name, (size_t)length, "pnetdata_ebpf_process.%s.o", kernel_string);
792
748 - return "pnetdata_ebpf_process.o";
793 + return ret;
794 }
795
796 int process_load_ebpf()
797 {
798 char lpath[4096];
799 + char name[128];
800
755 - char *name = select_file();
801 + int test = select_file(name, 127);
802 + if (test < 0 || test > 127)
803 + return -1;
804
805 build_complete_path(lpath, 4096, plugin_dir, name);
806 event_pid = getpid();
759 - if (load_bpf_file(lpath, event_pid) ) {
807 + if (load_bpf_file(lpath, event_pid)) {
808 error("[EBPF_PROCESS] Cannot load program: %s", lpath);
809 return -1;
810 } else {
@@ -1048,7 +1096,7 @@ int main(int argc, char **argv)
1096 {
1097 parse_args(argc, argv);
1098
1051 - mykernel = get_kernel_version();
1099 + mykernel = get_kernel_version(kernel_string, 63);
1100 if(!has_condition_to_run(mykernel)) {
1101 error("[EBPF PROCESS] The current collector cannot run on this kernel.");
1102 return 1;
collectors/plugins.d/plugins_d.c
+320 -283
@@ -5,22 +5,24 @@
5 char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL };
6 struct plugind *pluginsd_root = NULL;
7
8 -static inline int pluginsd_space(char c) {
9 - switch(c) {
10 - case ' ':
11 - case '\t':
12 - case '\r':
13 - case '\n':
14 - case '=':
15 - return 1;
16 -
17 - default:
18 - return 0;
8 +static inline int pluginsd_space(char c)
9 +{
10 + switch (c) {
11 + case ' ':
12 + case '\t':
13 + case '\r':
14 + case '\n':
15 + case '=':
16 + return 1;
17 +
18 + default:
19 + return 0;
20 }
21 }
22
22 -inline int config_isspace(char c) {
23 - switch(c) {
23 +inline int config_isspace(char c)
24 +{
25 + switch (c) {
26 case ' ':
27 case '\t':
28 case '\r':
@@ -34,15 +36,17 @@ inline int config_isspace(char c) {
36 }
37
38 // split a text into words, respecting quotes
37 -static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)) {
39 +static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char))
40 +{
41 char *s = str, quote = 0;
42 int i = 0, j;
43
44 // skip all white space
42 - while(unlikely(custom_isspace(*s))) s++;
45 + while (unlikely(custom_isspace(*s)))
46 + s++;
47
48 // check for quote
45 - if(unlikely(*s == '\'' || *s == '"')) {
49 + if (unlikely(*s == '\'' || *s == '"')) {
50 quote = *s; // remember the quote
51 s++; // skip the quote
52 }
@@ -51,69 +55,76 @@ static inline int quoted_strings_splitter(char *str, char **words, int max_words
55 words[i++] = s;
56
57 // while we have something
54 - while(likely(*s)) {
58 + while (likely(*s)) {
59 // if it is escape
56 - if(unlikely(*s == '\\' && s[1])) {
60 + if (unlikely(*s == '\\' && s[1])) {
61 s += 2;
62 continue;
63 }
64
65 // if it is quote
62 - else if(unlikely(*s == quote)) {
66 + else if (unlikely(*s == quote)) {
67 quote = 0;
68 *s = ' ';
69 continue;
70 }
71
72 // if it is a space
69 - else if(unlikely(quote == 0 && custom_isspace(*s))) {
70 -
73 + else if (unlikely(quote == 0 && custom_isspace(*s))) {
74 // terminate the word
75 *s++ = '\0';
76
77 // skip all white space
75 - while(likely(custom_isspace(*s))) s++;
78 + while (likely(custom_isspace(*s)))
79 + s++;
80
81 // check for quote
78 - if(unlikely(*s == '\'' || *s == '"')) {
82 + if (unlikely(*s == '\'' || *s == '"')) {
83 quote = *s; // remember the quote
84 s++; // skip the quote
85 }
86
87 // if we reached the end, stop
84 - if(unlikely(!*s)) break;
88 + if (unlikely(!*s))
89 + break;
90
91 // store the next word
87 - if(likely(i < max_words)) words[i++] = s;
88 - else break;
92 + if (likely(i < max_words))
93 + words[i++] = s;
94 + else
95 + break;
96 }
97
98 // anything else
92 - else s++;
99 + else
100 + s++;
101 }
102
103 // terminate the words
104 j = i;
97 - while(likely(j < max_words)) words[j++] = NULL;
105 + while (likely(j < max_words))
106 + words[j++] = NULL;
107
108 return i;
109 }
110
102 -inline int pluginsd_initialize_plugin_directories() {
111 +inline int pluginsd_initialize_plugin_directories()
112 +{
113 char plugins_dirs[(FILENAME_MAX * 2) + 1];
114 static char *plugins_dir_list = NULL;
115
116 // Get the configuration entry
107 - if(likely(!plugins_dir_list)) {
117 + if (likely(!plugins_dir_list)) {
118 snprintfz(plugins_dirs, FILENAME_MAX * 2, "\"%s\" \"%s/custom-plugins.d\"", PLUGINS_DIR, CONFIG_DIR);
109 - plugins_dir_list = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs));
119 + plugins_dir_list = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs));
120 }
121
122 // Parse it and store it to plugin directories
123 return quoted_strings_splitter(plugins_dir_list, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace);
124 }
125
116 -inline int pluginsd_split_words(char *str, char **words, int max_words) {
126 +inline int pluginsd_split_words(char *str, char **words, int max_words)
127 +{
128 return quoted_strings_splitter(str, words, max_words, pluginsd_space);
129 }
130
@@ -128,28 +139,28 @@ inline int pluginsd_split_words(char *str, char **words, int max_words) {
139 *
140 * @return it returns the total of bytes read on success and a negative number otherwise
141 */
131 -int pluginsd_update_buffer(char *output, SSL *ssl) {
142 +int pluginsd_update_buffer(char *output, SSL *ssl)
143 +{
144 ERR_clear_error();
145 int bytesleft = SSL_read(ssl, output, PLUGINSD_LINE_MAX_SSL_READ);
134 - if(bytesleft <= 0) {
146 + if (bytesleft <= 0) {
147 int sslerrno = SSL_get_error(ssl, bytesleft);
136 - switch(sslerrno) {
148 + switch (sslerrno) {
149 case SSL_ERROR_WANT_READ:
138 - case SSL_ERROR_WANT_WRITE:
139 - {
150 + case SSL_ERROR_WANT_WRITE: {
151 break;
152 }
142 - default:
143 - {
153 + default: {
154 u_long err;
155 char buf[256];
156 int counter = 0;
157 while ((err = ERR_get_error()) != 0) {
158 ERR_error_string_n(err, buf, sizeof(buf));
149 - info("%d SSL Handshake error (%s) on socket %d ", counter++, ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
159 + info(
160 + "%d SSL Handshake error (%s) on socket %d ", counter++,
161 + ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
162 }
163 }
152 -
164 }
165 } else {
166 output[bytesleft] = '\0';
@@ -171,14 +182,15 @@ int pluginsd_update_buffer(char *output, SSL *ssl) {
182 *
183 * @return It returns a pointer for the next iteration on success and NULL otherwise.
184 */
174 -char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src) {
185 +char *pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src)
186 +{
187 int copying = 1;
188 char *endbuffer;
189 size_t length;
178 - while(copying) {
179 - if(*bytesread > 0) {
190 + while (copying) {
191 + if (*bytesread > 0) {
192 endbuffer = strchr(input, '\n');
181 - if(endbuffer) {
193 + if (endbuffer) {
194 copying = 0;
195 endbuffer++; //Advance due the fact I wanna copy '\n'
196 length = endbuffer - input;
@@ -188,22 +200,22 @@ char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *
200 output += length;
201 *output = '\0';
202 input += length;
191 - }else {
203 + } else {
204 length = strlen(input);
205 memcpy(output, input, length);
206 output += length;
207 input = src;
208
209 *bytesread = pluginsd_update_buffer(input, ssl);
198 - if(*bytesread <= 0) {
210 + if (*bytesread <= 0) {
211 input = NULL;
212 copying = 0;
213 }
214 }
203 - }else {
215 + } else {
216 //reduce sample of bytes read, print the length
217 *bytesread = pluginsd_update_buffer(input, ssl);
206 - if(*bytesread <= 0) {
218 + if (*bytesread <= 0) {
219 input = NULL;
220 copying = 0;
221 }
@@ -214,10 +226,11 @@ char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *
226 }
227 #endif
228
217 -inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
229 +inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations)
230 +{
231 int enabled = cd->enabled;
232
220 - if(!fp || !enabled) {
233 + if (!fp || !enabled) {
234 cd->enabled = 0;
235 return 0;
236 }
@@ -244,7 +257,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
257 errno = 0;
258 clearerr(fp);
259
247 - if(unlikely(fileno(fp) == -1)) {
260 + if (unlikely(fileno(fp) == -1)) {
261 error("file descriptor given is not a valid stream");
262 goto cleanup;
263 }
@@ -255,24 +268,25 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
268 char *readfrom = NULL;
269 #endif
270 char *r = NULL;
258 - while(!ferror(fp)) {
259 - if(unlikely(netdata_exit)) break;
271 + while (!ferror(fp)) {
272 + if (unlikely(netdata_exit))
273 + break;
274
275 #ifdef ENABLE_HTTPS
276 int normalread = 1;
263 - if(netdata_srv_ctx) {
264 - if(host->stream_ssl.conn && !host->stream_ssl.flags) {
265 - if(!bytesleft) {
277 + if (netdata_srv_ctx) {
278 + if (host->stream_ssl.conn && !host->stream_ssl.flags) {
279 + if (!bytesleft) {
280 r = line;
281 readfrom = tmpbuffer;
282 bytesleft = pluginsd_update_buffer(readfrom, host->stream_ssl.conn);
269 - if(bytesleft <= 0) {
283 + if (bytesleft <= 0) {
284 break;
285 }
286 }
287
274 - readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->stream_ssl.conn, tmpbuffer);
275 - if(!readfrom) {
288 + readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->stream_ssl.conn, tmpbuffer);
289 + if (!readfrom) {
290 r = NULL;
291 }
292
@@ -280,227 +294,225 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
294 }
295 }
296
283 - if(normalread) {
297 + if (normalread) {
298 r = fgets(line, PLUGINSD_LINE_MAX, fp);
299 }
300 #else
301 r = fgets(line, PLUGINSD_LINE_MAX, fp);
302 #endif
303
290 - if(unlikely(!r)) {
291 - if(feof(fp))
304 + if (unlikely(!r)) {
305 + if (feof(fp))
306 error("read failed: end of file");
293 - else if(ferror(fp))
307 + else if (ferror(fp))
308 error("read failed: input error");
309 else
310 error("read failed: unknown error");
311 break;
312 }
313
300 - if(unlikely(netdata_exit)) break;
314 + if (unlikely(netdata_exit))
315 + break;
316
317 line[PLUGINSD_LINE_MAX] = '\0';
318
319 int w = pluginsd_split_words(line, words, PLUGINSD_MAX_WORDS);
320 char *s = words[0];
306 - if(unlikely(!s || !*s || !w)) {
321 + if (unlikely(!s || !*s || !w)) {
322 continue;
323 }
324
325 // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
326
312 - if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
327 + if (likely(!simple_hash_strcmp(s, "SET", &hash))) {
328 char *dimension = words[1];
329 char *value = words[2];
330
316 - if(unlikely(!dimension || !*dimension)) {
317 - error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, host->hostname);
331 + if (unlikely(!dimension || !*dimension)) {
332 + error(
333 + "requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id,
334 + host->hostname);
335 enabled = 0;
336 break;
337 }
338
322 - if(unlikely(!value || !*value)) value = NULL;
339 + if (unlikely(!value || !*value))
340 + value = NULL;
341
324 - if(unlikely(!st)) {
325 - error("requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", dimension, value?value:"<nothing>", host->hostname);
342 + if (unlikely(!st)) {
343 + error(
344 + "requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.",
345 + dimension, value ? value : "<nothing>", host->hostname);
346 enabled = 0;
347 break;
348 }
349
330 - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
331 - debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value?value:"<nothing>");
350 + if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
351 + debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value ? value : "<nothing>");
352
333 - if(value) {
353 + if (value) {
354 RRDDIM *rd = rrddim_find(st, dimension);
335 - if(unlikely(!rd)) {
336 - error("requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.", dimension, st->name, st->id, st->rrdhost->hostname);
355 + if (unlikely(!rd)) {
356 + error(
357 + "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.",
358 + dimension, st->name, st->id, st->rrdhost->hostname);
359 enabled = 0;
360 break;
339 - }
340 - else
361 + } else
362 rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0));
363 }
343 - }
344 - else if(likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) {
364 + } else if (likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) {
365 char *id = words[1];
366 char *microseconds_txt = words[2];
367
348 - if(unlikely(!id)) {
368 + if (unlikely(!id)) {
369 error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname);
370 enabled = 0;
371 break;
372 }
373
374 st = rrdset_find(host, id);
355 - if(unlikely(!st)) {
356 - error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, host->hostname);
375 + if (unlikely(!st)) {
376 + error(
377 + "requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id,
378 + host->hostname);
379 enabled = 0;
380 break;
381 }
382
361 - if(likely(st->counter_done)) {
383 + if (likely(st->counter_done)) {
384 usec_t microseconds = 0;
363 - if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
385 + if (microseconds_txt && *microseconds_txt)
386 + microseconds = str2ull(microseconds_txt);
387
365 - if(likely(microseconds)) {
366 - if(trust_durations)
388 + if (likely(microseconds)) {
389 + if (trust_durations)
390 rrdset_next_usec_unfiltered(st, microseconds);
391 else
392 rrdset_next_usec(st, microseconds);
370 - }
371 - else rrdset_next(st);
393 + } else
394 + rrdset_next(st);
395 }
373 - }
374 - else if(likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) {
375 - if(unlikely(!st)) {
396 + } else if (likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) {
397 + if (unlikely(!st)) {
398 error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname);
399 enabled = 0;
400 break;
401 }
402
381 - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
403 + if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
404 debug(D_PLUGINSD, "requested an END on chart %s", st->id);
405
406 rrdset_done(st);
407 st = NULL;
408
409 count++;
388 - }
389 - else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
410 + } else if (likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
411 st = NULL;
412
392 - char *type = words[1];
393 - char *name = words[2];
394 - char *title = words[3];
395 - char *units = words[4];
396 - char *family = words[5];
397 - char *context = words[6];
398 - char *chart = words[7];
399 - char *priority_s = words[8];
413 + char *type = words[1];
414 + char *name = words[2];
415 + char *title = words[3];
416 + char *units = words[4];
417 + char *family = words[5];
418 + char *context = words[6];
419 + char *chart = words[7];
420 + char *priority_s = words[8];
421 char *update_every_s = words[9];
401 - char *options = words[10];
402 - char *plugin = words[11];
403 - char *module = words[12];
422 + char *options = words[10];
423 + char *plugin = words[11];
424 + char *module = words[12];
425
426 // parse the id from type
427 char *id = NULL;
407 - if(likely(type && (id = strchr(type, '.')))) {
428 + if (likely(type && (id = strchr(type, '.')))) {
429 *id = '\0';
430 id++;
431 }
432
433 // make sure we have the required variables
413 - if(unlikely(!type || !*type || !id || !*id)) {
434 + if (unlikely(!type || !*type || !id || !*id)) {
435 error("requested a CHART, without a type.id, on host '%s'. Disabling it.", host->hostname);
436 enabled = 0;
437 break;
438 }
439
440 // parse the name, and make sure it does not include 'type.'
420 - if(unlikely(name && *name)) {
441 + if (unlikely(name && *name)) {
442 // when data are coming from slaves
443 // name will be type.name
444 // so we have to remove 'type.' from name too
445 size_t len = strlen(type);
425 - if(strncmp(type, name, len) == 0 && name[len] == '.')
446 + if (strncmp(type, name, len) == 0 && name[len] == '.')
447 name = &name[len + 1];
448
449 // if the name is the same with the id,
450 // or is just 'NULL', clear it.
430 - if(unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0))
451 + if (unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0))
452 name = NULL;
453 }
454
455 int priority = 1000;
435 - if(likely(priority_s && *priority_s)) priority = str2i(priority_s);
456 + if (likely(priority_s && *priority_s))
457 + priority = str2i(priority_s);
458
459 int update_every = cd->update_every;
438 - if(likely(update_every_s && *update_every_s)) update_every = str2i(update_every_s);
439 - if(unlikely(!update_every)) update_every = cd->update_every;
460 + if (likely(update_every_s && *update_every_s))
461 + update_every = str2i(update_every_s);
462 + if (unlikely(!update_every))
463 + update_every = cd->update_every;
464
465 RRDSET_TYPE chart_type = RRDSET_TYPE_LINE;
442 - if(unlikely(chart)) chart_type = rrdset_type_id(chart);
443 -
444 - if(unlikely(name && !*name)) name = NULL;
445 - if(unlikely(family && !*family)) family = NULL;
446 - if(unlikely(context && !*context)) context = NULL;
447 - if(unlikely(!title)) title = "";
448 - if(unlikely(!units)) units = "unknown";
449 -
450 - debug(D_PLUGINSD, "creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
451 - , type, id
452 - , name?name:""
453 - , family?family:""
454 - , context?context:""
455 - , rrdset_type_name(chart_type)
456 - , priority
457 - , update_every
458 - );
466 + if (unlikely(chart))
467 + chart_type = rrdset_type_id(chart);
468 +
469 + if (unlikely(name && !*name))
470 + name = NULL;
471 + if (unlikely(family && !*family))
472 + family = NULL;
473 + if (unlikely(context && !*context))
474 + context = NULL;
475 + if (unlikely(!title))
476 + title = "";
477 + if (unlikely(!units))
478 + units = "unknown";
479 +
480 + debug(
481 + D_PLUGINSD,
482 + "creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d",
483 + type, id, name ? name : "", family ? family : "", context ? context : "", rrdset_type_name(chart_type),
484 + priority, update_every);
485
486 st = rrdset_create(
461 - host
462 - , type
463 - , id
464 - , name
465 - , family
466 - , context
467 - , title
468 - , units
469 - , (plugin && *plugin)?plugin:cd->filename
470 - , module
471 - , priority
472 - , update_every
473 - , chart_type
474 - );
475 -
476 - if(options && *options) {
477 - if(strstr(options, "obsolete"))
487 + host, type, id, name, family, context, title, units, (plugin && *plugin) ? plugin : cd->filename,
488 + module, priority, update_every, chart_type);
489 +
490 + if (options && *options) {
491 + if (strstr(options, "obsolete"))
492 rrdset_is_obsolete(st);
493 else
494 rrdset_isnot_obsolete(st);
495
482 - if(strstr(options, "detail"))
496 + if (strstr(options, "detail"))
497 rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
498 else
499 rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
500
487 - if(strstr(options, "hidden"))
501 + if (strstr(options, "hidden"))
502 rrdset_flag_set(st, RRDSET_FLAG_HIDDEN);
503 else
504 rrdset_flag_clear(st, RRDSET_FLAG_HIDDEN);
505
492 - if(strstr(options, "store_first"))
506 + if (strstr(options, "store_first"))
507 rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST);
508 else
509 rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST);
496 - }
497 - else {
510 + } else {
511 rrdset_isnot_obsolete(st);
512 rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
513 rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST);
514 }
502 - }
503 - else if(likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) {
515 + } else if (likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) {
516 char *id = words[1];
517 char *name = words[2];
518 char *algorithm = words[3];
@@ -508,122 +520,131 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
520 char *divisor_s = words[5];
521 char *options = words[6];
522
511 - if(unlikely(!id || !*id)) {
512 - error("requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname, st?st->id:"UNSET");
523 + if (unlikely(!id || !*id)) {
524 + error(
525 + "requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname,
526 + st ? st->id : "UNSET");
527 enabled = 0;
528 break;
529 }
530
517 - if(unlikely(!st)) {
531 + if (unlikely(!st)) {
532 error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", host->hostname);
533 enabled = 0;
534 break;
535 }
536
537 long multiplier = 1;
524 - if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
525 - if(unlikely(!multiplier)) multiplier = 1;
538 + if (multiplier_s && *multiplier_s)
539 + multiplier = strtol(multiplier_s, NULL, 0);
540 + if (unlikely(!multiplier))
541 + multiplier = 1;
542
543 long divisor = 1;
528 - if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
529 - if(unlikely(!divisor)) divisor = 1;
530 -
531 - if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
532 -
533 - if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
534 - debug(D_PLUGINSD, "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
535 - , st->id
536 - , id
537 - , name?name:""
538 - , rrd_algorithm_name(rrd_algorithm_id(algorithm))
539 - , multiplier
540 - , divisor
541 - , options?options:""
542 - );
544 + if (likely(divisor_s && *divisor_s))
545 + divisor = strtol(divisor_s, NULL, 0);
546 + if (unlikely(!divisor))
547 + divisor = 1;
548 +
549 + if (unlikely(!algorithm || !*algorithm))
550 + algorithm = "absolute";
551 +
552 + if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
553 + debug(
554 + D_PLUGINSD,
555 + "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'",
556 + st->id, id, name ? name : "", rrd_algorithm_name(rrd_algorithm_id(algorithm)), multiplier, divisor,
557 + options ? options : "");
558
559 RRDDIM *rd = rrddim_add(st, id, name, multiplier, divisor, rrd_algorithm_id(algorithm));
560 rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
561 rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
547 - if(options && *options) {
548 - if(strstr(options, "obsolete") != NULL)
562 + if (options && *options) {
563 + if (strstr(options, "obsolete") != NULL)
564 rrddim_is_obsolete(st, rd);
565 else
566 rrddim_isnot_obsolete(st, rd);
552 - if(strstr(options, "hidden") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
553 - if(strstr(options, "noreset") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
554 - if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
555 - }
556 - else {
567 + if (strstr(options, "hidden") != NULL)
568 + rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
569 + if (strstr(options, "noreset") != NULL)
570 + rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
571 + if (strstr(options, "nooverflow") != NULL)
572 + rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
573 + } else {
574 rrddim_isnot_obsolete(st, rd);
575 }
559 - }
560 - else if(likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) {
576 + } else if (likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) {
577 char *name = words[1];
578 char *value = words[2];
563 - int global = (st)?0:1;
579 + int global = (st) ? 0 : 1;
580
565 - if(name && *name) {
566 - if((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) {
581 + if (name && *name) {
582 + if ((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) {
583 global = 1;
584 name = words[2];
569 - value = words[3];
570 - }
571 - else if((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) {
585 + value = words[3];
586 + } else if ((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) {
587 global = 0;
588 name = words[2];
574 - value = words[3];
589 + value = words[3];
590 }
591 }
592
578 - if(unlikely(!name || !*name)) {
593 + if (unlikely(!name || !*name)) {
594 error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", host->hostname);
595 enabled = 0;
596 break;
597 }
598
584 - if(unlikely(!value || !*value))
599 + if (unlikely(!value || !*value))
600 value = NULL;
601
587 - if(value) {
602 + if (value) {
603 char *endptr = NULL;
604 calculated_number v = (calculated_number)str2ld(value, &endptr);
605
591 - if(unlikely(endptr && *endptr)) {
592 - if(endptr == value)
593 - error("the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name, host->hostname);
606 + if (unlikely(endptr && *endptr)) {
607 + if (endptr == value)
608 + error(
609 + "the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name,
610 + host->hostname);
611 else
595 - error("the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, host->hostname, endptr);
612 + error(
613 + "the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name,
614 + host->hostname, endptr);
615 }
616
598 - if(global) {
617 + if (global) {
618 RRDVAR *rv = rrdvar_custom_host_variable_create(host, name);
600 - if (rv) rrdvar_custom_host_variable_set(host, rv, v);
601 - else error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname);
602 - }
603 - else if(st) {
619 + if (rv)
620 + rrdvar_custom_host_variable_set(host, rv, v);
621 + else
622 + error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname);
623 + } else if (st) {
624 RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name);
605 - if (rs) rrdsetvar_custom_chart_variable_set(rs, v);
606 - else error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, st->id);
607 - }
608 - else
625 + if (rs)
626 + rrdsetvar_custom_chart_variable_set(rs, v);
627 + else
628 + error(
629 + "cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname,
630 + st->id);
631 + } else
632 error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, host->hostname);
610 - }
611 - else
612 - error("cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global)?"HOST":"CHART", name, host->hostname);
613 - }
614 - else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) {
633 + } else
634 + error(
635 + "cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global) ? "HOST" : "CHART", name,
636 + host->hostname);
637 + } else if (likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) {
638 debug(D_PLUGINSD, "requested a FLUSH");
639 st = NULL;
617 - }
618 - else if(unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) {
640 + } else if (unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) {
641 info("called DISABLE. Disabling it.");
642 enabled = 0;
643 break;
622 - }
623 - else if(likely(hash == LABEL_HASH && !strcmp(s, PLUGINSD_KEYWORD_LABEL))) {
644 + } else if (likely(hash == LABEL_HASH && !strcmp(s, PLUGINSD_KEYWORD_LABEL))) {
645 debug(D_PLUGINSD, "requested a LABEL CHANGE");
646 char *store;
626 - if(!words[4])
647 + if (!words[4])
648 store = words[3];
649 else {
650 store = callocz(PLUGINSD_LINE_MAX + 1, sizeof(char));
@@ -635,13 +656,13 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
656 if ((length + 1) >= remaining)
657 break;
658
638 - remaining -= (length +1);
659 + remaining -= (length + 1);
660 memcpy(move, words[i], length);
661 move += length;
662 *move++ = ' ';
663
664 i++;
644 - if(!words[i])
665 + if (!words[i])
666 break;
667 }
668 }
@@ -649,10 +670,9 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
670 new_labels = add_label_to_list(new_labels, words[1], store, strtol(words[2], NULL, 10));
671 if (store != words[3])
672 freez(store);
652 - }
653 - else if(likely(hash == OVERWRITE_HASH && !strcmp(s, PLUGINSD_KEYWORD_OVERWRITE))) {
673 + } else if (likely(hash == OVERWRITE_HASH && !strcmp(s, PLUGINSD_KEYWORD_OVERWRITE))) {
674 debug(D_PLUGINSD, "requested a OVERWITE a variable");
655 - if(!host->labels) {
675 + if (!host->labels) {
676 host->labels = new_labels;
677 } else {
678 rrdhost_rdlock(host);
@@ -661,8 +681,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
681 }
682
683 new_labels = NULL;
664 - }
665 - else {
684 + } else {
685 error("sent command '%s' which is not known by netdata, for host '%s'. Disabling it.", s, host->hostname);
686 enabled = 0;
687 break;
@@ -672,23 +691,23 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
691 cleanup:
692 cd->enabled = enabled;
693
675 - if(new_labels)
694 + if (new_labels)
695 free_host_labels(new_labels);
696
678 - if(likely(count)) {
697 + if (likely(count)) {
698 cd->successful_collections += count;
699 cd->serial_failures = 0;
681 - }
682 - else
700 + } else
701 cd->serial_failures++;
702
703 return count;
704 }
705
688 -static void pluginsd_worker_thread_cleanup(void *arg) {
706 +static void pluginsd_worker_thread_cleanup(void *arg)
707 +{
708 struct plugind *cd = (struct plugind *)arg;
709
691 - if(cd->enabled && !cd->obsolete) {
710 + if (cd->enabled && !cd->obsolete) {
711 cd->obsolete = 1;
712
713 info("data collection thread exiting");
@@ -698,7 +717,7 @@ static void pluginsd_worker_thread_cleanup(void *arg) {
717 info("killing child process pid %d", cd->pid);
718 if (killpid(cd->pid) != -1) {
719 info("waiting for child process pid %d to exit...", cd->pid);
701 - waitid(P_PID, (id_t) cd->pid, &info, WEXITED);
720 + waitid(P_PID, (id_t)cd->pid, &info, WEXITED);
721 }
722 cd->pid = 0;
723 }
@@ -706,24 +725,25 @@ static void pluginsd_worker_thread_cleanup(void *arg) {
725 }
726
727 #define SERIAL_FAILURES_THRESHOLD 10
709 -static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
728 +static void pluginsd_worker_thread_handle_success(struct plugind *cd)
729 +{
730 if (likely(cd->successful_collections)) {
711 - sleep((unsigned int) cd->update_every);
731 + sleep((unsigned int)cd->update_every);
732 return;
733 }
734
715 - if(likely(cd->serial_failures <= SERIAL_FAILURES_THRESHOLD)) {
716 - info("'%s' (pid %d) does not generate useful output but it reports success (exits with 0). %s.",
735 + if (likely(cd->serial_failures <= SERIAL_FAILURES_THRESHOLD)) {
736 + info(
737 + "'%s' (pid %d) does not generate useful output but it reports success (exits with 0). %s.",
738 cd->fullfilename, cd->pid,
718 - cd->enabled ?
719 - "Waiting a bit before starting it again." :
720 - "Will not start it again - it is now disabled.");
721 - sleep((unsigned int) (cd->update_every * 10));
739 + cd->enabled ? "Waiting a bit before starting it again." : "Will not start it again - it is now disabled.");
740 + sleep((unsigned int)(cd->update_every * 10));
741 return;
742 }
743
744 if (cd->serial_failures > SERIAL_FAILURES_THRESHOLD) {
726 - error("'%s' (pid %d) does not generate useful output, although it reports success (exits with 0)."
745 + error(
746 + "'%s' (pid %d) does not generate useful output, although it reports success (exits with 0)."
747 "We have tried to collect something %zu times - unsuccessfully. Disabling it.",
748 cd->fullfilename, cd->pid, cd->serial_failures);
749 cd->enabled = 0;
@@ -733,7 +753,8 @@ static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
753 return;
754 }
755
736 -static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_ret_code) {
756 +static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_ret_code)
757 +{
758 if (worker_ret_code == -1) {
759 info("'%s' (pid %d) was killed with SIGTERM. Disabling it.", cd->fullfilename, cd->pid);
760 cd->enabled = 0;
@@ -741,24 +762,25 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
762 }
763
764 if (!cd->successful_collections) {
744 - error("'%s' (pid %d) exited with error code %d and haven't collected any data. Disabling it.",
745 - cd->fullfilename, cd->pid, worker_ret_code);
765 + error(
766 + "'%s' (pid %d) exited with error code %d and haven't collected any data. Disabling it.", cd->fullfilename,
767 + cd->pid, worker_ret_code);
768 cd->enabled = 0;
769 return;
770 }
771
772 if (cd->serial_failures <= SERIAL_FAILURES_THRESHOLD) {
751 - error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
773 + error(
774 + "'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
775 cd->fullfilename, cd->pid, worker_ret_code, cd->successful_collections,
753 - cd->enabled ?
754 - "Waiting a bit before starting it again." :
755 - "Will not start it again - it is disabled.");
756 - sleep((unsigned int) (cd->update_every * 10));
776 + cd->enabled ? "Waiting a bit before starting it again." : "Will not start it again - it is disabled.");
777 + sleep((unsigned int)(cd->update_every * 10));
778 return;
779 }
780
781 if (cd->serial_failures > SERIAL_FAILURES_THRESHOLD) {
761 - error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times)."
782 + error(
783 + "'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times)."
784 "We tried to restart it %zu times, but it failed to generate data. Disabling it.",
785 cd->fullfilename, cd->pid, worker_ret_code, cd->successful_collections, cd->serial_failures);
786 cd->enabled = 0;
@@ -769,7 +791,8 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
791 }
792 #undef SERIAL_FAILURES_THRESHOLD
793
772 -void *pluginsd_worker_thread(void *arg) {
794 +void *pluginsd_worker_thread(void *arg)
795 +{
796 netdata_thread_cleanup_push(pluginsd_worker_thread_cleanup, arg);
797
798 struct plugind *cd = (struct plugind *)arg;
@@ -777,16 +800,18 @@ void *pluginsd_worker_thread(void *arg) {
800 cd->obsolete = 0;
801 size_t count = 0;
802
780 - while(!netdata_exit) {
803 + while (!netdata_exit) {
804 FILE *fp = mypopen(cd->cmd, &cd->pid);
782 - if(unlikely(!fp)) {
805 + if (unlikely(!fp)) {
806 error("Cannot popen(\"%s\", \"r\").", cd->cmd);
807 break;
808 }
809
810 info("connected to '%s' running on pid %d", cd->fullfilename, cd->pid);
811 count = pluginsd_process(localhost, cd, fp, 0);
789 - error("'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
812 + error(
813 + "'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid,
814 + count);
815 killpid(cd->pid);
816
817 int worker_ret_code = mypclose(fp, cd->pid);
@@ -797,14 +822,16 @@ void *pluginsd_worker_thread(void *arg) {
822 pluginsd_worker_thread_handle_error(cd, worker_ret_code);
823
824 cd->pid = 0;
800 - if(unlikely(!cd->enabled)) break;
825 + if (unlikely(!cd->enabled))
826 + break;
827 }
828
829 netdata_thread_cleanup_pop(1);
830 return NULL;
831 }
832
807 -static void pluginsd_main_cleanup(void *data) {
833 +static void pluginsd_main_cleanup(void *data)
834 +{
835 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
836 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
837 info("cleaning up...");
@@ -821,32 +848,34 @@ static void pluginsd_main_cleanup(void *data) {
848 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
849 }
850
824 -void *pluginsd_main(void *ptr) {
851 +void *pluginsd_main(void *ptr)
852 +{
853 netdata_thread_cleanup_push(pluginsd_main_cleanup, ptr);
854
855 int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
828 - int scan_frequency = (int) config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
829 - if(scan_frequency < 1) scan_frequency = 1;
856 + int scan_frequency = (int)config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
857 + if (scan_frequency < 1)
858 + scan_frequency = 1;
859
860 // disable some plugins by default
861 config_get_boolean(CONFIG_SECTION_PLUGINS, "slabinfo", CONFIG_BOOLEAN_NO);
833 - config_get_boolean(CONFIG_SECTION_PLUGINS, "ebpf", CONFIG_BOOLEAN_NO);
862
863 // store the errno for each plugins directory
864 // so that we don't log broken directories on each loop
837 - int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 };
865 + int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 };
866
839 - while(!netdata_exit) {
867 + while (!netdata_exit) {
868 int idx;
869 const char *directory_name;
870
843 - for( idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]) ; idx++ ) {
844 - if(unlikely(netdata_exit)) break;
871 + for (idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]); idx++) {
872 + if (unlikely(netdata_exit))
873 + break;
874
875 errno = 0;
876 DIR *dir = opendir(directory_name);
848 - if(unlikely(!dir)) {
849 - if(directory_errors[idx] != errno) {
877 + if (unlikely(!dir)) {
878 + if (directory_errors[idx] != errno) {
879 directory_errors[idx] = errno;
880 error("cannot open plugins directory '%s'", directory_name);
881 }
@@ -854,16 +883,19 @@ void *pluginsd_main(void *ptr) {
883 }
884
885 struct dirent *file = NULL;
857 - while(likely((file = readdir(dir)))) {
858 - if(unlikely(netdata_exit)) break;
886 + while (likely((file = readdir(dir)))) {
887 + if (unlikely(netdata_exit))
888 + break;
889
890 debug(D_PLUGINSD, "examining file '%s'", file->d_name);
891
862 - if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
892 + if (unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0))
893 + continue;
894
864 - int len = (int) strlen(file->d_name);
865 - if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
866 - if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
895 + int len = (int)strlen(file->d_name);
896 + if (unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN))
897 + continue;
898 + if (unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
899 debug(D_PLUGINSD, "file '%s' does not end in '%s'", file->d_name, PLUGINSD_FILE_SUFFIX);
900 continue;
901 }
@@ -872,24 +904,25 @@ void *pluginsd_main(void *ptr) {
904 snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
905 int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run);
906
875 - if(unlikely(!enabled)) {
907 + if (unlikely(!enabled)) {
908 debug(D_PLUGINSD, "plugin '%s' is not enabled", file->d_name);
909 continue;
910 }
911
912 // check if it runs already
913 struct plugind *cd;
882 - for(cd = pluginsd_root ; cd ; cd = cd->next)
883 - if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
914 + for (cd = pluginsd_root; cd; cd = cd->next)
915 + if (unlikely(strcmp(cd->filename, file->d_name) == 0))
916 + break;
917
885 - if(likely(cd && !cd->obsolete)) {
918 + if (likely(cd && !cd->obsolete)) {
919 debug(D_PLUGINSD, "plugin '%s' is already running", cd->filename);
920 continue;
921 }
922
923 // it is not running
924 // allocate a new one, or use the obsolete one
892 - if(unlikely(!cd)) {
925 + if (unlikely(!cd)) {
926 cd = callocz(sizeof(struct plugind), 1);
927
928 snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
@@ -898,24 +931,28 @@ void *pluginsd_main(void *ptr) {
931 snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", directory_name, cd->filename);
932
933 cd->enabled = enabled;
901 - cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every);
934 + cd->update_every = (int)config_get_number(cd->id, "update every", localhost->rrd_update_every);
935 cd->started_t = now_realtime_sec();
936
937 char *def = "";
905 - snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
938 + snprintfz(
939 + cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every,
940 + config_get(cd->id, "command options", def));
941
942 // link it
908 - if(likely(pluginsd_root)) cd->next = pluginsd_root;
943 + if (likely(pluginsd_root))
944 + cd->next = pluginsd_root;
945 pluginsd_root = cd;
946
947 // it is not currently running
948 cd->obsolete = 1;
949
914 - if(cd->enabled) {
950 + if (cd->enabled) {
951 char tag[NETDATA_THREAD_TAG_MAX + 1];
952 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PLUGINSD[%s]", pluginname);
953 // spawn a new thread for it
918 - netdata_thread_create(&cd->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, pluginsd_worker_thread, cd);
954 + netdata_thread_create(
955 + &cd->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, pluginsd_worker_thread, cd);
956 }
957 }
958 }
@@ -923,7 +960,7 @@ void *pluginsd_main(void *ptr) {
960 closedir(dir);
961 }
962
926 - sleep((unsigned int) scan_frequency);
963 + sleep((unsigned int)scan_frequency);
964 }
965
966 netdata_thread_cleanup_pop(1);
libnetdata/ebpf/ebpf.c
+26 -1
@@ -53,11 +53,12 @@ int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr) {
53
54 //----------------------------------------------------------------------------------------------------------------------
55
56 -int get_kernel_version() {
56 +int get_kernel_version(char *out, int size) {
57 char major[16], minor[16], patch[16];
58 char ver[256];
59 char *version = ver;
60
61 + out[0] = '\0';
62 int fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
63 if (fd < 0)
64 return -1;
@@ -88,6 +89,10 @@ int get_kernel_version() {
89 while (*version) *move++ = *version++;
90 *move = '\0';
91
92 + fd = snprintf(out, (size_t)size, "%s.%s.%s", major, minor, patch);
93 + if (fd > size)
94 + error("[EBPF]: The buffer to store kernel version is not smaller than necessary.");
95 +
96 return ((int)(str2l(major)*65536) + (int)(str2l(minor)*256) + (int)str2l(patch));
97 }
98
@@ -143,3 +148,23 @@ int has_condition_to_run(int version) {
148
149 return 1;
150 }
151 +
152 +//----------------------------------------------------------------------------------------------------------------------
153 +
154 +char *ebpf_library_suffix(int version, int isrh) {
155 + if (isrh) {
156 + if (version >= NETDATA_EBPF_KERNEL_4_11)
157 + return "4.18.0";
158 + else
159 + return "3.10.0";
160 + } else {
161 + if (version >= NETDATA_EBPF_KERNEL_4_17)
162 + return "5.4.20";
163 + else if (version >= NETDATA_EBPF_KERNEL_4_15)
164 + return "4.16.18";
165 + else if (version >= NETDATA_EBPF_KERNEL_4_11)
166 + return "4.14.171";
167 + }
168 +
169 + return NULL;
170 +}
libnetdata/ebpf/ebpf.h
+22 -1
@@ -26,6 +26,26 @@
26 */
27 # define NETDATA_RH_8 2048
28
29 +/**
30 + * Kernel 4.17
31 + *
32 + * 266496 = 4*65536 + 17*256
33 + */
34 +# define NETDATA_EBPF_KERNEL_4_17 266496
35 +
36 +/**
37 + * Kernel 4.15
38 + *
39 + * 265984 = 4*65536 + 15*256
40 + */
41 +# define NETDATA_EBPF_KERNEL_4_15 265984
42 +
43 +/**
44 + * Kernel 4.11
45 + *
46 + * 264960 = 4*65536 + 15*256
47 + */
48 +# define NETDATA_EBPF_KERNEL_4_11 264960
49
50 typedef struct netdata_ebpf_events {
51 char type;
@@ -34,8 +54,9 @@ typedef struct netdata_ebpf_events {
54 } netdata_ebpf_events_t;
55
56 extern int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr);
37 -extern int get_kernel_version();
57 +extern int get_kernel_version(char *out, int size);
58 extern int get_redhat_release();
59 extern int has_condition_to_run(int version);
60 +extern char *ebpf_library_suffix(int version, int isrh);
61
62 #endif
netdata-installer.sh
+39 -121
@@ -192,7 +192,7 @@ USAGE: ${PROGRAM} [options]
192 --nightly-channel Use most recent nightly udpates instead of GitHub releases.
193 This results in more frequent updates.
194 --disable-go Disable installation of go.d.plugin.
195 - --enable-ebpf Enable eBPF Kernel plugin (Default: disabled, feature preview)
195 + --disable-ebpf Disable eBPF Kernel plugin (Default: enabled)
196 --disable-cloud Disable all Netdata Cloud functionality.
197 --require-cloud Fail the install if it can't build Netdata Cloud support.
198 --enable-plugin-freeipmi Enable the FreeIPMI plugin. Default: enable it when libipmimonitoring is available.
@@ -279,7 +279,7 @@ while [ -n "${1}" ]; do
279 "--disable-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse" ;;
280 "--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1 ;;
281 "--disable-go") NETDATA_DISABLE_GO=1 ;;
282 - "--enable-ebpf") NETDATA_ENABLE_EBPF=1 ;;
282 + "--disable-ebpf") NETDATA_DISABLE_EBPF=1 ;;
283 "--disable-cloud")
284 if [ -n "${NETDATA_REQUIRE_CLOUD}" ]; then
285 echo "Cloud explicitly enabled, ignoring --disable-cloud."
@@ -1281,6 +1281,19 @@ function get_kernel_version() {
1281 printf "%03d%03d%03d" "${p[0]}" "${p[1]}" "${p[2]}"
1282 }
1283
1284 +function get_rh_version() {
1285 + if [ ! -f /etc/redhat-release ]; then
1286 + printf "000000000"
1287 + return
1288 + fi
1289 +
1290 + r="$(cut -f 4 -d ' ' < /etc/redhat-release)"
1291 +
1292 + read -r -a p <<< "$(echo "${r}" | tr '.' ' ')"
1293 +
1294 + printf "%03d%03d%03d" "${p[0]}" "${p[1]}" "${p[2]}"
1295 +}
1296 +
1297 detect_libc() {
1298 libc=
1299 if ldd --version 2>&1 | grep -q -i glibc; then
@@ -1300,106 +1313,37 @@ detect_libc() {
1313 return 0
1314 }
1315
1303 -get_compatible_kernel_for_ebpf() {
1304 - kver="${1}"
1305 -
1306 - # XXX: Logic taken from Slack discussion in #ebpf
1307 - # everything that has a version <= 4.14 can use the code built to 4.14
1308 - # also all distributions that has a version <= 4.15.256 can use the code built to 4.15
1309 - # Continue the logic, everything that has a version < 4.19.102 and >= 4.15 can use the code built to 4.19
1310 - # Kernel 4.19 had a feature added in the version 4.19.102 that force us to break it in two, so version >= 4.19.102
1311 - # and smaller than < 5.0 runs with code built to 4.19.102
1312 - # Finally, everybody that is using 5.X can use what is compiled with 5.4
1313 -
1314 - kpkg=
1315 -
1316 - if [ "${kver}" -ge 005000000 ]; then
1317 - echo >&2 " Using eBPF Kernel Package built against Linux 5.4.20"
1318 - kpkg="5_4_20"
1319 - elif [ "${kver}" -ge 004019102 ] && [ "${kver}" -le 004020017 ]; then
1320 - echo >&2 " Using eBPF Kernel Package built against Linux 4.19.104"
1321 - kpkg="4_19_104"
1322 - elif [ "${kver}" -ge 004016000 ] && [ "${kver}" -le 004020017 ]; then
1323 - echo >&2 " Using eBPF Kernel Package built against Linux 4.19.98"
1324 - kpkg="4_19_98"
1325 - elif [ "${kver}" -ge 004015000 ] && [ "${kver}" -le 004015256 ]; then
1326 - echo >&2 " Using eBPF Kernel Package built against Linux 4.15.18"
1327 - kpkg="4_15_18"
1328 - elif [ "${kver}" -le 004014999 ]; then
1329 - echo >&2 " Using eBPF Kernel Package built against Linux 4.14.171"
1330 - kpkg="4_14_171"
1331 - else
1332 - echo >&2 " ERROR: Cannot detect a supported kernel on your system!"
1333 - return 1
1334 - fi
1335 -
1336 - echo "${kpkg}"
1337 - return 0
1338 -}
1339 -
1316 should_install_ebpf() {
1341 - if [ "${NETDATA_ENABLE_EBPF:=0}" -ne 1 ]; then
1342 - run_failed "ebpf not enabled. --enable-ebpf to enable"
1343 - return 1
1344 - fi
1345 -
1346 - if [ "$(uname)" != "Linux" ]; then
1347 - echo >&2 " Sorry eBPF Collector is currently unsupproted on $(uname) Systems at this time."
1348 - echo >&2 " Please contact NetData suppoort! https://github.com/netdata/netdata/issues/new"
1349 - return 1
1350 - fi
1351 -
1352 - # Get and Parse Kernel Version
1353 - kver="$(get_kernel_version)"
1354 - kver="${kver:-0}"
1355 -
1356 - # Check Kernel Compatibility
1357 - if ! get_compatible_kernel_for_ebpf "${kver}" > /dev/null; then
1358 - echo >&2 " Detected Kernel: ${kver}"
1359 - run_failed "Kernel incompatible. Please contact NetData support!"
1317 + if [ "${NETDATA_DISABLE_EBPF:=0}" -eq 1 ]; then
1318 + run_failed "eBPF explicitly disabled."
1319 + defer_error "eBPF explicitly disabled."
1320 return 1
1321 fi
1322
1323 # Check Kernel Config
1364 -
1365 - tmp="$(mktemp -d -t netdata-ebpf-XXXXXX)"
1366 -
1367 - echo >&2 " Downloading check-kernel-config.sh ..."
1368 - if ! get "https://raw.githubusercontent.com/netdata/kernel-collector/master/tools/check-kernel-config.sh" > "${tmp}"/check-kernel-config.sh; then
1369 - run_failed "Failed to download check-kernel-config.sh"
1370 - echo 2>&" Removing temporary directory ${tmp} ..."
1371 - rm -rf "${tmp}"
1372 - return 1
1373 - fi
1374 -
1375 - run chmod +x "${tmp}"/check-kernel-config.sh
1376 -
1377 - if ! run "${tmp}"/check-kernel-config.sh; then
1324 + if ! run "${INSTALLER_DIR}"/packaging/installer/check-kernel-config.sh; then
1325 run_failed "Kernel unsupported or missing required config"
1326 + defer_error "Kernel unsupported or missing required config, not installing eBPF collector"
1327 return 1
1328 fi
1329
1382 - rm -rf "${tmp}"
1383 -
1384 - # TODO: Check for current vs. latest version
1385 -
1330 return 0
1331 }
1332
1333 remove_old_ebpf() {
1334 if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/ebpf_process.plugin" ]; then
1335 echo >&2 "Removing alpha eBPF collector."
1392 - rm -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/ebpf_process.plugin"
1336 + rm -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/ebpf_process.plugin"
1337 fi
1338
1339 if [ -f "${NETDATA_PREFIX}/usr/lib/netdata/conf.d/ebpf_process.conf" ]; then
1340 echo >&2 "Removing alpha eBPF stock file"
1397 - rm -f "${NETDATA_PREFIX}/usr/lib/netdata/conf.d/ebpf_process.conf"
1341 + rm -f "${NETDATA_PREFIX}/usr/lib/netdata/conf.d/ebpf_process.conf"
1342 fi
1343
1344 if [ -f "${NETDATA_PREFIX}/etc/netdata/ebpf_process.conf" ]; then
1345 echo >&2 "Renaming eBPF configuration file."
1402 - mv "${NETDATA_PREFIX}/etc/netdata/ebpf_process.conf" "${NETDATA_PREFIX}/etc/netdata/ebpf.conf"
1346 + mv "${NETDATA_PREFIX}/etc/netdata/ebpf_process.conf" "${NETDATA_PREFIX}/etc/netdata/ebpf.conf"
1347 fi
1348 }
1349
@@ -1412,67 +1356,41 @@ install_ebpf() {
1356
1357 progress "Installing eBPF plugin"
1358
1415 - # Get and Parse Kernel Version
1416 - kver="$(get_kernel_version)"
1417 - kver="${kver:-0}"
1418 -
1419 - # Get Compatible eBPF Kernel Package
1420 - kpkg="$(get_compatible_kernel_for_ebpf "${kver}")"
1421 -
1359 # Detect libc
1360 libc="$(detect_libc)"
1361
1425 - PACKAGE_TARBALL="netdata_ebpf-${kpkg}-${libc}.tar.xz"
1426 -
1427 - echo >&2 " Getting latest eBPF Package URL for ${PACKAGE_TARBALL} ..."
1428 -
1429 - PACKAGE_TARBALL_URL=
1430 - PACKAGE_TARBALL_URL="$(get "https://api.github.com/repos/netdata/kernel-collector/releases/latest" | grep -o -E "\"browser_download_url\": \".*${PACKAGE_TARBALL}\"" | sed -e 's/"browser_download_url": "\(.*\)"/\1/')"
1431 -
1432 - if [ -z "${PACKAGE_TARBALL_URL}" ]; then
1433 - run_failed "Could not get latest eBPF Package URL for ${PACKAGE_TARBALL}"
1434 - return 1
1435 - fi
1362 + EBPF_VERSION="$(cat packaging/ebpf.version)"
1363 + EBPF_TARBALL="netdata-kernel-collector-${libc}-${EBPF_VERSION}.tar.xz"
1364
1365 tmp="$(mktemp -d -t netdata-ebpf-XXXXXX)"
1366
1439 - echo >&2 " Downloading eBPF Package ${PACKAGE_TARBALL_URL} ..."
1440 - if ! get "${PACKAGE_TARBALL_URL}" > "${tmp}"/"${PACKAGE_TARBALL}"; then
1441 - run_failed "Failed to download latest eBPF Package ${PACKAGE_TARBALL_URL}"
1367 + if ! fetch_and_verify "ebpf" \
1368 + "https://github.com/netdata/kernel-collector/releases/download/${EBPF_VERSION}/${EBPF_TARBALL}" \
1369 + "${EBPF_TARBALL}" \
1370 + "${tmp}" \
1371 + "${NETDATA_LOCAL_TARBALL_OVERRIDE_EBPF}"; then
1372 + run_failed "Failed to download eBPF collector package"
1373 echo 2>&" Removing temporary directory ${tmp} ..."
1374 rm -rf "${tmp}"
1375 return 1
1376 fi
1377
1447 - echo >&2 " Extracting ${PACKAGE_TARBALL} ..."
1448 - tar -xf "${tmp}/${PACKAGE_TARBALL}" -C "${tmp}"
1449 -
1450 - echo >&2 " Finding suitable lib directory ..."
1451 - libdir=
1452 - libdir="$(ldconfig -v 2> /dev/null | grep ':$' | sed -e 's/://' | sort -r | grep 'usr' | head -n 1)"
1453 - if [ -z "${libdir}" ]; then
1454 - libdir="$(ldconfig -v 2> /dev/null | grep ':$' | sed -e 's/://' | sort -r | head -n 1)"
1455 - fi
1378 + echo >&2 " Extracting ${EBPF_TARBALL} ..."
1379 + tar -xf "${tmp}/${EBPF_TARBALL}" -C "${tmp}"
1380
1457 - if [ -z "${libdir}" ]; then
1458 - run_failed "Could not find a suitable lib directory"
1459 - return 1
1460 - fi
1381 + # chown everything to root:netdata before we start copying out of our package
1382 + run chown -R root:netdata "${tmp}"
1383
1462 - run cp -a -v "${tmp}/usr/lib64/libbpf_kernel.so" "${libdir}"
1463 - run cp -a -v "${tmp}/libnetdata_ebpf.so" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d"
1464 - run cp -a -v "${tmp}"/pnetdata_ebpf_process.o "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d"
1465 - run cp -a -v "${tmp}"/rnetdata_ebpf_process.o "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d"
1466 - run ln -v -f -s "${libdir}"/libbpf_kernel.so "${libdir}"/libbpf_kernel.so.0
1467 - run ldconfig
1384 + run cp -a -v "${tmp}"/library/* "${NETDATA_PREFIX}"/usr/libexec/netdata/plugins.d
1385 + run cp -a -v "${tmp}"/*netdata_ebpf_*.o "${NETDATA_PREFIX}"/usr/libexec/netdata/plugins.d
1386 + run cp -a -v "${tmp}"/libnetdata_ebpf.so.* "${NETDATA_PREFIX}"/usr/libexec/netdata/plugins.d
1387
1469 - echo >&2 "ePBF installation all done!"
1388 rm -rf "${tmp}"
1389
1390 return 0
1391 }
1392
1475 -progress "eBPF Kernel Collector (opt-in)"
1393 +progress "eBPF Kernel Collector"
1394 install_ebpf
1395
1396 # -----------------------------------------------------------------------------
packaging/ebpf.checksums new
+2
@@ -0,0 +1,2 @@
1 +7dfb0b4bd39e2e73a8165b507439086521c960209066bfad98fce6280d61079b netdata-kernel-collector-glibc-v0.1.0.tar.xz
2 +3302febb7a6a07f1a3cf95e30a0020268cb85a8284c601932ff5c505105199df netdata-kernel-collector-musl-v0.1.0.tar.xz
packaging/ebpf.version new
+1
@@ -0,0 +1 @@
1 +v0.1.0
packaging/installer/check-kernel-config.sh new
+73
@@ -0,0 +1,73 @@
1 +#!/usr/bin/env bash
2 +
3 +get_kernel_version() {
4 + r="$(uname -r | cut -f 1 -d '-')"
5 +
6 + read -r -a p <<< "$(echo "${r}" | tr '.' ' ')"
7 +
8 + printf "%03d%03d%03d" "${p[0]}" "${p[1]}" "${p[2]}"
9 +}
10 +
11 +get_rh_version() {
12 + if [ ! -f /etc/redhat-release ]; then
13 + printf "000000000"
14 + return
15 + fi
16 +
17 + r="$(cut -f 4 -d ' ' < /etc/redhat-release)"
18 +
19 + read -r -a p <<< "$(echo "${r}" | tr '.' ' ')"
20 +
21 + printf "%03d%03d%03d" "${p[0]}" "${p[1]}" "${p[2]}"
22 +}
23 +
24 +if [ "$(uname -s)" != "Linux" ]; then
25 + echo >&2 "This does not appear to be a Linux system."
26 + exit 1
27 +fi
28 +
29 +KERNEL_VERSION="$(uname -r)"
30 +
31 +if [ "$(get_kernel_version)" -lt 004014000 ] && [ "$(get_rh_version)" -lt 0070061810 ]; then
32 + echo >&2 "WARNING: Your kernel appears to be older than 4.11 or you are using RH version older than 7.6.1810. This may still work in some cases, but probably won't."
33 +fi
34 +
35 +CONFIG_PATH=""
36 +MODULE_LOADED=""
37 +
38 +if modprobe configs 2> /dev/null; then
39 + MODULE_LOADED=1
40 +fi
41 +
42 +if [ -r /proc/config.gz ]; then
43 + CONFIG_PATH="/proc/config.gz"
44 +elif [ -r "/lib/modules/${KERNEL_VERSION}/source/.config" ]; then
45 + CONFIG_PATH="/lib/modules/${KERNEL_VERSION}/source/.config"
46 +elif [ -r "/lib/modules/${KERNEL_VERSION}.x86_64/source/.config" ]; then
47 + CONFIG_PATH="/lib/modules/${KERNEL_VERSION}.x86_64/source/.config"
48 +elif [ -n "$(find /boot -name "config-${KERNEL_VERSION}*")" ]; then
49 + CONFIG_PATH="$(find /boot -name "config-${KERNEL_VERSION}*" | head -n 1)"
50 +fi
51 +
52 +if [ -n "${CONFIG_PATH}" ]; then
53 + GREP='grep'
54 +
55 + if echo "${CONFIG_PATH}" | grep -q '.gz'; then
56 + GREP='zgrep'
57 + fi
58 +
59 + REQUIRED_CONFIG="KPROBES KPROBES_ON_FTRACE HAVE_KPROBES BPF BPF_SYSCALL BPF_JIT"
60 +
61 + for required_config in ${REQUIRED_CONFIG}; do
62 + if ! "${GREP}" -q "CONFIG_${required_config}=y" "${CONFIG_PATH}"; then
63 + echo >&2 " Missing Kernel Config: ${required_config}"
64 + exit 1
65 + fi
66 + done
67 +fi
68 +
69 +if [ -n "${MODULE_LOADED}" ]; then
70 + modprobe -r configs 2> /dev/null || true # Ignore failures from CONFIGS being builtin
71 +fi
72 +
73 +exit 0