ebpf_sync.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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. "Monitor calls for <code>fsync(2)</code> and <code>fdatasync(2)</code>.",
  269. EBPF_COMMON_DIMENSION_CALL,
  270. NETDATA_EBPF_SYNC_SUBMENU,
  271. NETDATA_EBPF_CHART_TYPE_LINE,
  272. NULL,
  273. 21300,
  274. em->update_every);
  275. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  276. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  277. NETDATA_EBPF_MSYNC_CHART,
  278. "Monitor calls for <code>msync(2)</code>.",
  279. EBPF_COMMON_DIMENSION_CALL,
  280. NETDATA_EBPF_SYNC_SUBMENU,
  281. NETDATA_EBPF_CHART_TYPE_LINE,
  282. NULL,
  283. 21301,
  284. em->update_every);
  285. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
  286. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  287. NETDATA_EBPF_SYNC_CHART,
  288. "Monitor calls for <code>sync(2)</code> and <code>syncfs(2)</code>.",
  289. EBPF_COMMON_DIMENSION_CALL,
  290. NETDATA_EBPF_SYNC_SUBMENU,
  291. NETDATA_EBPF_CHART_TYPE_LINE,
  292. NULL,
  293. 21302,
  294. em->update_every);
  295. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  296. ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
  297. NETDATA_EBPF_FILE_SEGMENT_CHART,
  298. "Monitor calls for <code>sync_file_range(2)</code>.",
  299. EBPF_COMMON_DIMENSION_CALL,
  300. NETDATA_EBPF_SYNC_SUBMENU,
  301. NETDATA_EBPF_CHART_TYPE_LINE,
  302. NULL,
  303. 21303,
  304. em->update_every);
  305. }
  306. /**
  307. * Exit
  308. *
  309. * Clean up the main thread.
  310. *
  311. * @param ptr thread data.
  312. */
  313. static void ebpf_sync_exit(void *ptr)
  314. {
  315. ebpf_module_t *em = (ebpf_module_t *)ptr;
  316. if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
  317. pthread_mutex_lock(&lock);
  318. ebpf_obsolete_sync_global(em);
  319. pthread_mutex_unlock(&lock);
  320. }
  321. ebpf_sync_cleanup_objects();
  322. pthread_mutex_lock(&ebpf_exit_cleanup);
  323. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  324. ebpf_update_stats(&plugin_statistics, em);
  325. pthread_mutex_unlock(&ebpf_exit_cleanup);
  326. }
  327. /*****************************************************************
  328. *
  329. * INITIALIZE THREAD
  330. *
  331. *****************************************************************/
  332. /**
  333. * Load Legacy
  334. *
  335. * Load legacy code.
  336. *
  337. * @param w is the sync output structure with pointers to objects loaded.
  338. * @param em is structure with configuration
  339. *
  340. * @return 0 on success and -1 otherwise.
  341. */
  342. static int ebpf_sync_load_legacy(ebpf_sync_syscalls_t *w, ebpf_module_t *em)
  343. {
  344. em->thread_name = w->syscall;
  345. if (!w->probe_links) {
  346. w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
  347. if (!w->probe_links) {
  348. return -1;
  349. }
  350. }
  351. return 0;
  352. }
  353. /*
  354. * Initialize Syscalls
  355. *
  356. * Load the eBPF programs to monitor syscalls
  357. *
  358. * @return 0 on success and -1 otherwise.
  359. */
  360. static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
  361. {
  362. #ifdef LIBBPF_MAJOR_VERSION
  363. ebpf_define_map_type(sync_maps, em->maps_per_core, running_on_kernel);
  364. ebpf_define_map_type(syncfs_maps, em->maps_per_core, running_on_kernel);
  365. ebpf_define_map_type(msync_maps, em->maps_per_core, running_on_kernel);
  366. ebpf_define_map_type(fsync_maps, em->maps_per_core, running_on_kernel);
  367. ebpf_define_map_type(fdatasync_maps, em->maps_per_core, running_on_kernel);
  368. ebpf_define_map_type(sync_file_range_maps, em->maps_per_core, running_on_kernel);
  369. #endif
  370. int i;
  371. const char *saved_name = em->thread_name;
  372. int errors = 0;
  373. for (i = 0; local_syscalls[i].syscall; i++) {
  374. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  375. w->sync_maps = local_syscalls[i].sync_maps;
  376. em->maps = local_syscalls[i].sync_maps;
  377. if (w->enabled) {
  378. if (em->load & EBPF_LOAD_LEGACY) {
  379. if (ebpf_sync_load_legacy(w, em))
  380. errors++;
  381. em->thread_name = saved_name;
  382. }
  383. #ifdef LIBBPF_MAJOR_VERSION
  384. else {
  385. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH];
  386. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH, w->syscall, running_on_kernel);
  387. if (ebpf_is_function_inside_btf(default_btf, syscall)) {
  388. w->sync_obj = sync_bpf__open();
  389. if (!w->sync_obj) {
  390. w->enabled = false;
  391. errors++;
  392. } else {
  393. if (ebpf_sync_load_and_attach(w->sync_obj, em, syscall, i)) {
  394. w->enabled = false;
  395. errors++;
  396. }
  397. }
  398. } else {
  399. netdata_log_info("Cannot find syscall %s we are not going to monitor it.", syscall);
  400. w->enabled = false;
  401. }
  402. em->thread_name = saved_name;
  403. }
  404. #endif
  405. }
  406. }
  407. em->thread_name = saved_name;
  408. memset(sync_counter_aggregated_data, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_syscall_stat_t));
  409. memset(sync_counter_publish_aggregated, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_publish_syscall_t));
  410. memset(sync_hash_values, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_idx_t));
  411. return (errors) ? -1 : 0;
  412. }
  413. /*****************************************************************
  414. *
  415. * DATA THREAD
  416. *
  417. *****************************************************************/
  418. /**
  419. * Read global table
  420. *
  421. * Read the table with number of calls for all functions
  422. *
  423. * @param maps_per_core do I need to read all cores?
  424. */
  425. static void ebpf_sync_read_global_table(int maps_per_core)
  426. {
  427. netdata_idx_t stored[NETDATA_MAX_PROCESSOR];
  428. uint32_t idx = NETDATA_SYNC_CALL;
  429. int i;
  430. for (i = 0; local_syscalls[i].syscall; i++) {
  431. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  432. if (w->enabled) {
  433. int fd = w->sync_maps[NETDATA_SYNC_GLOBAL_TABLE].map_fd;
  434. if (!bpf_map_lookup_elem(fd, &idx, &stored)) {
  435. int j, end = (maps_per_core) ? ebpf_nprocs : 1;
  436. netdata_idx_t total = 0;
  437. for (j = 0; j < end ;j++ )
  438. total += stored[j];
  439. sync_hash_values[i] = total;
  440. }
  441. }
  442. }
  443. }
  444. /**
  445. * Create Sync charts
  446. *
  447. * Create charts and dimensions according user input.
  448. *
  449. * @param id chart id
  450. * @param idx the first index with data.
  451. * @param end the last index with data.
  452. */
  453. static void ebpf_send_sync_chart(char *id,
  454. int idx,
  455. int end)
  456. {
  457. write_begin_chart(NETDATA_EBPF_MEMORY_GROUP, id);
  458. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  459. while (move && idx <= end) {
  460. if (local_syscalls[idx].enabled)
  461. write_chart_dimension(move->name, (long long)sync_hash_values[idx]);
  462. move = move->next;
  463. idx++;
  464. }
  465. write_end_chart();
  466. }
  467. /**
  468. * Send data
  469. *
  470. * Send global charts to Netdata
  471. */
  472. static void sync_send_data()
  473. {
  474. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled) {
  475. ebpf_send_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART, NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX);
  476. }
  477. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  478. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_MSYNC_CHART,
  479. sync_counter_publish_aggregated[NETDATA_SYNC_MSYNC_IDX].dimension,
  480. sync_hash_values[NETDATA_SYNC_MSYNC_IDX]);
  481. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled) {
  482. ebpf_send_sync_chart(NETDATA_EBPF_SYNC_CHART, NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX);
  483. }
  484. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  485. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_FILE_SEGMENT_CHART,
  486. sync_counter_publish_aggregated[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].dimension,
  487. sync_hash_values[NETDATA_SYNC_SYNC_FILE_RANGE_IDX]);
  488. }
  489. /**
  490. * Main loop for this collector.
  491. */
  492. static void sync_collector(ebpf_module_t *em)
  493. {
  494. heartbeat_t hb;
  495. heartbeat_init(&hb);
  496. int update_every = em->update_every;
  497. int counter = update_every - 1;
  498. int maps_per_core = em->maps_per_core;
  499. uint32_t running_time = 0;
  500. uint32_t lifetime = em->lifetime;
  501. while (!ebpf_exit_plugin && running_time < lifetime) {
  502. (void)heartbeat_next(&hb, USEC_PER_SEC);
  503. if (ebpf_exit_plugin || ++counter != update_every)
  504. continue;
  505. counter = 0;
  506. ebpf_sync_read_global_table(maps_per_core);
  507. pthread_mutex_lock(&lock);
  508. sync_send_data();
  509. pthread_mutex_unlock(&lock);
  510. pthread_mutex_lock(&ebpf_exit_cleanup);
  511. if (running_time && !em->running_time)
  512. running_time = update_every;
  513. else
  514. running_time += update_every;
  515. em->running_time = running_time;
  516. pthread_mutex_unlock(&ebpf_exit_cleanup);
  517. }
  518. }
  519. /*****************************************************************
  520. *
  521. * MAIN THREAD
  522. *
  523. *****************************************************************/
  524. /**
  525. * Create Sync charts
  526. *
  527. * Create charts and dimensions according user input.
  528. *
  529. * @param id chart id
  530. * @param title chart title
  531. * @param order order number of the specified chart
  532. * @param idx the first index with data.
  533. * @param end the last index with data.
  534. * @param update_every value to overwrite the update frequency set by the server.
  535. */
  536. static void ebpf_create_sync_chart(char *id,
  537. char *title,
  538. int order,
  539. int idx,
  540. int end,
  541. int update_every)
  542. {
  543. ebpf_write_chart_cmd(NETDATA_EBPF_MEMORY_GROUP, id, title, EBPF_COMMON_DIMENSION_CALL,
  544. NETDATA_EBPF_SYNC_SUBMENU, NETDATA_EBPF_CHART_TYPE_LINE, NULL, order,
  545. update_every,
  546. NETDATA_EBPF_MODULE_NAME_SYNC);
  547. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  548. while (move && idx <= end) {
  549. if (local_syscalls[idx].enabled)
  550. ebpf_write_global_dimension(move->name, move->dimension, move->algorithm);
  551. move = move->next;
  552. idx++;
  553. }
  554. }
  555. /**
  556. * Create global charts
  557. *
  558. * Call ebpf_create_chart to create the charts for the collector.
  559. *
  560. * @param update_every value to overwrite the update frequency set by the server.
  561. */
  562. static void ebpf_create_sync_charts(int update_every)
  563. {
  564. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled)
  565. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART,
  566. "Monitor calls for <code>fsync(2)</code> and <code>fdatasync(2)</code>.", 21300,
  567. NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX, update_every);
  568. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  569. ebpf_create_sync_chart(NETDATA_EBPF_MSYNC_CHART,
  570. "Monitor calls for <code>msync(2)</code>.", 21301,
  571. NETDATA_SYNC_MSYNC_IDX, NETDATA_SYNC_MSYNC_IDX, update_every);
  572. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
  573. ebpf_create_sync_chart(NETDATA_EBPF_SYNC_CHART,
  574. "Monitor calls for <code>sync(2)</code> and <code>syncfs(2)</code>.", 21302,
  575. NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX, update_every);
  576. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  577. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SEGMENT_CHART,
  578. "Monitor calls for <code>sync_file_range(2)</code>.", 21303,
  579. NETDATA_SYNC_SYNC_FILE_RANGE_IDX, NETDATA_SYNC_SYNC_FILE_RANGE_IDX, update_every);
  580. fflush(stdout);
  581. }
  582. /**
  583. * Parse Syscalls
  584. *
  585. * Parse syscall options available inside ebpf.d/sync.conf
  586. */
  587. static void ebpf_sync_parse_syscalls()
  588. {
  589. int i;
  590. for (i = 0; local_syscalls[i].syscall; i++) {
  591. local_syscalls[i].enabled = appconfig_get_boolean(&sync_config, NETDATA_SYNC_CONFIG_NAME,
  592. local_syscalls[i].syscall, CONFIG_BOOLEAN_YES);
  593. }
  594. }
  595. /**
  596. * Set sync maps
  597. *
  598. * When thread is initialized the variable sync_maps is set as null,
  599. * this function fills the variable before to use.
  600. */
  601. static void ebpf_set_sync_maps()
  602. {
  603. local_syscalls[NETDATA_SYNC_SYNC_IDX].sync_maps = sync_maps;
  604. local_syscalls[NETDATA_SYNC_SYNCFS_IDX].sync_maps = syncfs_maps;
  605. local_syscalls[NETDATA_SYNC_MSYNC_IDX].sync_maps = msync_maps;
  606. local_syscalls[NETDATA_SYNC_FSYNC_IDX].sync_maps = fsync_maps;
  607. local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].sync_maps = fdatasync_maps;
  608. local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].sync_maps = sync_file_range_maps;
  609. }
  610. /**
  611. * Sync thread
  612. *
  613. * Thread used to make sync thread
  614. *
  615. * @param ptr a pointer to `struct ebpf_module`
  616. *
  617. * @return It always return NULL
  618. */
  619. void *ebpf_sync_thread(void *ptr)
  620. {
  621. netdata_thread_cleanup_push(ebpf_sync_exit, ptr);
  622. ebpf_module_t *em = (ebpf_module_t *)ptr;
  623. ebpf_set_sync_maps();
  624. ebpf_sync_parse_syscalls();
  625. #ifdef LIBBPF_MAJOR_VERSION
  626. ebpf_adjust_thread_load(em, default_btf);
  627. #endif
  628. if (ebpf_sync_initialize_syscall(em)) {
  629. goto endsync;
  630. }
  631. int algorithms[NETDATA_SYNC_IDX_END] = { NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  632. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  633. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX };
  634. ebpf_global_labels(sync_counter_aggregated_data, sync_counter_publish_aggregated,
  635. sync_counter_dimension_name, sync_counter_dimension_name,
  636. algorithms, NETDATA_SYNC_IDX_END);
  637. pthread_mutex_lock(&lock);
  638. ebpf_create_sync_charts(em->update_every);
  639. ebpf_update_stats(&plugin_statistics, em);
  640. pthread_mutex_unlock(&lock);
  641. sync_collector(em);
  642. endsync:
  643. ebpf_update_disabled_plugin_stats(em);
  644. netdata_thread_cleanup_pop(1);
  645. return NULL;
  646. }