ebpf_sync.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_sync.h"
  4. static char *sync_counter_dimension_name[NETDATA_SYNC_IDX_END] = { "sync", "syncfs", "msync", "fsync", "fdatasync",
  5. "sync_file_range" };
  6. static netdata_syscall_stat_t sync_counter_aggregated_data[NETDATA_SYNC_IDX_END];
  7. static netdata_publish_syscall_t sync_counter_publish_aggregated[NETDATA_SYNC_IDX_END];
  8. static netdata_idx_t sync_hash_values[NETDATA_SYNC_IDX_END];
  9. ebpf_local_maps_t sync_maps[] = {{.name = "tbl_sync", .internal_input = NETDATA_SYNC_END,
  10. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  11. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  12. #ifdef LIBBPF_MAJOR_VERSION
  13. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  14. #endif
  15. },
  16. {.name = NULL, .internal_input = 0, .user_input = 0,
  17. .type = NETDATA_EBPF_MAP_CONTROLLER,
  18. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  19. #ifdef LIBBPF_MAJOR_VERSION
  20. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  21. #endif
  22. }};
  23. ebpf_local_maps_t syncfs_maps[] = {{.name = "tbl_syncfs", .internal_input = NETDATA_SYNC_END,
  24. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  25. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  26. #ifdef LIBBPF_MAJOR_VERSION
  27. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  28. #endif
  29. },
  30. {.name = NULL, .internal_input = 0, .user_input = 0,
  31. .type = NETDATA_EBPF_MAP_CONTROLLER,
  32. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  33. #ifdef LIBBPF_MAJOR_VERSION
  34. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  35. #endif
  36. }};
  37. ebpf_local_maps_t msync_maps[] = {{.name = "tbl_msync", .internal_input = NETDATA_SYNC_END,
  38. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  39. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  40. #ifdef LIBBPF_MAJOR_VERSION
  41. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  42. #endif
  43. },
  44. {.name = NULL, .internal_input = 0, .user_input = 0,
  45. .type = NETDATA_EBPF_MAP_CONTROLLER,
  46. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  47. #ifdef LIBBPF_MAJOR_VERSION
  48. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  49. #endif
  50. }};
  51. ebpf_local_maps_t fsync_maps[] = {{.name = "tbl_fsync", .internal_input = NETDATA_SYNC_END,
  52. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  53. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  54. #ifdef LIBBPF_MAJOR_VERSION
  55. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  56. #endif
  57. },
  58. {.name = NULL, .internal_input = 0, .user_input = 0,
  59. .type = NETDATA_EBPF_MAP_CONTROLLER,
  60. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  61. #ifdef LIBBPF_MAJOR_VERSION
  62. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  63. #endif
  64. }};
  65. ebpf_local_maps_t fdatasync_maps[] = {{.name = "tbl_fdatasync", .internal_input = NETDATA_SYNC_END,
  66. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  67. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  68. #ifdef LIBBPF_MAJOR_VERSION
  69. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  70. #endif
  71. },
  72. {.name = NULL, .internal_input = 0, .user_input = 0,
  73. .type = NETDATA_EBPF_MAP_CONTROLLER,
  74. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  75. #ifdef LIBBPF_MAJOR_VERSION
  76. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  77. #endif
  78. }};
  79. ebpf_local_maps_t sync_file_range_maps[] = {{.name = "tbl_syncfr", .internal_input = NETDATA_SYNC_END,
  80. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  81. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  82. #ifdef LIBBPF_MAJOR_VERSION
  83. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  84. #endif
  85. },
  86. {.name = NULL, .internal_input = 0, .user_input = 0,
  87. .type = NETDATA_EBPF_MAP_CONTROLLER,
  88. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  89. #ifdef LIBBPF_MAJOR_VERSION
  90. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  91. #endif
  92. }};
  93. struct config sync_config = { .first_section = NULL,
  94. .last_section = NULL,
  95. .mutex = NETDATA_MUTEX_INITIALIZER,
  96. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  97. .rwlock = AVL_LOCK_INITIALIZER } };
  98. netdata_ebpf_targets_t sync_targets[] = { {.name = NETDATA_SYSCALLS_SYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  99. {.name = NETDATA_SYSCALLS_SYNCFS, .mode = EBPF_LOAD_TRAMPOLINE},
  100. {.name = NETDATA_SYSCALLS_MSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  101. {.name = NETDATA_SYSCALLS_FSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  102. {.name = NETDATA_SYSCALLS_FDATASYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  103. {.name = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .mode = EBPF_LOAD_TRAMPOLINE},
  104. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  105. #ifdef LIBBPF_MAJOR_VERSION
  106. /*****************************************************************
  107. *
  108. * BTF FUNCTIONS
  109. *
  110. *****************************************************************/
  111. /**
  112. * Disable probe
  113. *
  114. * Disable kprobe to use another method.
  115. *
  116. * @param obj is the main structure for bpf objects.
  117. */
  118. static inline void ebpf_sync_disable_probe(struct sync_bpf *obj)
  119. {
  120. bpf_program__set_autoload(obj->progs.netdata_sync_kprobe, false);
  121. }
  122. /**
  123. * Disable trampoline
  124. *
  125. * Disable trampoline to use another method.
  126. *
  127. * @param obj is the main structure for bpf objects.
  128. */
  129. static inline void ebpf_sync_disable_trampoline(struct sync_bpf *obj)
  130. {
  131. bpf_program__set_autoload(obj->progs.netdata_sync_fentry, false);
  132. }
  133. /**
  134. * Disable tracepoint
  135. *
  136. * Disable tracepoints according information given.
  137. *
  138. * @param obj object loaded
  139. * @param idx Which syscall will not be disabled
  140. */
  141. void ebpf_sync_disable_tracepoints(struct sync_bpf *obj, sync_syscalls_index_t idx)
  142. {
  143. if (idx != NETDATA_SYNC_SYNC_IDX)
  144. bpf_program__set_autoload(obj->progs.netdata_sync_entry, false);
  145. if (idx != NETDATA_SYNC_SYNCFS_IDX)
  146. bpf_program__set_autoload(obj->progs.netdata_syncfs_entry, false);
  147. if (idx != NETDATA_SYNC_MSYNC_IDX)
  148. bpf_program__set_autoload(obj->progs.netdata_msync_entry, false);
  149. if (idx != NETDATA_SYNC_FSYNC_IDX)
  150. bpf_program__set_autoload(obj->progs.netdata_fsync_entry, false);
  151. if (idx != NETDATA_SYNC_FDATASYNC_IDX)
  152. bpf_program__set_autoload(obj->progs.netdata_fdatasync_entry, false);
  153. if (idx != NETDATA_SYNC_SYNC_FILE_RANGE_IDX)
  154. bpf_program__set_autoload(obj->progs.netdata_sync_file_range_entry, false);
  155. }
  156. /**
  157. * Set hash tables
  158. *
  159. * Set the values for maps according the value given by kernel.
  160. *
  161. * @param map the map loaded.
  162. * @param obj the main structure for bpf objects.
  163. */
  164. static void ebpf_sync_set_hash_tables(ebpf_local_maps_t *map, struct sync_bpf *obj)
  165. {
  166. map->map_fd = bpf_map__fd(obj->maps.tbl_sync);
  167. }
  168. /**
  169. * Load and attach
  170. *
  171. * Load and attach the eBPF code in kernel.
  172. *
  173. * @param obj is the main structure for bpf objects.
  174. * @param em the structure with configuration
  175. * @param target the syscall that we are attaching a tracer.
  176. * @param idx the index for the main structure
  177. *
  178. * @return it returns 0 on success and -1 otherwise
  179. */
  180. static inline int ebpf_sync_load_and_attach(struct sync_bpf *obj, ebpf_module_t *em, char *target,
  181. sync_syscalls_index_t idx)
  182. {
  183. netdata_ebpf_targets_t *synct = em->targets;
  184. netdata_ebpf_program_loaded_t test = synct[NETDATA_SYNC_SYNC_IDX].mode;
  185. if (test == EBPF_LOAD_TRAMPOLINE) {
  186. ebpf_sync_disable_probe(obj);
  187. ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
  188. bpf_program__set_attach_target(obj->progs.netdata_sync_fentry, 0,
  189. target);
  190. } else if (test == EBPF_LOAD_PROBE ||
  191. test == EBPF_LOAD_RETPROBE) {
  192. ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
  193. ebpf_sync_disable_trampoline(obj);
  194. } else {
  195. ebpf_sync_disable_probe(obj);
  196. ebpf_sync_disable_trampoline(obj);
  197. ebpf_sync_disable_tracepoints(obj, idx);
  198. }
  199. ebpf_update_map_type(obj->maps.tbl_sync, &em->maps[NETDATA_SYNC_GLOBAL_TABLE]);
  200. int ret = sync_bpf__load(obj);
  201. if (!ret) {
  202. if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE) {
  203. ret = sync_bpf__attach(obj);
  204. } else {
  205. obj->links.netdata_sync_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sync_kprobe,
  206. false, target);
  207. ret = (int)libbpf_get_error(obj->links.netdata_sync_kprobe);
  208. }
  209. if (!ret)
  210. ebpf_sync_set_hash_tables(&em->maps[NETDATA_SYNC_GLOBAL_TABLE], obj);
  211. }
  212. return ret;
  213. }
  214. #endif
  215. /*****************************************************************
  216. *
  217. * CLEANUP THREAD
  218. *
  219. *****************************************************************/
  220. /**
  221. * Cleanup Objects
  222. *
  223. * Cleanup loaded objects when thread was initialized.
  224. */
  225. void ebpf_sync_cleanup_objects()
  226. {
  227. int i;
  228. for (i = 0; local_syscalls[i].syscall; i++) {
  229. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  230. #ifdef LIBBPF_MAJOR_VERSION
  231. if (w->sync_obj) {
  232. sync_bpf__destroy(w->sync_obj);
  233. w->sync_obj = NULL;
  234. }
  235. #endif
  236. if (w->probe_links) {
  237. ebpf_unload_legacy_code(w->objects, w->probe_links);
  238. w->objects = NULL;
  239. w->probe_links = NULL;
  240. }
  241. }
  242. }
  243. /*
  244. static void ebpf_create_sync_chart(char *id,
  245. char *title,
  246. int order,
  247. int idx,
  248. int end,
  249. int update_every)
  250. {
  251. ebpf_write_chart_cmd(NETDATA_EBPF_MEMORY_GROUP, id, title, EBPF_COMMON_DIMENSION_CALL,
  252. NETDATA_EBPF_SYNC_SUBMENU, NETDATA_EBPF_CHART_TYPE_LINE, NULL, order,
  253. update_every,
  254. NETDATA_EBPF_MODULE_NAME_SYNC);
  255. */
  256. /**
  257. * Obsolete global
  258. *
  259. * Obsolete global charts created by thread.
  260. *
  261. * @param em a pointer to `struct ebpf_module`
  262. */
  263. static void ebpf_obsolete_sync_global(ebpf_module_t *em)
  264. {
  265. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled)
  266. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  267. NETDATA_EBPF_FILE_SYNC_CHART,
  268. "",
  269. "Monitor calls to fsync(2) and fdatasync(2).",
  270. EBPF_COMMON_DIMENSION_CALL,
  271. NETDATA_EBPF_SYNC_SUBMENU,
  272. NETDATA_EBPF_CHART_TYPE_LINE,
  273. NULL,
  274. 21300,
  275. em->update_every);
  276. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  277. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  278. NETDATA_EBPF_MSYNC_CHART,
  279. "",
  280. "Monitor calls to msync(2).",
  281. EBPF_COMMON_DIMENSION_CALL,
  282. NETDATA_EBPF_SYNC_SUBMENU,
  283. NETDATA_EBPF_CHART_TYPE_LINE,
  284. NULL,
  285. 21301,
  286. em->update_every);
  287. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
  288. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  289. NETDATA_EBPF_SYNC_CHART,
  290. "",
  291. "Monitor calls to sync(2) and syncfs(2).",
  292. EBPF_COMMON_DIMENSION_CALL,
  293. NETDATA_EBPF_SYNC_SUBMENU,
  294. NETDATA_EBPF_CHART_TYPE_LINE,
  295. NULL,
  296. 21302,
  297. em->update_every);
  298. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  299. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  300. NETDATA_EBPF_FILE_SEGMENT_CHART,
  301. "",
  302. "Monitor calls to sync_file_range(2).",
  303. EBPF_COMMON_DIMENSION_CALL,
  304. NETDATA_EBPF_SYNC_SUBMENU,
  305. NETDATA_EBPF_CHART_TYPE_LINE,
  306. NULL,
  307. 21303,
  308. em->update_every);
  309. }
  310. /**
  311. * Exit
  312. *
  313. * Clean up the main thread.
  314. *
  315. * @param ptr thread data.
  316. */
  317. static void ebpf_sync_exit(void *ptr)
  318. {
  319. ebpf_module_t *em = (ebpf_module_t *)ptr;
  320. if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
  321. pthread_mutex_lock(&lock);
  322. ebpf_obsolete_sync_global(em);
  323. pthread_mutex_unlock(&lock);
  324. }
  325. ebpf_sync_cleanup_objects();
  326. pthread_mutex_lock(&ebpf_exit_cleanup);
  327. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  328. ebpf_update_stats(&plugin_statistics, em);
  329. pthread_mutex_unlock(&ebpf_exit_cleanup);
  330. }
  331. /*****************************************************************
  332. *
  333. * INITIALIZE THREAD
  334. *
  335. *****************************************************************/
  336. /**
  337. * Load Legacy
  338. *
  339. * Load legacy code.
  340. *
  341. * @param w is the sync output structure with pointers to objects loaded.
  342. * @param em is structure with configuration
  343. *
  344. * @return 0 on success and -1 otherwise.
  345. */
  346. static int ebpf_sync_load_legacy(ebpf_sync_syscalls_t *w, ebpf_module_t *em)
  347. {
  348. em->info.thread_name = w->syscall;
  349. if (!w->probe_links) {
  350. w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
  351. if (!w->probe_links) {
  352. return -1;
  353. }
  354. }
  355. return 0;
  356. }
  357. /*
  358. * Initialize Syscalls
  359. *
  360. * Load the eBPF programs to monitor syscalls
  361. *
  362. * @return 0 on success and -1 otherwise.
  363. */
  364. static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
  365. {
  366. #ifdef LIBBPF_MAJOR_VERSION
  367. ebpf_define_map_type(sync_maps, em->maps_per_core, running_on_kernel);
  368. ebpf_define_map_type(syncfs_maps, em->maps_per_core, running_on_kernel);
  369. ebpf_define_map_type(msync_maps, em->maps_per_core, running_on_kernel);
  370. ebpf_define_map_type(fsync_maps, em->maps_per_core, running_on_kernel);
  371. ebpf_define_map_type(fdatasync_maps, em->maps_per_core, running_on_kernel);
  372. ebpf_define_map_type(sync_file_range_maps, em->maps_per_core, running_on_kernel);
  373. #endif
  374. int i;
  375. const char *saved_name = em->info.thread_name;
  376. int errors = 0;
  377. for (i = 0; local_syscalls[i].syscall; i++) {
  378. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  379. w->sync_maps = local_syscalls[i].sync_maps;
  380. em->maps = local_syscalls[i].sync_maps;
  381. if (w->enabled) {
  382. if (em->load & EBPF_LOAD_LEGACY) {
  383. if (ebpf_sync_load_legacy(w, em))
  384. errors++;
  385. em->info.thread_name = saved_name;
  386. }
  387. #ifdef LIBBPF_MAJOR_VERSION
  388. else {
  389. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH];
  390. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH, w->syscall, running_on_kernel);
  391. if (ebpf_is_function_inside_btf(default_btf, syscall)) {
  392. w->sync_obj = sync_bpf__open();
  393. if (!w->sync_obj) {
  394. w->enabled = false;
  395. errors++;
  396. } else {
  397. if (ebpf_sync_load_and_attach(w->sync_obj, em, syscall, i)) {
  398. w->enabled = false;
  399. errors++;
  400. }
  401. }
  402. } else {
  403. netdata_log_info("Cannot find syscall %s we are not going to monitor it.", syscall);
  404. w->enabled = false;
  405. }
  406. em->info.thread_name = saved_name;
  407. }
  408. #endif
  409. }
  410. }
  411. em->info.thread_name = saved_name;
  412. memset(sync_counter_aggregated_data, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_syscall_stat_t));
  413. memset(sync_counter_publish_aggregated, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_publish_syscall_t));
  414. memset(sync_hash_values, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_idx_t));
  415. return (errors) ? -1 : 0;
  416. }
  417. /*****************************************************************
  418. *
  419. * DATA THREAD
  420. *
  421. *****************************************************************/
  422. /**
  423. * Read global table
  424. *
  425. * Read the table with number of calls for all functions
  426. *
  427. * @param maps_per_core do I need to read all cores?
  428. */
  429. static void ebpf_sync_read_global_table(int maps_per_core)
  430. {
  431. netdata_idx_t stored[NETDATA_MAX_PROCESSOR];
  432. uint32_t idx = NETDATA_SYNC_CALL;
  433. int i;
  434. for (i = 0; local_syscalls[i].syscall; i++) {
  435. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  436. if (w->enabled) {
  437. int fd = w->sync_maps[NETDATA_SYNC_GLOBAL_TABLE].map_fd;
  438. if (!bpf_map_lookup_elem(fd, &idx, &stored)) {
  439. int j, end = (maps_per_core) ? ebpf_nprocs : 1;
  440. netdata_idx_t total = 0;
  441. for (j = 0; j < end ;j++ )
  442. total += stored[j];
  443. sync_hash_values[i] = total;
  444. }
  445. }
  446. }
  447. }
  448. /**
  449. * Create Sync charts
  450. *
  451. * Create charts and dimensions according user input.
  452. *
  453. * @param id chart id
  454. * @param idx the first index with data.
  455. * @param end the last index with data.
  456. */
  457. static void ebpf_send_sync_chart(char *id,
  458. int idx,
  459. int end)
  460. {
  461. ebpf_write_begin_chart(NETDATA_EBPF_MEMORY_GROUP, id, "");
  462. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  463. while (move && idx <= end) {
  464. if (local_syscalls[idx].enabled)
  465. write_chart_dimension(move->name, (long long)sync_hash_values[idx]);
  466. move = move->next;
  467. idx++;
  468. }
  469. ebpf_write_end_chart();
  470. }
  471. /**
  472. * Send data
  473. *
  474. * Send global charts to Netdata
  475. */
  476. static void sync_send_data()
  477. {
  478. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled) {
  479. ebpf_send_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART, NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX);
  480. }
  481. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  482. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_MSYNC_CHART,
  483. sync_counter_publish_aggregated[NETDATA_SYNC_MSYNC_IDX].dimension,
  484. sync_hash_values[NETDATA_SYNC_MSYNC_IDX]);
  485. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled) {
  486. ebpf_send_sync_chart(NETDATA_EBPF_SYNC_CHART, NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX);
  487. }
  488. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  489. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_FILE_SEGMENT_CHART,
  490. sync_counter_publish_aggregated[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].dimension,
  491. sync_hash_values[NETDATA_SYNC_SYNC_FILE_RANGE_IDX]);
  492. }
  493. /**
  494. * Main loop for this collector.
  495. */
  496. static void sync_collector(ebpf_module_t *em)
  497. {
  498. heartbeat_t hb;
  499. heartbeat_init(&hb);
  500. int update_every = em->update_every;
  501. int counter = update_every - 1;
  502. int maps_per_core = em->maps_per_core;
  503. uint32_t running_time = 0;
  504. uint32_t lifetime = em->lifetime;
  505. while (!ebpf_plugin_exit && running_time < lifetime) {
  506. (void)heartbeat_next(&hb, USEC_PER_SEC);
  507. if (ebpf_plugin_exit || ++counter != update_every)
  508. continue;
  509. counter = 0;
  510. ebpf_sync_read_global_table(maps_per_core);
  511. pthread_mutex_lock(&lock);
  512. sync_send_data();
  513. pthread_mutex_unlock(&lock);
  514. pthread_mutex_lock(&ebpf_exit_cleanup);
  515. if (running_time && !em->running_time)
  516. running_time = update_every;
  517. else
  518. running_time += update_every;
  519. em->running_time = running_time;
  520. pthread_mutex_unlock(&ebpf_exit_cleanup);
  521. }
  522. }
  523. /*****************************************************************
  524. *
  525. * MAIN THREAD
  526. *
  527. *****************************************************************/
  528. /**
  529. * Create Sync charts
  530. *
  531. * Create charts and dimensions according user input.
  532. *
  533. * @param id chart id
  534. * @param title chart title
  535. * @param order order number of the specified chart
  536. * @param idx the first index with data.
  537. * @param end the last index with data.
  538. * @param update_every value to overwrite the update frequency set by the server.
  539. */
  540. static void ebpf_create_sync_chart(char *id,
  541. char *title,
  542. int order,
  543. int idx,
  544. int end,
  545. int update_every)
  546. {
  547. ebpf_write_chart_cmd(NETDATA_EBPF_MEMORY_GROUP, id, "", title, EBPF_COMMON_DIMENSION_CALL,
  548. NETDATA_EBPF_SYNC_SUBMENU, NETDATA_EBPF_CHART_TYPE_LINE, NULL, order,
  549. update_every,
  550. NETDATA_EBPF_MODULE_NAME_SYNC);
  551. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  552. while (move && idx <= end) {
  553. if (local_syscalls[idx].enabled)
  554. ebpf_write_global_dimension(move->name, move->dimension, move->algorithm);
  555. move = move->next;
  556. idx++;
  557. }
  558. }
  559. /**
  560. * Create global charts
  561. *
  562. * Call ebpf_create_chart to create the charts for the collector.
  563. *
  564. * @param update_every value to overwrite the update frequency set by the server.
  565. */
  566. static void ebpf_create_sync_charts(int update_every)
  567. {
  568. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled)
  569. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART,
  570. "Monitor calls to fsync(2) and fdatasync(2).", 21300,
  571. NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX, update_every);
  572. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  573. ebpf_create_sync_chart(NETDATA_EBPF_MSYNC_CHART,
  574. "Monitor calls to msync(2).", 21301,
  575. NETDATA_SYNC_MSYNC_IDX, NETDATA_SYNC_MSYNC_IDX, update_every);
  576. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
  577. ebpf_create_sync_chart(NETDATA_EBPF_SYNC_CHART,
  578. "Monitor calls to sync(2) and syncfs(2).", 21302,
  579. NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX, update_every);
  580. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  581. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SEGMENT_CHART,
  582. "Monitor calls to sync_file_range(2).", 21303,
  583. NETDATA_SYNC_SYNC_FILE_RANGE_IDX, NETDATA_SYNC_SYNC_FILE_RANGE_IDX, update_every);
  584. fflush(stdout);
  585. }
  586. /**
  587. * Parse Syscalls
  588. *
  589. * Parse syscall options available inside ebpf.d/sync.conf
  590. */
  591. static void ebpf_sync_parse_syscalls()
  592. {
  593. int i;
  594. for (i = 0; local_syscalls[i].syscall; i++) {
  595. local_syscalls[i].enabled = appconfig_get_boolean(&sync_config, NETDATA_SYNC_CONFIG_NAME,
  596. local_syscalls[i].syscall, CONFIG_BOOLEAN_YES);
  597. }
  598. }
  599. /**
  600. * Set sync maps
  601. *
  602. * When thread is initialized the variable sync_maps is set as null,
  603. * this function fills the variable before to use.
  604. */
  605. static void ebpf_set_sync_maps()
  606. {
  607. local_syscalls[NETDATA_SYNC_SYNC_IDX].sync_maps = sync_maps;
  608. local_syscalls[NETDATA_SYNC_SYNCFS_IDX].sync_maps = syncfs_maps;
  609. local_syscalls[NETDATA_SYNC_MSYNC_IDX].sync_maps = msync_maps;
  610. local_syscalls[NETDATA_SYNC_FSYNC_IDX].sync_maps = fsync_maps;
  611. local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].sync_maps = fdatasync_maps;
  612. local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].sync_maps = sync_file_range_maps;
  613. }
  614. /**
  615. * Sync thread
  616. *
  617. * Thread used to make sync thread
  618. *
  619. * @param ptr a pointer to `struct ebpf_module`
  620. *
  621. * @return It always return NULL
  622. */
  623. void *ebpf_sync_thread(void *ptr)
  624. {
  625. netdata_thread_cleanup_push(ebpf_sync_exit, ptr);
  626. ebpf_module_t *em = (ebpf_module_t *)ptr;
  627. ebpf_set_sync_maps();
  628. ebpf_sync_parse_syscalls();
  629. #ifdef LIBBPF_MAJOR_VERSION
  630. ebpf_adjust_thread_load(em, default_btf);
  631. #endif
  632. if (ebpf_sync_initialize_syscall(em)) {
  633. goto endsync;
  634. }
  635. int algorithms[NETDATA_SYNC_IDX_END] = { NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  636. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  637. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX };
  638. ebpf_global_labels(sync_counter_aggregated_data, sync_counter_publish_aggregated,
  639. sync_counter_dimension_name, sync_counter_dimension_name,
  640. algorithms, NETDATA_SYNC_IDX_END);
  641. pthread_mutex_lock(&lock);
  642. ebpf_create_sync_charts(em->update_every);
  643. ebpf_update_stats(&plugin_statistics, em);
  644. pthread_mutex_unlock(&lock);
  645. sync_collector(em);
  646. endsync:
  647. ebpf_update_disabled_plugin_stats(em);
  648. netdata_thread_cleanup_pop(1);
  649. return NULL;
  650. }