ebpf_fd.c 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_fd.h"
  4. static char *fd_dimension_names[NETDATA_FD_SYSCALL_END] = { "open", "close" };
  5. static char *fd_id_names[NETDATA_FD_SYSCALL_END] = { "do_sys_open", "__close_fd" };
  6. static char *close_targets[NETDATA_EBPF_MAX_FD_TARGETS] = {"close_fd", "__close_fd"};
  7. static char *open_targets[NETDATA_EBPF_MAX_FD_TARGETS] = {"do_sys_openat2", "do_sys_open"};
  8. static netdata_syscall_stat_t fd_aggregated_data[NETDATA_FD_SYSCALL_END];
  9. static netdata_publish_syscall_t fd_publish_aggregated[NETDATA_FD_SYSCALL_END];
  10. static ebpf_local_maps_t fd_maps[] = {{.name = "tbl_fd_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  11. .user_input = 0,
  12. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  13. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  14. {.name = "tbl_fd_global", .internal_input = NETDATA_KEY_END_VECTOR,
  15. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  16. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  17. {.name = "fd_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  18. .user_input = 0,
  19. .type = NETDATA_EBPF_MAP_CONTROLLER,
  20. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  21. {.name = NULL, .internal_input = 0, .user_input = 0,
  22. .type = NETDATA_EBPF_MAP_CONTROLLER,
  23. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
  24. struct config fd_config = { .first_section = NULL, .last_section = NULL, .mutex = NETDATA_MUTEX_INITIALIZER,
  25. .index = {.avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  26. .rwlock = AVL_LOCK_INITIALIZER } };
  27. struct netdata_static_thread fd_thread = {"FD KERNEL",
  28. .config_section = NULL,
  29. .config_name = NULL,
  30. .env_name = NULL,
  31. .enabled = 1,
  32. .thread = NULL,
  33. .init_routine = NULL,
  34. .start_routine = NULL};
  35. static netdata_idx_t fd_hash_values[NETDATA_FD_COUNTER];
  36. static netdata_idx_t *fd_values = NULL;
  37. netdata_fd_stat_t *fd_vector = NULL;
  38. netdata_fd_stat_t **fd_pid = NULL;
  39. netdata_ebpf_targets_t fd_targets[] = { {.name = "open", .mode = EBPF_LOAD_TRAMPOLINE},
  40. {.name = "close", .mode = EBPF_LOAD_TRAMPOLINE},
  41. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  42. #ifdef LIBBPF_MAJOR_VERSION
  43. #include "includes/fd.skel.h" // BTF code
  44. static struct fd_bpf *bpf_obj = NULL;
  45. /**
  46. * Disable probe
  47. *
  48. * Disable all probes to use exclusively another method.
  49. *
  50. * @param obj is the main structure for bpf objects
  51. */
  52. static inline void ebpf_fd_disable_probes(struct fd_bpf *obj)
  53. {
  54. bpf_program__set_autoload(obj->progs.netdata_sys_open_kprobe, false);
  55. bpf_program__set_autoload(obj->progs.netdata_sys_open_kretprobe, false);
  56. bpf_program__set_autoload(obj->progs.netdata_release_task_fd_kprobe, false);
  57. if (!strcmp(fd_targets[NETDATA_FD_SYSCALL_CLOSE].name, close_targets[NETDATA_FD_CLOSE_FD])) {
  58. bpf_program__set_autoload(obj->progs.netdata___close_fd_kretprobe, false);
  59. bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
  60. bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
  61. } else {
  62. bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
  63. bpf_program__set_autoload(obj->progs.netdata_close_fd_kretprobe, false);
  64. bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
  65. }
  66. }
  67. /*
  68. * Disable specific probe
  69. *
  70. * Disable probes according the kernel version
  71. *
  72. * @param obj is the main structure for bpf objects
  73. */
  74. static inline void ebpf_disable_specific_probes(struct fd_bpf *obj)
  75. {
  76. if (!strcmp(fd_targets[NETDATA_FD_SYSCALL_CLOSE].name, close_targets[NETDATA_FD_CLOSE_FD])) {
  77. bpf_program__set_autoload(obj->progs.netdata___close_fd_kretprobe, false);
  78. bpf_program__set_autoload(obj->progs.netdata___close_fd_kprobe, false);
  79. } else {
  80. bpf_program__set_autoload(obj->progs.netdata_close_fd_kretprobe, false);
  81. bpf_program__set_autoload(obj->progs.netdata_close_fd_kprobe, false);
  82. }
  83. }
  84. /*
  85. * Disable trampoline
  86. *
  87. * Disable all trampoline to use exclusively another method.
  88. *
  89. * @param obj is the main structure for bpf objects.
  90. */
  91. static inline void ebpf_disable_trampoline(struct fd_bpf *obj)
  92. {
  93. bpf_program__set_autoload(obj->progs.netdata_sys_open_fentry, false);
  94. bpf_program__set_autoload(obj->progs.netdata_sys_open_fexit, false);
  95. bpf_program__set_autoload(obj->progs.netdata_close_fd_fentry, false);
  96. bpf_program__set_autoload(obj->progs.netdata_close_fd_fexit, false);
  97. bpf_program__set_autoload(obj->progs.netdata___close_fd_fentry, false);
  98. bpf_program__set_autoload(obj->progs.netdata___close_fd_fexit, false);
  99. bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
  100. }
  101. /*
  102. * Disable specific trampoline
  103. *
  104. * Disable trampoline according to kernel version.
  105. *
  106. * @param obj is the main structure for bpf objects.
  107. */
  108. static inline void ebpf_disable_specific_trampoline(struct fd_bpf *obj)
  109. {
  110. if (!strcmp(fd_targets[NETDATA_FD_SYSCALL_CLOSE].name, close_targets[NETDATA_FD_CLOSE_FD])) {
  111. bpf_program__set_autoload(obj->progs.netdata___close_fd_fentry, false);
  112. bpf_program__set_autoload(obj->progs.netdata___close_fd_fexit, false);
  113. } else {
  114. bpf_program__set_autoload(obj->progs.netdata_close_fd_fentry, false);
  115. bpf_program__set_autoload(obj->progs.netdata_close_fd_fexit, false);
  116. }
  117. }
  118. /**
  119. * Set trampoline target
  120. *
  121. * Set the targets we will monitor.
  122. *
  123. * @param obj is the main structure for bpf objects.
  124. */
  125. static void ebpf_set_trampoline_target(struct fd_bpf *obj)
  126. {
  127. bpf_program__set_attach_target(obj->progs.netdata_sys_open_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
  128. bpf_program__set_attach_target(obj->progs.netdata_sys_open_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
  129. bpf_program__set_attach_target(obj->progs.netdata_release_task_fd_fentry, 0, EBPF_COMMON_FNCT_CLEAN_UP);
  130. if (!strcmp(fd_targets[NETDATA_FD_SYSCALL_CLOSE].name, close_targets[NETDATA_FD_CLOSE_FD])) {
  131. bpf_program__set_attach_target(
  132. obj->progs.netdata_close_fd_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  133. bpf_program__set_attach_target(obj->progs.netdata_close_fd_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  134. } else {
  135. bpf_program__set_attach_target(
  136. obj->progs.netdata___close_fd_fentry, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  137. bpf_program__set_attach_target(
  138. obj->progs.netdata___close_fd_fexit, 0, fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  139. }
  140. }
  141. /**
  142. * Mount Attach Probe
  143. *
  144. * Attach probes to target
  145. *
  146. * @param obj is the main structure for bpf objects.
  147. *
  148. * @return It returns 0 on success and -1 otherwise.
  149. */
  150. static int ebpf_fd_attach_probe(struct fd_bpf *obj)
  151. {
  152. obj->links.netdata_sys_open_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sys_open_kprobe, false,
  153. fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
  154. int ret = libbpf_get_error(obj->links.netdata_sys_open_kprobe);
  155. if (ret)
  156. return -1;
  157. obj->links.netdata_sys_open_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_sys_open_kretprobe, true,
  158. fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
  159. ret = libbpf_get_error(obj->links.netdata_sys_open_kretprobe);
  160. if (ret)
  161. return -1;
  162. obj->links.netdata_release_task_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_release_task_fd_kprobe,
  163. false,
  164. EBPF_COMMON_FNCT_CLEAN_UP);
  165. ret = libbpf_get_error(obj->links.netdata_release_task_fd_kprobe);
  166. if (ret)
  167. return -1;
  168. if (!strcmp(fd_targets[NETDATA_FD_SYSCALL_CLOSE].name, close_targets[NETDATA_FD_CLOSE_FD])) {
  169. obj->links.netdata_close_fd_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_close_fd_kretprobe, true,
  170. fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  171. ret = libbpf_get_error(obj->links.netdata_close_fd_kretprobe);
  172. if (ret)
  173. return -1;
  174. obj->links.netdata_close_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_close_fd_kprobe, false,
  175. fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  176. ret = libbpf_get_error(obj->links.netdata_close_fd_kprobe);
  177. if (ret)
  178. return -1;
  179. } else {
  180. obj->links.netdata___close_fd_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata___close_fd_kretprobe,
  181. true,
  182. fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  183. ret = libbpf_get_error(obj->links.netdata___close_fd_kretprobe);
  184. if (ret)
  185. return -1;
  186. obj->links.netdata___close_fd_kprobe = bpf_program__attach_kprobe(obj->progs.netdata___close_fd_kprobe,
  187. false,
  188. fd_targets[NETDATA_FD_SYSCALL_CLOSE].name);
  189. ret = libbpf_get_error(obj->links.netdata___close_fd_kprobe);
  190. if (ret)
  191. return -1;
  192. }
  193. return 0;
  194. }
  195. /**
  196. * FD Fill Address
  197. *
  198. * Fill address value used to load probes/trampoline.
  199. */
  200. static inline void ebpf_fd_fill_address(ebpf_addresses_t *address, char **targets)
  201. {
  202. int i;
  203. for (i = 0; i < NETDATA_EBPF_MAX_FD_TARGETS; i++) {
  204. address->function = targets[i];
  205. ebpf_load_addresses(address, -1);
  206. if (address->addr)
  207. break;
  208. }
  209. }
  210. /**
  211. * Set target values
  212. *
  213. * Set pointers used to load data.
  214. *
  215. * @return It returns 0 on success and -1 otherwise.
  216. */
  217. static int ebpf_fd_set_target_values()
  218. {
  219. ebpf_addresses_t address = {.function = NULL, .hash = 0, .addr = 0};
  220. ebpf_fd_fill_address(&address, close_targets);
  221. if (!address.addr)
  222. return -1;
  223. fd_targets[NETDATA_FD_SYSCALL_CLOSE].name = address.function;
  224. address.addr = 0;
  225. ebpf_fd_fill_address(&address, open_targets);
  226. if (!address.addr)
  227. return -1;
  228. fd_targets[NETDATA_FD_SYSCALL_OPEN].name = address.function;
  229. return 0;
  230. }
  231. /**
  232. * Set hash tables
  233. *
  234. * Set the values for maps according the value given by kernel.
  235. *
  236. * @param obj is the main structure for bpf objects.
  237. */
  238. static void ebpf_fd_set_hash_tables(struct fd_bpf *obj)
  239. {
  240. fd_maps[NETDATA_FD_GLOBAL_STATS].map_fd = bpf_map__fd(obj->maps.tbl_fd_global);
  241. fd_maps[NETDATA_FD_PID_STATS].map_fd = bpf_map__fd(obj->maps.tbl_fd_pid);
  242. fd_maps[NETDATA_FD_CONTROLLER].map_fd = bpf_map__fd(obj->maps.fd_ctrl);
  243. }
  244. /**
  245. * Adjust Map Size
  246. *
  247. * Resize maps according input from users.
  248. *
  249. * @param obj is the main structure for bpf objects.
  250. * @param em structure with configuration
  251. */
  252. static void ebpf_fd_adjust_map_size(struct fd_bpf *obj, ebpf_module_t *em)
  253. {
  254. ebpf_update_map_size(obj->maps.tbl_fd_pid, &fd_maps[NETDATA_FD_PID_STATS],
  255. em, bpf_map__name(obj->maps.tbl_fd_pid));
  256. }
  257. /**
  258. * Disable Release Task
  259. *
  260. * Disable release task when apps is not enabled.
  261. *
  262. * @param obj is the main structure for bpf objects.
  263. */
  264. static void ebpf_fd_disable_release_task(struct fd_bpf *obj)
  265. {
  266. bpf_program__set_autoload(obj->progs.netdata_release_task_fd_kprobe, false);
  267. bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
  268. }
  269. /**
  270. * Load and attach
  271. *
  272. * Load and attach the eBPF code in kernel.
  273. *
  274. * @param obj is the main structure for bpf objects.
  275. * @param em structure with configuration
  276. *
  277. * @return it returns 0 on success and -1 otherwise
  278. */
  279. static inline int ebpf_fd_load_and_attach(struct fd_bpf *obj, ebpf_module_t *em)
  280. {
  281. netdata_ebpf_targets_t *mt = em->targets;
  282. netdata_ebpf_program_loaded_t test = mt[NETDATA_FD_SYSCALL_OPEN].mode;
  283. if (ebpf_fd_set_target_values()) {
  284. error("%s file descriptor.", NETDATA_EBPF_DEFAULT_FNT_NOT_FOUND);
  285. return -1;
  286. }
  287. if (test == EBPF_LOAD_TRAMPOLINE) {
  288. ebpf_fd_disable_probes(obj);
  289. ebpf_disable_specific_trampoline(obj);
  290. ebpf_set_trampoline_target(obj);
  291. // TODO: Remove this in next PR, because this specific trampoline has an error.
  292. bpf_program__set_autoload(obj->progs.netdata_release_task_fd_fentry, false);
  293. } else {
  294. ebpf_disable_trampoline(obj);
  295. ebpf_disable_specific_probes(obj);
  296. }
  297. ebpf_fd_adjust_map_size(obj, em);
  298. if (!em->apps_charts && !em->cgroup_charts)
  299. ebpf_fd_disable_release_task(obj);
  300. int ret = fd_bpf__load(obj);
  301. if (ret) {
  302. return ret;
  303. }
  304. ret = (test == EBPF_LOAD_TRAMPOLINE) ? fd_bpf__attach(obj) : ebpf_fd_attach_probe(obj);
  305. if (!ret) {
  306. ebpf_fd_set_hash_tables(obj);
  307. ebpf_update_controller(fd_maps[NETDATA_CACHESTAT_CTRL].map_fd, em);
  308. }
  309. return ret;
  310. }
  311. #endif
  312. /*****************************************************************
  313. *
  314. * FUNCTIONS TO CLOSE THE THREAD
  315. *
  316. *****************************************************************/
  317. /**
  318. * FD Free
  319. *
  320. * Cleanup variables after child threads to stop
  321. *
  322. * @param ptr thread data.
  323. */
  324. static void ebpf_fd_free(ebpf_module_t *em)
  325. {
  326. pthread_mutex_lock(&ebpf_exit_cleanup);
  327. if (em->thread->enabled == NETDATA_THREAD_EBPF_RUNNING) {
  328. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPING;
  329. pthread_mutex_unlock(&ebpf_exit_cleanup);
  330. return;
  331. }
  332. pthread_mutex_unlock(&ebpf_exit_cleanup);
  333. ebpf_cleanup_publish_syscall(fd_publish_aggregated);
  334. freez(fd_thread.thread);
  335. freez(fd_values);
  336. freez(fd_vector);
  337. #ifdef LIBBPF_MAJOR_VERSION
  338. if (bpf_obj)
  339. fd_bpf__destroy(bpf_obj);
  340. #endif
  341. pthread_mutex_lock(&ebpf_exit_cleanup);
  342. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
  343. pthread_mutex_unlock(&ebpf_exit_cleanup);
  344. }
  345. /**
  346. * FD Exit
  347. *
  348. * Cancel child thread and exit.
  349. *
  350. * @param ptr thread data.
  351. */
  352. static void ebpf_fd_exit(void *ptr)
  353. {
  354. ebpf_module_t *em = (ebpf_module_t *)ptr;
  355. if (fd_thread.thread)
  356. netdata_thread_cancel(*fd_thread.thread);
  357. ebpf_fd_free(em);
  358. }
  359. /**
  360. * Clean up the main thread.
  361. *
  362. * @param ptr thread data.
  363. */
  364. static void ebpf_fd_cleanup(void *ptr)
  365. {
  366. ebpf_module_t *em = (ebpf_module_t *)ptr;
  367. ebpf_fd_free(em);
  368. }
  369. /*****************************************************************
  370. *
  371. * MAIN LOOP
  372. *
  373. *****************************************************************/
  374. /**
  375. * Send data to Netdata calling auxiliary functions.
  376. *
  377. * @param em the structure with thread information
  378. */
  379. static void ebpf_fd_send_data(ebpf_module_t *em)
  380. {
  381. fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].ncall = fd_hash_values[NETDATA_KEY_CALLS_DO_SYS_OPEN];
  382. fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].nerr = fd_hash_values[NETDATA_KEY_ERROR_DO_SYS_OPEN];
  383. fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].ncall = fd_hash_values[NETDATA_KEY_CALLS_CLOSE_FD];
  384. fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].nerr = fd_hash_values[NETDATA_KEY_ERROR_CLOSE_FD];
  385. write_count_chart(NETDATA_FILE_OPEN_CLOSE_COUNT, NETDATA_FILESYSTEM_FAMILY, fd_publish_aggregated,
  386. NETDATA_FD_SYSCALL_END);
  387. if (em->mode < MODE_ENTRY) {
  388. write_err_chart(NETDATA_FILE_OPEN_ERR_COUNT, NETDATA_FILESYSTEM_FAMILY,
  389. fd_publish_aggregated, NETDATA_FD_SYSCALL_END);
  390. }
  391. }
  392. /**
  393. * Read global counter
  394. *
  395. * Read the table with number of calls for all functions
  396. */
  397. static void read_global_table()
  398. {
  399. uint32_t idx;
  400. netdata_idx_t *val = fd_hash_values;
  401. netdata_idx_t *stored = fd_values;
  402. int fd = fd_maps[NETDATA_FD_GLOBAL_STATS].map_fd;
  403. for (idx = NETDATA_KEY_CALLS_DO_SYS_OPEN; idx < NETDATA_FD_COUNTER; idx++) {
  404. if (!bpf_map_lookup_elem(fd, &idx, stored)) {
  405. int i;
  406. int end = ebpf_nprocs;
  407. netdata_idx_t total = 0;
  408. for (i = 0; i < end; i++)
  409. total += stored[i];
  410. val[idx] = total;
  411. }
  412. }
  413. }
  414. /**
  415. * File descriptor read hash
  416. *
  417. * This is the thread callback.
  418. * This thread is necessary, because we cannot freeze the whole plugin to read the data.
  419. *
  420. * @param ptr It is a NULL value for this thread.
  421. *
  422. * @return It always returns NULL.
  423. */
  424. void *ebpf_fd_read_hash(void *ptr)
  425. {
  426. netdata_thread_cleanup_push(ebpf_fd_cleanup, ptr);
  427. heartbeat_t hb;
  428. heartbeat_init(&hb);
  429. ebpf_module_t *em = (ebpf_module_t *)ptr;
  430. usec_t step = NETDATA_FD_SLEEP_MS * em->update_every;
  431. while (!ebpf_exit_plugin) {
  432. (void)heartbeat_next(&hb, step);
  433. read_global_table();
  434. }
  435. netdata_thread_cleanup_pop(1);
  436. return NULL;
  437. }
  438. /**
  439. * Apps Accumulator
  440. *
  441. * Sum all values read from kernel and store in the first address.
  442. *
  443. * @param out the vector with read values.
  444. */
  445. static void fd_apps_accumulator(netdata_fd_stat_t *out)
  446. {
  447. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  448. netdata_fd_stat_t *total = &out[0];
  449. for (i = 1; i < end; i++) {
  450. netdata_fd_stat_t *w = &out[i];
  451. total->open_call += w->open_call;
  452. total->close_call += w->close_call;
  453. total->open_err += w->open_err;
  454. total->close_err += w->close_err;
  455. }
  456. }
  457. /**
  458. * Fill PID
  459. *
  460. * Fill PID structures
  461. *
  462. * @param current_pid pid that we are collecting data
  463. * @param out values read from hash tables;
  464. */
  465. static void fd_fill_pid(uint32_t current_pid, netdata_fd_stat_t *publish)
  466. {
  467. netdata_fd_stat_t *curr = fd_pid[current_pid];
  468. if (!curr) {
  469. curr = callocz(1, sizeof(netdata_fd_stat_t));
  470. fd_pid[current_pid] = curr;
  471. }
  472. memcpy(curr, &publish[0], sizeof(netdata_fd_stat_t));
  473. }
  474. /**
  475. * Read APPS table
  476. *
  477. * Read the apps table and store data inside the structure.
  478. */
  479. static void read_apps_table()
  480. {
  481. netdata_fd_stat_t *fv = fd_vector;
  482. uint32_t key;
  483. struct pid_stat *pids = root_of_pids;
  484. int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
  485. size_t length = sizeof(netdata_fd_stat_t) * ebpf_nprocs;
  486. while (pids) {
  487. key = pids->pid;
  488. if (bpf_map_lookup_elem(fd, &key, fv)) {
  489. pids = pids->next;
  490. continue;
  491. }
  492. fd_apps_accumulator(fv);
  493. fd_fill_pid(key, fv);
  494. // We are cleaning to avoid passing data read from one process to other.
  495. memset(fv, 0, length);
  496. pids = pids->next;
  497. }
  498. }
  499. /**
  500. * Update cgroup
  501. *
  502. * Update cgroup data based in
  503. */
  504. static void ebpf_update_fd_cgroup()
  505. {
  506. ebpf_cgroup_target_t *ect ;
  507. netdata_fd_stat_t *fv = fd_vector;
  508. int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
  509. size_t length = sizeof(netdata_fd_stat_t) * ebpf_nprocs;
  510. pthread_mutex_lock(&mutex_cgroup_shm);
  511. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  512. struct pid_on_target2 *pids;
  513. for (pids = ect->pids; pids; pids = pids->next) {
  514. int pid = pids->pid;
  515. netdata_fd_stat_t *out = &pids->fd;
  516. if (likely(fd_pid) && fd_pid[pid]) {
  517. netdata_fd_stat_t *in = fd_pid[pid];
  518. memcpy(out, in, sizeof(netdata_fd_stat_t));
  519. } else {
  520. memset(fv, 0, length);
  521. if (!bpf_map_lookup_elem(fd, &pid, fv)) {
  522. fd_apps_accumulator(fv);
  523. memcpy(out, fv, sizeof(netdata_fd_stat_t));
  524. }
  525. }
  526. }
  527. }
  528. pthread_mutex_unlock(&mutex_cgroup_shm);
  529. }
  530. /**
  531. * Sum PIDs
  532. *
  533. * Sum values for all targets.
  534. *
  535. * @param fd the output
  536. * @param root list of pids
  537. */
  538. static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct pid_on_target *root)
  539. {
  540. uint32_t open_call = 0;
  541. uint32_t close_call = 0;
  542. uint32_t open_err = 0;
  543. uint32_t close_err = 0;
  544. while (root) {
  545. int32_t pid = root->pid;
  546. netdata_fd_stat_t *w = fd_pid[pid];
  547. if (w) {
  548. open_call += w->open_call;
  549. close_call += w->close_call;
  550. open_err += w->open_err;
  551. close_err += w->close_err;
  552. }
  553. root = root->next;
  554. }
  555. // These conditions were added, because we are using incremental algorithm
  556. fd->open_call = (open_call >= fd->open_call) ? open_call : fd->open_call;
  557. fd->close_call = (close_call >= fd->close_call) ? close_call : fd->close_call;
  558. fd->open_err = (open_err >= fd->open_err) ? open_err : fd->open_err;
  559. fd->close_err = (close_err >= fd->close_err) ? close_err : fd->close_err;
  560. }
  561. /**
  562. * Send data to Netdata calling auxiliary functions.
  563. *
  564. * @param em the structure with thread information
  565. * @param root the target list.
  566. */
  567. void ebpf_fd_send_apps_data(ebpf_module_t *em, struct target *root)
  568. {
  569. struct target *w;
  570. for (w = root; w; w = w->next) {
  571. if (unlikely(w->exposed && w->processes)) {
  572. ebpf_fd_sum_pids(&w->fd, w->root_pid);
  573. }
  574. }
  575. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
  576. for (w = root; w; w = w->next) {
  577. if (unlikely(w->exposed && w->processes)) {
  578. write_chart_dimension(w->name, w->fd.open_call);
  579. }
  580. }
  581. write_end_chart();
  582. if (em->mode < MODE_ENTRY) {
  583. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
  584. for (w = root; w; w = w->next) {
  585. if (unlikely(w->exposed && w->processes)) {
  586. write_chart_dimension(w->name, w->fd.open_err);
  587. }
  588. }
  589. write_end_chart();
  590. }
  591. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSED);
  592. for (w = root; w; w = w->next) {
  593. if (unlikely(w->exposed && w->processes)) {
  594. write_chart_dimension(w->name, w->fd.close_call);
  595. }
  596. }
  597. write_end_chart();
  598. if (em->mode < MODE_ENTRY) {
  599. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
  600. for (w = root; w; w = w->next) {
  601. if (unlikely(w->exposed && w->processes)) {
  602. write_chart_dimension(w->name, w->fd.close_err);
  603. }
  604. }
  605. write_end_chart();
  606. }
  607. }
  608. /**
  609. * Sum PIDs
  610. *
  611. * Sum values for all targets.
  612. *
  613. * @param fd structure used to store data
  614. * @param pids input data
  615. */
  616. static void ebpf_fd_sum_cgroup_pids(netdata_fd_stat_t *fd, struct pid_on_target2 *pids)
  617. {
  618. netdata_fd_stat_t accumulator;
  619. memset(&accumulator, 0, sizeof(accumulator));
  620. while (pids) {
  621. netdata_fd_stat_t *w = &pids->fd;
  622. accumulator.open_err += w->open_err;
  623. accumulator.open_call += w->open_call;
  624. accumulator.close_call += w->close_call;
  625. accumulator.close_err += w->close_err;
  626. pids = pids->next;
  627. }
  628. fd->open_call = (accumulator.open_call >= fd->open_call) ? accumulator.open_call : fd->open_call;
  629. fd->open_err = (accumulator.open_err >= fd->open_err) ? accumulator.open_err : fd->open_err;
  630. fd->close_call = (accumulator.close_call >= fd->close_call) ? accumulator.close_call : fd->close_call;
  631. fd->close_err = (accumulator.close_err >= fd->close_err) ? accumulator.close_err : fd->close_err;
  632. }
  633. /**
  634. * Create specific file descriptor charts
  635. *
  636. * Create charts for cgroup/application.
  637. *
  638. * @param type the chart type.
  639. * @param em the main thread structure.
  640. */
  641. static void ebpf_create_specific_fd_charts(char *type, ebpf_module_t *em)
  642. {
  643. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_FILE_OPEN, "Number of open files",
  644. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  645. NETDATA_CGROUP_FD_OPEN_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  646. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5400,
  647. ebpf_create_global_dimension,
  648. &fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN],
  649. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  650. if (em->mode < MODE_ENTRY) {
  651. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR, "Fails to open files",
  652. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  653. NETDATA_CGROUP_FD_OPEN_ERR_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  654. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5401,
  655. ebpf_create_global_dimension,
  656. &fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN],
  657. 1, em->update_every,
  658. NETDATA_EBPF_MODULE_NAME_SWAP);
  659. }
  660. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_FILE_CLOSED, "Files closed",
  661. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  662. NETDATA_CGROUP_FD_CLOSE_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  663. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5402,
  664. ebpf_create_global_dimension,
  665. &fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE],
  666. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
  667. if (em->mode < MODE_ENTRY) {
  668. ebpf_create_chart(type, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR, "Fails to close files",
  669. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  670. NETDATA_CGROUP_FD_CLOSE_ERR_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
  671. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5403,
  672. ebpf_create_global_dimension,
  673. &fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE],
  674. 1, em->update_every,
  675. NETDATA_EBPF_MODULE_NAME_SWAP);
  676. }
  677. }
  678. /**
  679. * Obsolete specific file descriptor charts
  680. *
  681. * Obsolete charts for cgroup/application.
  682. *
  683. * @param type the chart type.
  684. * @param em the main thread structure.
  685. */
  686. static void ebpf_obsolete_specific_fd_charts(char *type, ebpf_module_t *em)
  687. {
  688. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_FILE_OPEN, "Number of open files",
  689. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_GROUP,
  690. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_FD_OPEN_CONTEXT,
  691. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5400, em->update_every);
  692. if (em->mode < MODE_ENTRY) {
  693. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR, "Fails to open files",
  694. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_GROUP,
  695. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_FD_OPEN_ERR_CONTEXT,
  696. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5401, em->update_every);
  697. }
  698. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_FILE_CLOSED, "Files closed",
  699. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_GROUP,
  700. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_FD_CLOSE_CONTEXT,
  701. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5402, em->update_every);
  702. if (em->mode < MODE_ENTRY) {
  703. ebpf_write_chart_obsolete(type, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR, "Fails to close files",
  704. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_GROUP,
  705. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_FD_CLOSE_ERR_CONTEXT,
  706. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5403, em->update_every);
  707. }
  708. }
  709. /*
  710. * Send specific file descriptor data
  711. *
  712. * Send data for specific cgroup/apps.
  713. *
  714. * @param type chart type
  715. * @param values structure with values that will be sent to netdata
  716. */
  717. static void ebpf_send_specific_fd_data(char *type, netdata_fd_stat_t *values, ebpf_module_t *em)
  718. {
  719. write_begin_chart(type, NETDATA_SYSCALL_APPS_FILE_OPEN);
  720. write_chart_dimension(fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].name, (long long)values->open_call);
  721. write_end_chart();
  722. if (em->mode < MODE_ENTRY) {
  723. write_begin_chart(type, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
  724. write_chart_dimension(fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].name, (long long)values->open_err);
  725. write_end_chart();
  726. }
  727. write_begin_chart(type, NETDATA_SYSCALL_APPS_FILE_CLOSED);
  728. write_chart_dimension(fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].name, (long long)values->close_call);
  729. write_end_chart();
  730. if (em->mode < MODE_ENTRY) {
  731. write_begin_chart(type, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
  732. write_chart_dimension(fd_publish_aggregated[NETDATA_FD_SYSCALL_CLOSE].name, (long long)values->close_err);
  733. write_end_chart();
  734. }
  735. }
  736. /**
  737. * Create systemd file descriptor charts
  738. *
  739. * Create charts when systemd is enabled
  740. *
  741. * @param em the main collector structure
  742. **/
  743. static void ebpf_create_systemd_fd_charts(ebpf_module_t *em)
  744. {
  745. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_FILE_OPEN, "Number of open files",
  746. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  747. NETDATA_EBPF_CHART_TYPE_STACKED, 20061,
  748. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_FD_OPEN_CONTEXT,
  749. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  750. if (em->mode < MODE_ENTRY) {
  751. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR, "Fails to open files",
  752. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  753. NETDATA_EBPF_CHART_TYPE_STACKED, 20062,
  754. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_FD_OPEN_ERR_CONTEXT,
  755. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  756. }
  757. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_FILE_CLOSED, "Files closed",
  758. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  759. NETDATA_EBPF_CHART_TYPE_STACKED, 20063,
  760. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_FD_CLOSE_CONTEXT,
  761. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  762. if (em->mode < MODE_ENTRY) {
  763. ebpf_create_charts_on_systemd(NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR, "Fails to close files",
  764. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_FILE_CGROUP_GROUP,
  765. NETDATA_EBPF_CHART_TYPE_STACKED, 20064,
  766. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX], NETDATA_SYSTEMD_FD_CLOSE_ERR_CONTEXT,
  767. NETDATA_EBPF_MODULE_NAME_PROCESS, em->update_every);
  768. }
  769. }
  770. /**
  771. * Send Systemd charts
  772. *
  773. * Send collected data to Netdata.
  774. *
  775. * @param em the main collector structure
  776. */
  777. static void ebpf_send_systemd_fd_charts(ebpf_module_t *em)
  778. {
  779. ebpf_cgroup_target_t *ect;
  780. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN);
  781. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  782. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  783. write_chart_dimension(ect->name, ect->publish_systemd_fd.open_call);
  784. }
  785. }
  786. write_end_chart();
  787. if (em->mode < MODE_ENTRY) {
  788. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR);
  789. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  790. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  791. write_chart_dimension(ect->name, ect->publish_systemd_fd.open_err);
  792. }
  793. }
  794. write_end_chart();
  795. }
  796. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSED);
  797. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  798. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  799. write_chart_dimension(ect->name, ect->publish_systemd_fd.close_call);
  800. }
  801. }
  802. write_end_chart();
  803. if (em->mode < MODE_ENTRY) {
  804. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR);
  805. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  806. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  807. write_chart_dimension(ect->name, ect->publish_systemd_fd.close_err);
  808. }
  809. }
  810. write_end_chart();
  811. }
  812. }
  813. /**
  814. * Send data to Netdata calling auxiliary functions.
  815. *
  816. * @param em the main collector structure
  817. */
  818. static void ebpf_fd_send_cgroup_data(ebpf_module_t *em)
  819. {
  820. if (!ebpf_cgroup_pids)
  821. return;
  822. pthread_mutex_lock(&mutex_cgroup_shm);
  823. ebpf_cgroup_target_t *ect;
  824. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  825. ebpf_fd_sum_cgroup_pids(&ect->publish_systemd_fd, ect->pids);
  826. }
  827. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  828. if (has_systemd) {
  829. if (send_cgroup_chart) {
  830. ebpf_create_systemd_fd_charts(em);
  831. }
  832. ebpf_send_systemd_fd_charts(em);
  833. }
  834. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  835. if (ect->systemd)
  836. continue;
  837. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_FD_CHART) && ect->updated) {
  838. ebpf_create_specific_fd_charts(ect->name, em);
  839. ect->flags |= NETDATA_EBPF_CGROUP_HAS_FD_CHART;
  840. }
  841. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_FD_CHART ) {
  842. if (ect->updated) {
  843. ebpf_send_specific_fd_data(ect->name, &ect->publish_systemd_fd, em);
  844. } else {
  845. ebpf_obsolete_specific_fd_charts(ect->name, em);
  846. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_FD_CHART;
  847. }
  848. }
  849. }
  850. pthread_mutex_unlock(&mutex_cgroup_shm);
  851. }
  852. /**
  853. * Main loop for this collector.
  854. */
  855. static void fd_collector(ebpf_module_t *em)
  856. {
  857. fd_thread.thread = mallocz(sizeof(netdata_thread_t));
  858. fd_thread.start_routine = ebpf_fd_read_hash;
  859. netdata_thread_create(fd_thread.thread, fd_thread.name, NETDATA_THREAD_OPTION_DEFAULT,
  860. ebpf_fd_read_hash, em);
  861. int cgroups = em->cgroup_charts;
  862. heartbeat_t hb;
  863. heartbeat_init(&hb);
  864. usec_t step = em->update_every * USEC_PER_SEC;
  865. while (!ebpf_exit_plugin) {
  866. (void)heartbeat_next(&hb, step);
  867. if (ebpf_exit_plugin)
  868. break;
  869. netdata_apps_integration_flags_t apps = em->apps_charts;
  870. pthread_mutex_lock(&collect_data_mutex);
  871. if (apps)
  872. read_apps_table();
  873. if (cgroups)
  874. ebpf_update_fd_cgroup();
  875. pthread_mutex_lock(&lock);
  876. ebpf_fd_send_data(em);
  877. if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
  878. ebpf_fd_send_apps_data(em, apps_groups_root_target);
  879. if (cgroups)
  880. ebpf_fd_send_cgroup_data(em);
  881. pthread_mutex_unlock(&lock);
  882. pthread_mutex_unlock(&collect_data_mutex);
  883. }
  884. }
  885. /*****************************************************************
  886. *
  887. * CREATE CHARTS
  888. *
  889. *****************************************************************/
  890. /**
  891. * Create apps charts
  892. *
  893. * Call ebpf_create_chart to create the charts on apps submenu.
  894. *
  895. * @param em a pointer to the structure with the default values.
  896. */
  897. void ebpf_fd_create_apps_charts(struct ebpf_module *em, void *ptr)
  898. {
  899. struct target *root = ptr;
  900. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN,
  901. "Number of open files",
  902. EBPF_COMMON_DIMENSION_CALL,
  903. NETDATA_APPS_FILE_GROUP,
  904. NETDATA_EBPF_CHART_TYPE_STACKED,
  905. 20061,
  906. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  907. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  908. if (em->mode < MODE_ENTRY) {
  909. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR,
  910. "Fails to open files",
  911. EBPF_COMMON_DIMENSION_CALL,
  912. NETDATA_APPS_FILE_GROUP,
  913. NETDATA_EBPF_CHART_TYPE_STACKED,
  914. 20062,
  915. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  916. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  917. }
  918. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSED,
  919. "Files closed",
  920. EBPF_COMMON_DIMENSION_CALL,
  921. NETDATA_APPS_FILE_GROUP,
  922. NETDATA_EBPF_CHART_TYPE_STACKED,
  923. 20063,
  924. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  925. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  926. if (em->mode < MODE_ENTRY) {
  927. ebpf_create_charts_on_apps(NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR,
  928. "Fails to close files",
  929. EBPF_COMMON_DIMENSION_CALL,
  930. NETDATA_APPS_FILE_GROUP,
  931. NETDATA_EBPF_CHART_TYPE_STACKED,
  932. 20064,
  933. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  934. root, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
  935. }
  936. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  937. }
  938. /**
  939. * Create global charts
  940. *
  941. * Call ebpf_create_chart to create the charts for the collector.
  942. *
  943. * @param em a pointer to the structure with the default values.
  944. */
  945. static void ebpf_create_fd_global_charts(ebpf_module_t *em)
  946. {
  947. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY,
  948. NETDATA_FILE_OPEN_CLOSE_COUNT,
  949. "Open and close calls",
  950. EBPF_COMMON_DIMENSION_CALL,
  951. NETDATA_FILE_GROUP,
  952. NULL,
  953. NETDATA_EBPF_CHART_TYPE_LINE,
  954. NETDATA_CHART_PRIO_EBPF_FD_CHARTS,
  955. ebpf_create_global_dimension,
  956. fd_publish_aggregated,
  957. NETDATA_FD_SYSCALL_END,
  958. em->update_every, NETDATA_EBPF_MODULE_NAME_FD);
  959. if (em->mode < MODE_ENTRY) {
  960. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY,
  961. NETDATA_FILE_OPEN_ERR_COUNT,
  962. "Open fails",
  963. EBPF_COMMON_DIMENSION_CALL,
  964. NETDATA_FILE_GROUP,
  965. NULL,
  966. NETDATA_EBPF_CHART_TYPE_LINE,
  967. NETDATA_CHART_PRIO_EBPF_FD_CHARTS + 1,
  968. ebpf_create_global_dimension,
  969. fd_publish_aggregated,
  970. NETDATA_FD_SYSCALL_END,
  971. em->update_every, NETDATA_EBPF_MODULE_NAME_FD);
  972. }
  973. }
  974. /*****************************************************************
  975. *
  976. * MAIN THREAD
  977. *
  978. *****************************************************************/
  979. /**
  980. * Allocate vectors used with this thread.
  981. *
  982. * We are not testing the return, because callocz does this and shutdown the software
  983. * case it was not possible to allocate.
  984. *
  985. * @param apps is apps enabled?
  986. */
  987. static void ebpf_fd_allocate_global_vectors(int apps)
  988. {
  989. if (apps)
  990. fd_pid = callocz((size_t)pid_max, sizeof(netdata_fd_stat_t *));
  991. fd_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_fd_stat_t));
  992. fd_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  993. }
  994. /*
  995. * Load BPF
  996. *
  997. * Load BPF files.
  998. *
  999. * @param em the structure with configuration
  1000. */
  1001. static int ebpf_fd_load_bpf(ebpf_module_t *em)
  1002. {
  1003. int ret = 0;
  1004. ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_FD_SYSCALL_OPEN].mode);
  1005. if (em->load & EBPF_LOAD_LEGACY) {
  1006. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  1007. if (!em->probe_links) {
  1008. em->enabled = CONFIG_BOOLEAN_NO;
  1009. ret = -1;
  1010. }
  1011. }
  1012. #ifdef LIBBPF_MAJOR_VERSION
  1013. else {
  1014. bpf_obj = fd_bpf__open();
  1015. if (!bpf_obj)
  1016. ret = -1;
  1017. else
  1018. ret = ebpf_fd_load_and_attach(bpf_obj, em);
  1019. }
  1020. #endif
  1021. if (ret)
  1022. error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
  1023. return ret;
  1024. }
  1025. /**
  1026. * Directory Cache thread
  1027. *
  1028. * Thread used to make dcstat thread
  1029. *
  1030. * @param ptr a pointer to `struct ebpf_module`
  1031. *
  1032. * @return It always returns NULL
  1033. */
  1034. void *ebpf_fd_thread(void *ptr)
  1035. {
  1036. netdata_thread_cleanup_push(ebpf_fd_exit, ptr);
  1037. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1038. em->maps = fd_maps;
  1039. #ifdef LIBBPF_MAJOR_VERSION
  1040. ebpf_adjust_thread_load(em, default_btf);
  1041. #endif
  1042. if (ebpf_fd_load_bpf(em)) {
  1043. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
  1044. goto endfd;
  1045. }
  1046. ebpf_fd_allocate_global_vectors(em->apps_charts);
  1047. int algorithms[NETDATA_FD_SYSCALL_END] = {
  1048. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX
  1049. };
  1050. ebpf_global_labels(fd_aggregated_data, fd_publish_aggregated, fd_dimension_names, fd_id_names,
  1051. algorithms, NETDATA_FD_SYSCALL_END);
  1052. pthread_mutex_lock(&lock);
  1053. ebpf_create_fd_global_charts(em);
  1054. ebpf_update_stats(&plugin_statistics, em);
  1055. pthread_mutex_unlock(&lock);
  1056. fd_collector(em);
  1057. endfd:
  1058. ebpf_update_disabled_plugin_stats(em);
  1059. netdata_thread_cleanup_pop(1);
  1060. return NULL;
  1061. }