1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include <sys/time.h>
4
+#include <sys/resource.h>
5
+
6
+#include "ebpf_process.h"
7
+
8
+// callback required by eval()
9
+int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, calculated_number *result) {
10
+ (void)variable;
11
+ (void)hash;
12
+ (void)rc;
13
+ (void)result;
14
+ return 0;
15
+};
16
+
17
+void send_statistics( const char *action, const char *action_result, const char *action_data) {
18
+ (void) action;
19
+ (void) action_result;
20
+ (void) action_data;
21
+ return;
22
+}
23
+
24
+// callbacks required by popen()
25
+void signals_block(void) {};
26
+void signals_unblock(void) {};
27
+void signals_reset(void) {};
28
+
29
+// required by get_system_cpus()
30
+char *netdata_configured_host_prefix = "";
31
+
32
+// callback required by fatal()
33
+void netdata_cleanup_and_exit(int ret) {
34
+ exit(ret);
35
+}
36
+
37
+// ----------------------------------------------------------------------
38
+//Netdata eBPF library
39
+void *libnetdata = NULL;
40
+int (*load_bpf_file)(char *, int) = NULL;
41
+int (*set_bpf_perf_event)(int, int);
42
+int (*perf_event_unmap)(struct perf_event_mmap_page *, size_t);
43
+int (*perf_event_mmap_header)(int, struct perf_event_mmap_page **, int);
44
+void (*netdata_perf_loop_multi)(int *, struct perf_event_mmap_page **, int, int *, int (*nsb)(void *, int), int);
45
+int *map_fd = NULL;
46
+
47
+//Perf event variables
48
+static int pmu_fd[NETDATA_MAX_PROCESSOR];
49
+static struct perf_event_mmap_page *headers[NETDATA_MAX_PROCESSOR];
50
+int page_cnt = 8;
51
+
52
+//Libbpf (It is necessary to have at least kernel 4.10)
53
+int (*bpf_map_lookup_elem)(int, const void *, void *);
54
+
55
+static char *plugin_dir = PLUGINS_DIR;
56
+static char *user_config_dir = CONFIG_DIR;
57
+static char *stock_config_dir = LIBCONFIG_DIR;
58
+static char *netdata_configured_log_dir = LOG_DIR;
59
+
60
+FILE *developer_log = NULL;
61
+
62
+//Global vectors
63
+netdata_syscall_stat_t *aggregated_data = NULL;
64
+netdata_publish_syscall_t *publish_aggregated = NULL;
65
+
66
+static int update_every = 1;
67
+static int thread_finished = 0;
68
+static int close_plugin = 0;
69
+static int mode = 2;
70
+static int debug_log = 0;
71
+static int use_stdout = 0;
72
+struct config collector_config;
73
+static int mykernel = 0;
74
+static int nprocs;
75
+uint32_t *hash_values;
76
+
77
+pthread_mutex_t lock;
78
+
79
+static char *dimension_names[NETDATA_MAX_MONITOR_VECTOR] = { "open", "close", "delete", "read", "write", "process", "task", "process", "thread" };
80
+static char *id_names[NETDATA_MAX_MONITOR_VECTOR] = { "do_sys_open", "__close_fd", "vfs_unlink", "vfs_read", "vfs_write", "do_exit", "release_task", "_do_fork", "sys_clone" };
81
+static char *status[] = { "process", "zombie" };
82
+
83
+int event_pid = 0;
84
+netdata_ebpf_events_t collector_events[] = {
85
+ { .type = 'r', .name = "vfs_write" },
86
+ { .type = 'r', .name = "vfs_writev" },
87
+ { .type = 'r', .name = "vfs_read" },
88
+ { .type = 'r', .name = "vfs_readv" },
89
+ { .type = 'r', .name = "do_sys_open" },
90
+ { .type = 'r', .name = "vfs_unlink" },
91
+ { .type = 'p', .name = "do_exit" },
92
+ { .type = 'p', .name = "release_task" },
93
+ { .type = 'r', .name = "_do_fork" },
94
+ { .type = 'r', .name = "__close_fd" },
95
+ { .type = 'r', .name = "__x64_sys_clone" },
96
+ { .type = 0, .name = NULL }
97
+};
98
+
99
+void open_developer_log() {
100
+ char filename[FILENAME_MAX+1];
101
+ int tot = sprintf(filename, "%s/%s", netdata_configured_log_dir, NETDATA_DEVELOPER_LOG_FILE);
102
+
103
+ if(tot > 0)
104
+ developer_log = fopen(filename, "a");
105
+}
106
+
107
+static int unmap_memory() {
108
+ int i;
109
+ int size = (int)sysconf(_SC_PAGESIZE)*(page_cnt + 1);
110
+ for ( i = 0 ; i < nprocs ; i++ ) {
111
+ if (perf_event_unmap(headers[i], size) < 0) {
112
+ fprintf(stderr,"[EBPF PROCESS] CANNOT unmap headers.\n");
113
+ return -1;
114
+ }
115
+
116
+ close(pmu_fd[i]);
117
+ }
118
+
119
+ return 0;
120
+}
121
+
122
+static void int_exit(int sig)
123
+{
124
+ close_plugin = 1;
125
+
126
+ //When both threads were not finished case I try to go in front this address, the collector will crash
127
+ if (!thread_finished) {
128
+ return;
129
+ }
130
+
131
+ if (aggregated_data) {
132
+ free(aggregated_data);
133
+ aggregated_data = NULL;
134
+ }
135
+
136
+ if (publish_aggregated) {
137
+ free(publish_aggregated);
138
+ publish_aggregated = NULL;
139
+ }
140
+
141
+ if(mode == 1 && debug_log) {
142
+ unmap_memory();
143
+ }
144
+
145
+ if (libnetdata) {
146
+ dlclose(libnetdata);
147
+ libnetdata = NULL;
148
+ }
149
+
150
+ if (developer_log) {
151
+ fclose(developer_log);
152
+ developer_log = NULL;
153
+ }
154
+
155
+ if (hash_values) {
156
+ freez(hash_values);
157
+ }
158
+
159
+ if (event_pid) {
160
+ int ret = fork();
161
+ if (ret < 0) //error
162
+ error("[EBPF PROCESS] Cannot fork(), so I won't be able to clean %skprobe_events", NETDATA_DEBUGFS);
163
+ else if (!ret) { //child
164
+ int i;
165
+ for ( i=getdtablesize(); i>=0; --i)
166
+ close(i);
167
+
168
+ int fd = open("/dev/null",O_RDWR, 0);
169
+ if (fd != -1) {
170
+ dup2 (fd, STDIN_FILENO);
171
+ dup2 (fd, STDOUT_FILENO);
172
+ dup2 (fd, STDERR_FILENO);
173
+
174
+ if (fd > 2)
175
+ close (fd);
176
+ }
177
+
178
+ int sid = setsid();
179
+ if(sid >= 0) {
180
+ sleep(1);
181
+ if(debug_log) {
182
+ open_developer_log();
183
+ }
184
+ debug(D_EXIT, "Wait for father %d die", event_pid);
185
+ clean_kprobe_events(developer_log, event_pid, collector_events);
186
+ } else {
187
+ error("Cannot become session id leader, so I won't try to clean kprobe_events.\n");
188
+ }
189
+ } else { //parent
190
+ exit(0);
191
+ }
192
+
193
+ if (developer_log) {
194
+ fclose(developer_log);
195
+ developer_log = NULL;
196
+ }
197
+ }
198
+
199
+ exit(sig);
200
+}
201
+
202
+static inline void netdata_write_chart_cmd(char *type
203
+ , char *id
204
+ , char *axis
205
+ , char *web
206
+ , int order)
207
+{
208
+ printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n"
209
+ , type
210
+ , id
211
+ , axis
212
+ , web
213
+ , order);
214
+}
215
+
216
+static void netdata_write_global_dimension(char *dimension, char *name)
217
+{
218
+ printf("DIMENSION %s %s absolute 1 1\n", dimension, name);
219
+}
220
+
221
+static void netdata_create_global_dimension(void *ptr, int end)
222
+{
223
+ netdata_publish_syscall_t *move = ptr;
224
+
225
+ int i = 0;
226
+ while (move && i < end) {
227
+ netdata_write_global_dimension(move->name, move->dimension);
228
+
229
+ move = move->next;
230
+ i++;
231
+ }
232
+}
233
+static inline void netdata_create_chart(char *family
234
+ , char *name
235
+ , char *axis
236
+ , char *web
237
+ , int order
238
+ , void (*ncd)(void *, int)
239
+ , void *move
240
+ , int end)
241
+{
242
+ netdata_write_chart_cmd(family, name, axis, web, order);
243
+
244
+ ncd(move, end);
245
+}
246
+
247
+static void netdata_create_io_chart(char *family, char *name, char *axis, char *web, int order) {
248
+ printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n"
249
+ , family
250
+ , name
251
+ , axis
252
+ , web
253
+ , order);
254
+
255
+ printf("DIMENSION %s %s absolute 1 1\n", id_names[3], NETDATA_VFS_DIM_OUT_FILE_BYTES);
256
+ printf("DIMENSION %s %s absolute 1 1\n", id_names[4], NETDATA_VFS_DIM_IN_FILE_BYTES);
257
+}
258
+
259
+static void netdata_process_status_chart(char *family, char *name, char *axis, char *web, int order) {
260
+ printf("CHART %s.%s '' '' '%s' '%s' '' line %d 1 ''\n"
261
+ , family
262
+ , name
263
+ , axis
264
+ , web
265
+ , order);
266
+
267
+ printf("DIMENSION %s '' absolute 1 1\n", status[0]);
268
+ printf("DIMENSION %s '' absolute 1 1\n", status[1]);
269
+}
270
+
271
+static void netdata_global_charts_create() {
272
+ netdata_create_chart(NETDATA_EBPF_FAMILY
273
+ , NETDATA_FILE_OPEN_CLOSE_COUNT
274
+ , "Calls"
275
+ , NETDATA_FILE_GROUP
276
+ , 970
277
+ , netdata_create_global_dimension
278
+ , publish_aggregated
279
+ , 2);
280
+
281
+ if(mode < 2) {
282
+ netdata_create_chart(NETDATA_EBPF_FAMILY
283
+ , NETDATA_FILE_OPEN_ERR_COUNT
284
+ , "Calls"
285
+ , NETDATA_FILE_GROUP
286
+ , 971
287
+ , netdata_create_global_dimension
288
+ , publish_aggregated
289
+ , 2);
290
+ }
291
+
292
+ netdata_create_chart(NETDATA_EBPF_FAMILY
293
+ , NETDATA_VFS_FILE_CLEAN_COUNT
294
+ , "Calls"
295
+ , NETDATA_VFS_GROUP
296
+ , 972
297
+ , netdata_create_global_dimension
298
+ , &publish_aggregated[NETDATA_DEL_START]
299
+ , 1);
300
+
301
+ netdata_create_chart(NETDATA_EBPF_FAMILY
302
+ , NETDATA_VFS_FILE_IO_COUNT
303
+ , "Calls"
304
+ , NETDATA_VFS_GROUP
305
+ , 973
306
+ , netdata_create_global_dimension
307
+ , &publish_aggregated[NETDATA_IN_START_BYTE]
308
+ , 2);
309
+
310
+ if(mode < 2) {
311
+ netdata_create_io_chart(NETDATA_EBPF_FAMILY
312
+ , NETDATA_VFS_IO_FILE_BYTES
313
+ , "bytes/s"
314
+ , NETDATA_VFS_GROUP
315
+ , 974);
316
+
317
+ netdata_create_chart(NETDATA_EBPF_FAMILY
318
+ , NETDATA_VFS_FILE_ERR_COUNT
319
+ , "Calls"
320
+ , NETDATA_VFS_GROUP
321
+ , 975
322
+ , netdata_create_global_dimension
323
+ , &publish_aggregated[2]
324
+ , NETDATA_VFS_ERRORS);
325
+
326
+ }
327
+
328
+ netdata_create_chart(NETDATA_EBPF_FAMILY
329
+ , NETDATA_PROCESS_SYSCALL
330
+ , "Calls"
331
+ , NETDATA_PROCESS_GROUP
332
+ , 976
333
+ , netdata_create_global_dimension
334
+ , &publish_aggregated[NETDATA_PROCESS_START]
335
+ , 2);
336
+
337
+ netdata_create_chart(NETDATA_EBPF_FAMILY
338
+ , NETDATA_EXIT_SYSCALL
339
+ , "Calls"
340
+ , NETDATA_PROCESS_GROUP
341
+ , 977
342
+ , netdata_create_global_dimension
343
+ , &publish_aggregated[NETDATA_EXIT_START]
344
+ , 2);
345
+
346
+ netdata_process_status_chart(NETDATA_EBPF_FAMILY
347
+ , NETDATA_PROCESS_STATUS_NAME
348
+ , "Total"
349
+ , NETDATA_PROCESS_GROUP
350
+ , 978);
351
+
352
+ if(mode < 2) {
353
+ netdata_create_chart(NETDATA_EBPF_FAMILY
354
+ , NETDATA_PROCESS_ERROR_NAME
355
+ , "Calls"
356
+ , NETDATA_PROCESS_GROUP
357
+ , 979
358
+ , netdata_create_global_dimension
359
+ , &publish_aggregated[NETDATA_PROCESS_START]
360
+ , 2);
361
+ }
362
+
363
+}
364
+
365
+
366
+static void netdata_create_charts() {
367
+ netdata_global_charts_create();
368
+}
369
+
370
+static void netdata_update_publish(netdata_publish_syscall_t *publish
371
+ , netdata_publish_vfs_common_t *pvc
372
+ , netdata_syscall_stat_t *input) {
373
+
374
+ netdata_publish_syscall_t *move = publish;
375
+ while(move) {
376
+ if(input->call != move->pcall) {
377
+ //This condition happens to avoid initial values with dimensions higher than normal values.
378
+ if(move->pcall) {
379
+ move->ncall = (input->call > move->pcall)?input->call - move->pcall: move->pcall - input->call;
380
+ move->nbyte = (input->bytes > move->pbyte)?input->bytes - move->pbyte: move->pbyte - input->bytes;
381
+ move->nerr = (input->ecall > move->nerr)?input->ecall - move->perr: move->perr - input->ecall;
382
+ } else {
383
+ move->ncall = 0;
384
+ move->nbyte = 0;
385
+ move->nerr = 0;
386
+ }
387
+
388
+ move->pcall = input->call;
389
+ move->pbyte = input->bytes;
390
+ move->perr = input->ecall;
391
+ } else {
392
+ move->ncall = 0;
393
+ move->nbyte = 0;
394
+ move->nerr = 0;
395
+ }
396
+
397
+ input = input->next;
398
+ move = move->next;
399
+ }
400
+
401
+ pvc->write = -((long)publish[2].nbyte);
402
+ pvc->read = (long)publish[3].nbyte;
403
+
404
+ pvc->running = (long)publish[7].ncall - (long)publish[8].ncall;
405
+ publish[6].ncall = -publish[6].ncall; // release
406
+ pvc->zombie = (long)publish[5].ncall + (long)publish[6].ncall;
407
+}
408
+
409
+static inline void write_begin_chart(char *family, char *name)
410
+{
411
+ int ret = printf( "BEGIN %s.%s\n"
412
+ , family
413
+ , name);
414
+
415
+ (void)ret;
416
+}
417
+
418
+static inline void write_chart_dimension(char *dim, long long value)
419
+{
420
+ int ret = printf("SET %s = %lld\n", dim, value);
421
+ (void)ret;
422
+}
423
+
424
+static void write_global_count_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) {
425
+ write_begin_chart(family, name);
426
+
427
+ int i = 0;
428
+ while (move && i < end) {
429
+ write_chart_dimension(move->name, move->ncall);
430
+
431
+ move = move->next;
432
+ i++;
433
+ }
434
+
435
+ printf("END\n");
436
+}
437
+
438
+static void write_global_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end) {
439
+ write_begin_chart(family, name);
440
+
441
+ int i = 0;
442
+ while (move && i < end) {
443
+ write_chart_dimension(move->name, move->nerr);
444
+
445
+ move = move->next;
446
+ i++;
447
+ }
448
+
449
+ printf("END\n");
450
+}
451
+
452
+static void write_io_chart(char *family, netdata_publish_vfs_common_t *pvc) {
453
+ write_begin_chart(family, NETDATA_VFS_IO_FILE_BYTES);
454
+
455
+ write_chart_dimension(id_names[3], (long long) pvc->write);
456
+ write_chart_dimension(id_names[4], (long long) pvc->read);
457
+
458
+ printf("END\n");
459
+}
460
+
461
+static void write_status_chart(char *family, netdata_publish_vfs_common_t *pvc) {
462
+ write_begin_chart(family, NETDATA_PROCESS_STATUS_NAME);
463
+
464
+ write_chart_dimension(status[0], (long long) pvc->running);
465
+ write_chart_dimension(status[1], (long long) pvc->zombie);
466
+
467
+ printf("END\n");
468
+}
469
+
470
+static void netdata_publish_data() {
471
+ netdata_publish_vfs_common_t pvc;
472
+ netdata_update_publish(publish_aggregated, &pvc, aggregated_data);
473
+
474
+ write_global_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_EBPF_FAMILY, publish_aggregated, 2);
475
+ write_global_count_chart(NETDATA_VFS_FILE_CLEAN_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_DEL_START], 1);
476
+ write_global_count_chart(NETDATA_VFS_FILE_IO_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_IN_START_BYTE], 2);
477
+ write_global_count_chart(NETDATA_EXIT_SYSCALL, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_EXIT_START], 2);
478
+ write_global_count_chart(NETDATA_PROCESS_SYSCALL, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_PROCESS_START], 2);
479
+
480
+ write_status_chart(NETDATA_EBPF_FAMILY, &pvc);
481
+ if(mode < 2) {
482
+ write_global_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_EBPF_FAMILY, publish_aggregated, 2);
483
+ write_global_err_chart(NETDATA_VFS_FILE_ERR_COUNT, NETDATA_EBPF_FAMILY, &publish_aggregated[2], NETDATA_VFS_ERRORS);
484
+ write_global_err_chart(NETDATA_PROCESS_ERROR_NAME, NETDATA_EBPF_FAMILY, &publish_aggregated[NETDATA_PROCESS_START], 2);
485
+
486
+ write_io_chart(NETDATA_EBPF_FAMILY, &pvc);
487
+ }
488
+}
489
+
490
+void *process_publisher(void *ptr)
491
+{
492
+ (void)ptr;
493
+ netdata_create_charts();
494
+
495
+ usec_t step = update_every * USEC_PER_SEC;
496
+ heartbeat_t hb;
497
+ heartbeat_init(&hb);
498
+ while(!close_plugin) {
499
+ usec_t dt = heartbeat_next(&hb, step);
500
+ (void)dt;
501
+
502
+ pthread_mutex_lock(&lock);
503
+ netdata_publish_data();
504
+ pthread_mutex_unlock(&lock);
505
+
506
+ fflush(stdout);
507
+ }
508
+
509
+ return NULL;
510
+}
511
+
512
+static void move_from_kernel2user_global() {
513
+ uint32_t idx;
514
+ uint32_t res[NETDATA_GLOBAL_VECTOR];
515
+
516
+ uint32_t *val = hash_values;
517
+ for (idx = 0; idx < NETDATA_GLOBAL_VECTOR; idx++) {
518
+ if(!bpf_map_lookup_elem(map_fd[1], &idx, val)) {
519
+ uint32_t total = 0;
520
+ int i;
521
+ int end = (mykernel < 265984)?1:nprocs;
522
+ for (i = 0; i < end; i++)
523
+ total += val[i];
524
+
525
+ res[idx] = total;
526
+ } else {
527
+ res[idx] = 0;
528
+ }
529
+ }
530
+
531
+ aggregated_data[0].call = res[0]; //open
532
+ aggregated_data[1].call = res[14]; //close
533
+ aggregated_data[2].call = res[8]; //unlink
534
+ aggregated_data[3].call = res[5] + res[21]; //read + readv
535
+ aggregated_data[4].call = res[2] + res[18]; //write + writev
536
+ aggregated_data[5].call = res[10]; //exit
537
+ aggregated_data[6].call = res[11]; //release
538
+ aggregated_data[7].call = res[12]; //fork
539
+ aggregated_data[8].call = res[16]; //thread
540
+
541
+ aggregated_data[0].ecall = res[1]; //open
542
+ aggregated_data[1].ecall = res[15]; //close
543
+ aggregated_data[2].ecall = res[9]; //unlink
544
+ aggregated_data[3].ecall = res[6] + res[22]; //read + readv
545
+ aggregated_data[4].ecall = res[3] + res[19]; //write + writev
546
+ aggregated_data[7].ecall = res[13]; //fork
547
+ aggregated_data[8].ecall = res[17]; //thread
548
+
549
+ aggregated_data[2].bytes = (uint64_t)res[4] + (uint64_t)res[20]; //write + writev
550
+ aggregated_data[3].bytes = (uint64_t)res[7] + (uint64_t)res[23];//read + readv
551
+}
552
+
553
+static void move_from_kernel2user()
554
+{
555
+ move_from_kernel2user_global();
556
+}
557
+
558
+void *process_collector(void *ptr)
559
+{
560
+ (void)ptr;
561
+
562
+ usec_t step = 778879ULL;
563
+ heartbeat_t hb;
564
+ heartbeat_init(&hb);
565
+ while(!close_plugin) {
566
+ usec_t dt = heartbeat_next(&hb, step);
567
+ (void)dt;
568
+
569
+ pthread_mutex_lock(&lock);
570
+ move_from_kernel2user();
571
+ pthread_mutex_unlock(&lock);
572
+ }
573
+
574
+ return NULL;
575
+}
576
+
577
+static int netdata_store_bpf(void *data, int size) {
578
+ (void)size;
579
+
580
+ if (close_plugin)
581
+ return 0;
582
+
583
+ if(!debug_log)
584
+ return -2; //LIBBPF_PERF_EVENT_CONT;
585
+
586
+ netdata_error_report_t *e = data;
587
+ fprintf(developer_log
588
+ ,"%llu %s %u: %s, %d\n"
589
+ , now_realtime_usec() ,e->comm, e->pid, dimension_names[e->type], e->err);
590
+ fflush(developer_log);
591
+
592
+ return -2; //LIBBPF_PERF_EVENT_CONT;
593
+}
594
+
595
+void *process_log(void *ptr)
596
+{
597
+ (void) ptr;
598
+
599
+ if (mode == 1 && debug_log) {
600
+ netdata_perf_loop_multi(pmu_fd, headers, nprocs, &close_plugin, netdata_store_bpf, page_cnt);
601
+ }
602
+
603
+ return NULL;
604
+}
605
+
606
+void set_global_labels() {
607
+ int i;
608
+
609
+ netdata_syscall_stat_t *is = aggregated_data;
610
+ netdata_syscall_stat_t *prev = NULL;
611
+
612
+ netdata_publish_syscall_t *pio = publish_aggregated;
613
+ netdata_publish_syscall_t *publish_prev = NULL;
614
+ for (i = 0; i < NETDATA_MAX_MONITOR_VECTOR; i++) {
615
+ if(prev) {
616
+ prev->next = &is[i];
617
+ }
618
+ prev = &is[i];
619
+
620
+ pio[i].dimension = dimension_names[i];
621
+ pio[i].name = id_names[i];
622
+ if(publish_prev) {
623
+ publish_prev->next = &pio[i];
624
+ }
625
+ publish_prev = &pio[i];
626
+ }
627
+}
628
+
629
+int allocate_global_vectors() {
630
+ aggregated_data = callocz(NETDATA_MAX_MONITOR_VECTOR, sizeof(netdata_syscall_stat_t));
631
+ if(!aggregated_data) {
632
+ return -1;
633
+ }
634
+
635
+ publish_aggregated = callocz(NETDATA_MAX_MONITOR_VECTOR, sizeof(netdata_publish_syscall_t));
636
+ if(!publish_aggregated) {
637
+ return -1;
638
+ }
639
+
640
+ hash_values = callocz(nprocs, sizeof(uint32_t));
641
+ if(!hash_values) {
642
+ return -1;
643
+ }
644
+
645
+ return 0;
646
+}
647
+
648
+static void build_complete_path(char *out, size_t length,char *path, char *filename) {
649
+ if(path){
650
+ snprintf(out, length, "%s/%s", path, filename);
651
+ } else {
652
+ snprintf(out, length, "%s", filename);
653
+ }
654
+}
655
+
656
+static int map_memory() {
657
+ int i;
658
+ for (i = 0; i < nprocs; i++) {
659
+ pmu_fd[i] = set_bpf_perf_event(i, 2);
660
+
661
+ if (perf_event_mmap_header(pmu_fd[i], &headers[i], page_cnt) < 0) {
662
+ return -1;
663
+ }
664
+ }
665
+ return 0;
666
+}
667
+
668
+static int ebpf_load_libraries()
669
+{
670
+ char *err = NULL;
671
+ char lpath[4096];
672
+
673
+ build_complete_path(lpath, 4096, plugin_dir, "libnetdata_ebpf.so");
674
+ libnetdata = dlopen(lpath, RTLD_LAZY);
675
+ if (!libnetdata) {
676
+ error("[EBPF_PROCESS] Cannot load %s.", lpath);
677
+ return -1;
678
+ } else {
679
+ load_bpf_file = dlsym(libnetdata, "load_bpf_file");
680
+ if ((err = dlerror()) != NULL) {
681
+ error("[EBPF_PROCESS] Cannot find load_bpf_file: %s", err);
682
+ return -1;
683
+ }
684
+
685
+ map_fd = dlsym(libnetdata, "map_fd");
686
+ if ((err = dlerror()) != NULL) {
687
+ error("[EBPF_PROCESS] Cannot find map_fd: %s", err);
688
+ return -1;
689
+ }
690
+
691
+ bpf_map_lookup_elem = dlsym(libnetdata, "bpf_map_lookup_elem");
692
+ if ((err = dlerror()) != NULL) {
693
+ error("[EBPF_PROCESS] Cannot find bpf_map_lookup_elem: %s", err);
694
+ return -1;
695
+ }
696
+
697
+ if(mode == 1) {
698
+ set_bpf_perf_event = dlsym(libnetdata, "set_bpf_perf_event");
699
+ if ((err = dlerror()) != NULL) {
700
+ error("[EBPF_PROCESS] Cannot find set_bpf_perf_event: %s", err);
701
+ return -1;
702
+ }
703
+
704
+ perf_event_unmap = dlsym(libnetdata, "perf_event_unmap");
705
+ if ((err = dlerror()) != NULL) {
706
+ error("[EBPF_PROCESS] Cannot find perf_event_unmap: %s", err);
707
+ return -1;
708
+ }
709
+
710
+ perf_event_mmap_header = dlsym(libnetdata, "perf_event_mmap_header");
711
+ if ((err = dlerror()) != NULL) {
712
+ error("[EBPF_PROCESS] Cannot find perf_event_mmap_header: %s", err);
713
+ return -1;
714
+ }
715
+
716
+ netdata_perf_loop_multi = dlsym(libnetdata, "netdata_perf_loop_multi");
717
+ if ((err = dlerror()) != NULL) {
718
+ error("[EBPF_PROCESS] Cannot find netdata_perf_loop_multi: %s", err);
719
+ return -1;
720
+ }
721
+ }
722
+ }
723
+
724
+ return 0;
725
+}
726
+
727
+char *select_file() {
728
+ if(!mode)
729
+ return "rnetdata_ebpf_process.o";
730
+ if(mode == 1)
731
+ return "dnetdata_ebpf_process.o";
732
+
733
+ return "pnetdata_ebpf_process.o";
734
+}
735
+
736
+int process_load_ebpf()
737
+{
738
+ char lpath[4096];
739
+
740
+ char *name = select_file();
741
+
742
+ build_complete_path(lpath, 4096, plugin_dir, name);
743
+ event_pid = getpid();
744
+ if (load_bpf_file(lpath, event_pid) ) {
745
+ error("[EBPF_PROCESS] Cannot load program: %s", lpath);
746
+ return -1;
747
+ } else {
748
+ info("[EBPF PROCESS]: The eBPF program %s was loaded with success.", name);
749
+ }
750
+
751
+ return 0;
752
+}
753
+
754
+void set_global_variables() {
755
+ //Get environment variables
756
+ plugin_dir = getenv("NETDATA_PLUGINS_DIR");
757
+ if(!plugin_dir)
758
+ plugin_dir = PLUGINS_DIR;
759
+
760
+ user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
761
+ if(!user_config_dir)
762
+ user_config_dir = CONFIG_DIR;
763
+
764
+ stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
765
+ if(!stock_config_dir)
766
+ stock_config_dir = LIBCONFIG_DIR;
767
+
768
+ netdata_configured_log_dir = getenv("NETDATA_LOG_DIR");
769
+ if(!netdata_configured_log_dir)
770
+ netdata_configured_log_dir = LOG_DIR;
771
+
772
+ page_cnt *= (int)sysconf(_SC_NPROCESSORS_ONLN);
773
+
774
+ nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
775
+ if (nprocs > NETDATA_MAX_PROCESSOR) {
776
+ nprocs = NETDATA_MAX_PROCESSOR;
777
+ }
778
+}
779
+
780
+static void change_collector_event() {
781
+ int i;
782
+ for (i = 0; collector_events[i].name ; i++ ) {
783
+ collector_events[i].type = 'p';
784
+ }
785
+
786
+ if (mykernel < 328448)
787
+ collector_events[i].name = NULL;
788
+}
789
+
790
+static inline void what_to_load(char *ptr) {
791
+ if (!strcasecmp(ptr, "return"))
792
+ mode = 0;
793
+ /*
794
+ else if (!strcasecmp(ptr, "dev"))
795
+ mode = 1;
796
+ */
797
+ else
798
+ change_collector_event();
799
+}
800
+
801
+static inline void enable_debug(char *ptr) {
802
+ if (!strcasecmp(ptr, "yes"))
803
+ debug_log = 1;
804
+}
805
+
806
+static inline void set_log_file(char *ptr) {
807
+ if (!strcasecmp(ptr, "yes"))
808
+ use_stdout = 1;
809
+}
810
+
811
+static void set_global_values() {
812
+ struct section *sec = collector_config.sections;
813
+ while(sec) {
814
+ if(!strcasecmp(sec->name, "global")) {
815
+ struct config_option *values = sec->values;
816
+ while(values) {
817
+ if(!strcasecmp(values->name, "load"))
818
+ what_to_load(values->value);
819
+ else if(!strcasecmp(values->name, "debug log"))
820
+ enable_debug(values->value);
821
+ else if(!strcasecmp(values->name, "use stdout"))
822
+ set_log_file(values->value);
823
+
824
+ values = values->next;
825
+ }
826
+ }
827
+ sec = sec->next;
828
+ }
829
+}
830
+
831
+static int load_collector_file(char *path) {
832
+ char lpath[4096];
833
+
834
+ build_complete_path(lpath, 4096, path, "ebpf_process.conf" );
835
+
836
+ if (!appconfig_load(&collector_config, lpath, 0, NULL))
837
+ return 1;
838
+
839
+ set_global_values();
840
+
841
+ return 0;
842
+}
843
+
844
+int main(int argc, char **argv)
845
+{
846
+ (void)argc;
847
+ (void)argv;
848
+
849
+ mykernel = get_kernel_version();
850
+ if(!has_condition_to_run(mykernel))
851
+ return 1;
852
+
853
+ //set name
854
+ program_name = "ebpf_process.plugin";
855
+
856
+ //disable syslog
857
+ error_log_syslog = 0;
858
+
859
+ // set errors flood protection to 100 logs per hour
860
+ error_log_errors_per_period = 100;
861
+ error_log_throttle_period = 3600;
862
+
863
+ if (argc > 1) {
864
+ update_every = (int)strtol(argv[1], NULL, 10);
865
+ }
866
+
867
+ struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
868
+ if (setrlimit(RLIMIT_MEMLOCK, &r)) {
869
+ error("[EBPF PROCESS] setrlimit(RLIMIT_MEMLOCK)");
870
+ return 2;
871
+ }
872
+
873
+ set_global_variables();
874
+
875
+ if (load_collector_file(user_config_dir)) {
876
+ info("[EBPF PROCESS] does not have a configuration file. It is starting with default options.");
877
+ }
878
+
879
+ if(ebpf_load_libraries()) {
880
+ error("[EBPF_PROCESS] Cannot load library.");
881
+ thread_finished++;
882
+ int_exit(3);
883
+ }
884
+
885
+ signal(SIGINT, int_exit);
886
+ signal(SIGTERM, int_exit);
887
+
888
+ if (process_load_ebpf()) {
889
+ thread_finished++;
890
+ int_exit(4);
891
+ }
892
+
893
+ if(allocate_global_vectors()) {
894
+ thread_finished++;
895
+ error("[EBPF_PROCESS] Cannot allocate necessary vectors.");
896
+ int_exit(5);
897
+ }
898
+
899
+ if(mode == 1 && debug_log) {
900
+ if(map_memory()) {
901
+ thread_finished++;
902
+ error("[EBPF_PROCESS] Cannot map memory used with perf events.");
903
+ int_exit(6);
904
+ }
905
+ }
906
+
907
+ set_global_labels();
908
+
909
+ if(debug_log) {
910
+ open_developer_log();
911
+ }
912
+
913
+ if (pthread_mutex_init(&lock, NULL)) {
914
+ thread_finished++;
915
+ int_exit(7);
916
+ }
917
+
918
+ pthread_attr_t attr;
919
+ pthread_attr_init(&attr);
920
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
921
+ pthread_t thread[NETDATA_EBPF_PROCESS_THREADS];
922
+
923
+ int i;
924
+ int end = NETDATA_EBPF_PROCESS_THREADS;
925
+
926
+ void * (*function_pointer[])(void *) = {process_publisher, process_collector, process_log };
927
+
928
+ for ( i = 0; i < end ; i++ ) {
929
+ if ( ( pthread_create(&thread[i], &attr, function_pointer[i], NULL) ) ) {
930
+ error("[EBPF_PROCESS] Cannot create threads.");
931
+ thread_finished++;
932
+ int_exit(8);
933
+ }
934
+ }
935
+
936
+ for ( i = 0; i < end ; i++ ) {
937
+ if ( (pthread_join(thread[i], NULL) ) ) {
938
+ error("[EBPF_PROCESS] Cannot join threads.");
939
+ thread_finished++;
940
+ int_exit(9);
941
+ }
942
+ }
943
+
944
+ thread_finished++;
945
+ int_exit(0);
946
+
947
+ return 0;
948
+}