ebpf_shm.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_shm.h"
  4. static char *shm_dimension_name[NETDATA_SHM_END] = { "get", "at", "dt", "ctl" };
  5. static netdata_syscall_stat_t shm_aggregated_data[NETDATA_SHM_END];
  6. static netdata_publish_syscall_t shm_publish_aggregated[NETDATA_SHM_END];
  7. netdata_publish_shm_t *shm_vector = NULL;
  8. static netdata_idx_t shm_hash_values[NETDATA_SHM_END];
  9. static netdata_idx_t *shm_values = NULL;
  10. struct config shm_config = { .first_section = NULL,
  11. .last_section = NULL,
  12. .mutex = NETDATA_MUTEX_INITIALIZER,
  13. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  14. .rwlock = AVL_LOCK_INITIALIZER } };
  15. static ebpf_local_maps_t shm_maps[] = {{.name = "tbl_pid_shm", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
  16. .user_input = 0,
  17. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  18. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  19. {.name = "shm_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  20. .user_input = 0,
  21. .type = NETDATA_EBPF_MAP_CONTROLLER,
  22. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  23. {.name = "tbl_shm", .internal_input = NETDATA_SHM_END,
  24. .user_input = 0,
  25. .type = NETDATA_EBPF_MAP_STATIC,
  26. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  27. {.name = NULL, .internal_input = 0, .user_input = 0}};
  28. netdata_ebpf_targets_t shm_targets[] = { {.name = "shmget", .mode = EBPF_LOAD_TRAMPOLINE},
  29. {.name = "shmat", .mode = EBPF_LOAD_TRAMPOLINE},
  30. {.name = "shmdt", .mode = EBPF_LOAD_TRAMPOLINE},
  31. {.name = "shmctl", .mode = EBPF_LOAD_TRAMPOLINE},
  32. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  33. #ifdef LIBBPF_MAJOR_VERSION
  34. /*****************************************************************
  35. *
  36. * BTF FUNCTIONS
  37. *
  38. *****************************************************************/
  39. /*
  40. * Disable tracepoint
  41. *
  42. * Disable all tracepoints to use exclusively another method.
  43. *
  44. * @param obj is the main structure for bpf objects.
  45. */
  46. static void ebpf_shm_disable_tracepoint(struct shm_bpf *obj)
  47. {
  48. bpf_program__set_autoload(obj->progs.netdata_syscall_shmget, false);
  49. bpf_program__set_autoload(obj->progs.netdata_syscall_shmat, false);
  50. bpf_program__set_autoload(obj->progs.netdata_syscall_shmdt, false);
  51. bpf_program__set_autoload(obj->progs.netdata_syscall_shmctl, false);
  52. }
  53. /*
  54. * Disable probe
  55. *
  56. * Disable all probes to use exclusively another method.
  57. *
  58. * @param obj is the main structure for bpf objects.
  59. */
  60. static void ebpf_disable_probe(struct shm_bpf *obj)
  61. {
  62. bpf_program__set_autoload(obj->progs.netdata_shmget_probe, false);
  63. bpf_program__set_autoload(obj->progs.netdata_shmat_probe, false);
  64. bpf_program__set_autoload(obj->progs.netdata_shmdt_probe, false);
  65. bpf_program__set_autoload(obj->progs.netdata_shmctl_probe, false);
  66. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_probe, false);
  67. }
  68. /*
  69. * Disable trampoline
  70. *
  71. * Disable all trampoline to use exclusively another method.
  72. *
  73. * @param obj is the main structure for bpf objects.
  74. */
  75. static void ebpf_disable_trampoline(struct shm_bpf *obj)
  76. {
  77. bpf_program__set_autoload(obj->progs.netdata_shmget_fentry, false);
  78. bpf_program__set_autoload(obj->progs.netdata_shmat_fentry, false);
  79. bpf_program__set_autoload(obj->progs.netdata_shmdt_fentry, false);
  80. bpf_program__set_autoload(obj->progs.netdata_shmctl_fentry, false);
  81. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_fentry, false);
  82. }
  83. /**
  84. * Set trampoline target
  85. *
  86. * Set the targets we will monitor.
  87. *
  88. * @param obj is the main structure for bpf objects.
  89. */
  90. static void ebpf_set_trampoline_target(struct shm_bpf *obj)
  91. {
  92. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
  93. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  94. shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
  95. bpf_program__set_attach_target(obj->progs.netdata_shmget_fentry, 0,
  96. syscall);
  97. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  98. shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
  99. bpf_program__set_attach_target(obj->progs.netdata_shmat_fentry, 0,
  100. syscall);
  101. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  102. shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
  103. bpf_program__set_attach_target(obj->progs.netdata_shmdt_fentry, 0,
  104. syscall);
  105. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  106. shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
  107. bpf_program__set_attach_target(obj->progs.netdata_shmctl_fentry, 0,
  108. syscall);
  109. bpf_program__set_attach_target(obj->progs.netdata_shm_release_task_fentry, 0,
  110. EBPF_COMMON_FNCT_CLEAN_UP);
  111. }
  112. /**
  113. * SHM Attach Probe
  114. *
  115. * Attach probes to target
  116. *
  117. * @param obj is the main structure for bpf objects.
  118. *
  119. * @return It returns 0 on success and -1 otherwise.
  120. */
  121. static int ebpf_shm_attach_probe(struct shm_bpf *obj)
  122. {
  123. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH + 1];
  124. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  125. shm_targets[NETDATA_KEY_SHMGET_CALL].name, running_on_kernel);
  126. obj->links.netdata_shmget_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmget_probe,
  127. false, syscall);
  128. int ret = (int)libbpf_get_error(obj->links.netdata_shmget_probe);
  129. if (ret)
  130. return -1;
  131. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  132. shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
  133. obj->links.netdata_shmat_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmat_probe,
  134. false, syscall);
  135. ret = (int)libbpf_get_error(obj->links.netdata_shmat_probe);
  136. if (ret)
  137. return -1;
  138. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  139. shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
  140. obj->links.netdata_shmdt_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmdt_probe,
  141. false, syscall);
  142. ret = (int)libbpf_get_error(obj->links.netdata_shmdt_probe);
  143. if (ret)
  144. return -1;
  145. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH,
  146. shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
  147. obj->links.netdata_shmctl_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmctl_probe,
  148. false, syscall);
  149. ret = (int)libbpf_get_error(obj->links.netdata_shmctl_probe);
  150. if (ret)
  151. return -1;
  152. obj->links.netdata_shm_release_task_probe = bpf_program__attach_kprobe(obj->progs.netdata_shm_release_task_probe,
  153. false, EBPF_COMMON_FNCT_CLEAN_UP);
  154. ret = (int)libbpf_get_error(obj->links.netdata_shm_release_task_probe);
  155. if (ret)
  156. return -1;
  157. return 0;
  158. }
  159. /**
  160. * Set hash tables
  161. *
  162. * Set the values for maps according the value given by kernel.
  163. */
  164. static void ebpf_shm_set_hash_tables(struct shm_bpf *obj)
  165. {
  166. shm_maps[NETDATA_PID_SHM_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_pid_shm);
  167. shm_maps[NETDATA_SHM_CONTROLLER].map_fd = bpf_map__fd(obj->maps.shm_ctrl);
  168. shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd = bpf_map__fd(obj->maps.tbl_shm);
  169. }
  170. /**
  171. * Disable Release Task
  172. *
  173. * Disable release task when apps is not enabled.
  174. *
  175. * @param obj is the main structure for bpf objects.
  176. */
  177. static void ebpf_shm_disable_release_task(struct shm_bpf *obj)
  178. {
  179. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_probe, false);
  180. bpf_program__set_autoload(obj->progs.netdata_shm_release_task_fentry, false);
  181. }
  182. /**
  183. * Adjust Map Size
  184. *
  185. * Resize maps according input from users.
  186. *
  187. * @param obj is the main structure for bpf objects.
  188. * @param em structure with configuration
  189. */
  190. static void ebpf_shm_adjust_map_size(struct shm_bpf *obj, ebpf_module_t *em)
  191. {
  192. ebpf_update_map_size(obj->maps.tbl_pid_shm, &shm_maps[NETDATA_PID_SHM_TABLE],
  193. em, bpf_map__name(obj->maps.tbl_pid_shm));
  194. }
  195. /**
  196. * Load and attach
  197. *
  198. * Load and attach the eBPF code in kernel.
  199. *
  200. * @param obj is the main structure for bpf objects.
  201. * @param em structure with configuration
  202. *
  203. * @return it returns 0 on success and -1 otherwise
  204. */
  205. static inline int ebpf_shm_load_and_attach(struct shm_bpf *obj, ebpf_module_t *em)
  206. {
  207. netdata_ebpf_targets_t *shmt = em->targets;
  208. netdata_ebpf_program_loaded_t test = shmt[NETDATA_KEY_SHMGET_CALL].mode;
  209. // We are testing only one, because all will have the same behavior
  210. if (test == EBPF_LOAD_TRAMPOLINE ) {
  211. ebpf_shm_disable_tracepoint(obj);
  212. ebpf_disable_probe(obj);
  213. ebpf_set_trampoline_target(obj);
  214. } else if (test == EBPF_LOAD_PROBE || test == EBPF_LOAD_RETPROBE ) {
  215. ebpf_shm_disable_tracepoint(obj);
  216. ebpf_disable_trampoline(obj);
  217. } else {
  218. ebpf_disable_probe(obj);
  219. ebpf_disable_trampoline(obj);
  220. }
  221. ebpf_shm_adjust_map_size(obj, em);
  222. if (!em->apps_charts && !em->cgroup_charts)
  223. ebpf_shm_disable_release_task(obj);
  224. int ret = shm_bpf__load(obj);
  225. if (!ret) {
  226. if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE)
  227. shm_bpf__attach(obj);
  228. else
  229. ret = ebpf_shm_attach_probe(obj);
  230. if (!ret)
  231. ebpf_shm_set_hash_tables(obj);
  232. }
  233. return ret;
  234. }
  235. #endif
  236. /*****************************************************************
  237. * FUNCTIONS TO CLOSE THE THREAD
  238. *****************************************************************/
  239. /**
  240. * SHM Free
  241. *
  242. * Cleanup variables after child threads to stop
  243. *
  244. * @param ptr thread data.
  245. */
  246. static void ebpf_shm_free(ebpf_module_t *em)
  247. {
  248. freez(shm_vector);
  249. freez(shm_values);
  250. pthread_mutex_lock(&ebpf_exit_cleanup);
  251. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  252. pthread_mutex_unlock(&ebpf_exit_cleanup);
  253. }
  254. /**
  255. * SHM Exit
  256. *
  257. * Cancel child thread.
  258. *
  259. * @param ptr thread data.
  260. */
  261. static void ebpf_shm_exit(void *ptr)
  262. {
  263. ebpf_module_t *em = (ebpf_module_t *)ptr;
  264. ebpf_shm_free(em);
  265. }
  266. /*****************************************************************
  267. * COLLECTOR THREAD
  268. *****************************************************************/
  269. /**
  270. * Apps Accumulator
  271. *
  272. * Sum all values read from kernel and store in the first address.
  273. *
  274. * @param out the vector with read values.
  275. */
  276. static void shm_apps_accumulator(netdata_publish_shm_t *out)
  277. {
  278. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  279. netdata_publish_shm_t *total = &out[0];
  280. for (i = 1; i < end; i++) {
  281. netdata_publish_shm_t *w = &out[i];
  282. total->get += w->get;
  283. total->at += w->at;
  284. total->dt += w->dt;
  285. total->ctl += w->ctl;
  286. }
  287. }
  288. /**
  289. * Fill PID
  290. *
  291. * Fill PID structures
  292. *
  293. * @param current_pid pid that we are collecting data
  294. * @param out values read from hash tables;
  295. */
  296. static void shm_fill_pid(uint32_t current_pid, netdata_publish_shm_t *publish)
  297. {
  298. netdata_publish_shm_t *curr = shm_pid[current_pid];
  299. if (!curr) {
  300. curr = ebpf_shm_stat_get( );
  301. shm_pid[current_pid] = curr;
  302. }
  303. memcpy(curr, publish, sizeof(netdata_publish_shm_t));
  304. }
  305. /**
  306. * Update cgroup
  307. *
  308. * Update cgroup data based in
  309. */
  310. static void ebpf_update_shm_cgroup()
  311. {
  312. netdata_publish_shm_t *cv = shm_vector;
  313. int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
  314. size_t length = sizeof(netdata_publish_shm_t) * ebpf_nprocs;
  315. ebpf_cgroup_target_t *ect;
  316. memset(cv, 0, length);
  317. pthread_mutex_lock(&mutex_cgroup_shm);
  318. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  319. struct pid_on_target2 *pids;
  320. for (pids = ect->pids; pids; pids = pids->next) {
  321. int pid = pids->pid;
  322. netdata_publish_shm_t *out = &pids->shm;
  323. if (likely(shm_pid) && shm_pid[pid]) {
  324. netdata_publish_shm_t *in = shm_pid[pid];
  325. memcpy(out, in, sizeof(netdata_publish_shm_t));
  326. } else {
  327. if (!bpf_map_lookup_elem(fd, &pid, cv)) {
  328. shm_apps_accumulator(cv);
  329. memcpy(out, cv, sizeof(netdata_publish_shm_t));
  330. // now that we've consumed the value, zero it out in the map.
  331. memset(cv, 0, length);
  332. bpf_map_update_elem(fd, &pid, cv, BPF_EXIST);
  333. }
  334. }
  335. }
  336. }
  337. pthread_mutex_unlock(&mutex_cgroup_shm);
  338. }
  339. /**
  340. * Read APPS table
  341. *
  342. * Read the apps table and store data inside the structure.
  343. */
  344. static void read_apps_table()
  345. {
  346. netdata_publish_shm_t *cv = shm_vector;
  347. uint32_t key;
  348. struct ebpf_pid_stat *pids = ebpf_root_of_pids;
  349. int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
  350. size_t length = sizeof(netdata_publish_shm_t)*ebpf_nprocs;
  351. while (pids) {
  352. key = pids->pid;
  353. if (bpf_map_lookup_elem(fd, &key, cv)) {
  354. pids = pids->next;
  355. continue;
  356. }
  357. shm_apps_accumulator(cv);
  358. shm_fill_pid(key, cv);
  359. // now that we've consumed the value, zero it out in the map.
  360. memset(cv, 0, length);
  361. bpf_map_update_elem(fd, &key, cv, BPF_EXIST);
  362. pids = pids->next;
  363. }
  364. }
  365. /**
  366. * Send global charts to netdata agent.
  367. */
  368. static void shm_send_global()
  369. {
  370. write_begin_chart(NETDATA_EBPF_SYSTEM_GROUP, NETDATA_SHM_GLOBAL_CHART);
  371. write_chart_dimension(
  372. shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL].dimension,
  373. (long long) shm_hash_values[NETDATA_KEY_SHMGET_CALL]
  374. );
  375. write_chart_dimension(
  376. shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL].dimension,
  377. (long long) shm_hash_values[NETDATA_KEY_SHMAT_CALL]
  378. );
  379. write_chart_dimension(
  380. shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL].dimension,
  381. (long long) shm_hash_values[NETDATA_KEY_SHMDT_CALL]
  382. );
  383. write_chart_dimension(
  384. shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL].dimension,
  385. (long long) shm_hash_values[NETDATA_KEY_SHMCTL_CALL]
  386. );
  387. write_end_chart();
  388. }
  389. /**
  390. * Read global counter
  391. *
  392. * Read the table with number of calls for all functions
  393. */
  394. static void ebpf_shm_read_global_table()
  395. {
  396. netdata_idx_t *stored = shm_values;
  397. netdata_idx_t *val = shm_hash_values;
  398. int fd = shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd;
  399. uint32_t i, end = NETDATA_SHM_END;
  400. for (i = NETDATA_KEY_SHMGET_CALL; i < end; i++) {
  401. if (!bpf_map_lookup_elem(fd, &i, stored)) {
  402. int j;
  403. int last = ebpf_nprocs;
  404. netdata_idx_t total = 0;
  405. for (j = 0; j < last; j++)
  406. total += stored[j];
  407. val[i] = total;
  408. }
  409. }
  410. }
  411. /**
  412. * Sum values for all targets.
  413. */
  414. static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct ebpf_pid_on_target *root)
  415. {
  416. while (root) {
  417. int32_t pid = root->pid;
  418. netdata_publish_shm_t *w = shm_pid[pid];
  419. if (w) {
  420. shm->get += w->get;
  421. shm->at += w->at;
  422. shm->dt += w->dt;
  423. shm->ctl += w->ctl;
  424. // reset for next collection.
  425. w->get = 0;
  426. w->at = 0;
  427. w->dt = 0;
  428. w->ctl = 0;
  429. }
  430. root = root->next;
  431. }
  432. }
  433. /**
  434. * Send data to Netdata calling auxiliary functions.
  435. *
  436. * @param root the target list.
  437. */
  438. void ebpf_shm_send_apps_data(struct ebpf_target *root)
  439. {
  440. struct ebpf_target *w;
  441. for (w = root; w; w = w->next) {
  442. if (unlikely(w->exposed && w->processes)) {
  443. ebpf_shm_sum_pids(&w->shm, w->root_pid);
  444. }
  445. }
  446. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMGET_CHART);
  447. for (w = root; w; w = w->next) {
  448. if (unlikely(w->exposed && w->processes)) {
  449. write_chart_dimension(w->name, (long long) w->shm.get);
  450. }
  451. }
  452. write_end_chart();
  453. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMAT_CHART);
  454. for (w = root; w; w = w->next) {
  455. if (unlikely(w->exposed && w->processes)) {
  456. write_chart_dimension(w->name, (long long) w->shm.at);
  457. }
  458. }
  459. write_end_chart();
  460. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMDT_CHART);
  461. for (w = root; w; w = w->next) {
  462. if (unlikely(w->exposed && w->processes)) {
  463. write_chart_dimension(w->name, (long long) w->shm.dt);
  464. }
  465. }
  466. write_end_chart();
  467. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMCTL_CHART);
  468. for (w = root; w; w = w->next) {
  469. if (unlikely(w->exposed && w->processes)) {
  470. write_chart_dimension(w->name, (long long) w->shm.ctl);
  471. }
  472. }
  473. write_end_chart();
  474. }
  475. /**
  476. * Sum values for all targets.
  477. */
  478. static void ebpf_shm_sum_cgroup_pids(netdata_publish_shm_t *shm, struct pid_on_target2 *root)
  479. {
  480. netdata_publish_shm_t shmv;
  481. memset(&shmv, 0, sizeof(shmv));
  482. while (root) {
  483. netdata_publish_shm_t *w = &root->shm;
  484. shmv.get += w->get;
  485. shmv.at += w->at;
  486. shmv.dt += w->dt;
  487. shmv.ctl += w->ctl;
  488. root = root->next;
  489. }
  490. memcpy(shm, &shmv, sizeof(shmv));
  491. }
  492. /**
  493. * Create specific shared memory charts
  494. *
  495. * Create charts for cgroup/application.
  496. *
  497. * @param type the chart type.
  498. * @param update_every value to overwrite the update frequency set by the server.
  499. */
  500. static void ebpf_create_specific_shm_charts(char *type, int update_every)
  501. {
  502. ebpf_create_chart(type, NETDATA_SHMGET_CHART,
  503. "Calls to syscall <code>shmget(2)</code>.",
  504. EBPF_COMMON_DIMENSION_CALL,
  505. NETDATA_APPS_IPC_SHM_GROUP,
  506. NETDATA_CGROUP_SHM_GET_CONTEXT,
  507. NETDATA_EBPF_CHART_TYPE_LINE,
  508. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5800,
  509. ebpf_create_global_dimension,
  510. &shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL],
  511. 1,
  512. update_every,
  513. NETDATA_EBPF_MODULE_NAME_SHM);
  514. ebpf_create_chart(type, NETDATA_SHMAT_CHART,
  515. "Calls to syscall <code>shmat(2)</code>.",
  516. EBPF_COMMON_DIMENSION_CALL,
  517. NETDATA_APPS_IPC_SHM_GROUP,
  518. NETDATA_CGROUP_SHM_AT_CONTEXT,
  519. NETDATA_EBPF_CHART_TYPE_LINE,
  520. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5801,
  521. ebpf_create_global_dimension,
  522. &shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL],
  523. 1,
  524. update_every,
  525. NETDATA_EBPF_MODULE_NAME_SHM);
  526. ebpf_create_chart(type, NETDATA_SHMDT_CHART,
  527. "Calls to syscall <code>shmdt(2)</code>.",
  528. EBPF_COMMON_DIMENSION_CALL,
  529. NETDATA_APPS_IPC_SHM_GROUP,
  530. NETDATA_CGROUP_SHM_DT_CONTEXT,
  531. NETDATA_EBPF_CHART_TYPE_LINE,
  532. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5802,
  533. ebpf_create_global_dimension,
  534. &shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL],
  535. 1,
  536. update_every,
  537. NETDATA_EBPF_MODULE_NAME_SHM);
  538. ebpf_create_chart(type, NETDATA_SHMCTL_CHART,
  539. "Calls to syscall <code>shmctl(2)</code>.",
  540. EBPF_COMMON_DIMENSION_CALL,
  541. NETDATA_APPS_IPC_SHM_GROUP,
  542. NETDATA_CGROUP_SHM_CTL_CONTEXT,
  543. NETDATA_EBPF_CHART_TYPE_LINE,
  544. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5803,
  545. ebpf_create_global_dimension,
  546. &shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL],
  547. 1,
  548. update_every,
  549. NETDATA_EBPF_MODULE_NAME_SHM);
  550. }
  551. /**
  552. * Obsolete specific shared memory charts
  553. *
  554. * Obsolete charts for cgroup/application.
  555. *
  556. * @param type the chart type.
  557. * @param update_every value to overwrite the update frequency set by the server.
  558. */
  559. static void ebpf_obsolete_specific_shm_charts(char *type, int update_every)
  560. {
  561. ebpf_write_chart_obsolete(type, NETDATA_SHMGET_CHART,
  562. "Calls to syscall <code>shmget(2)</code>.",
  563. EBPF_COMMON_DIMENSION_CALL,
  564. NETDATA_APPS_IPC_SHM_GROUP,
  565. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_GET_CONTEXT,
  566. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5800, update_every);
  567. ebpf_write_chart_obsolete(type, NETDATA_SHMAT_CHART,
  568. "Calls to syscall <code>shmat(2)</code>.",
  569. EBPF_COMMON_DIMENSION_CALL,
  570. NETDATA_APPS_IPC_SHM_GROUP,
  571. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_AT_CONTEXT,
  572. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5801, update_every);
  573. ebpf_write_chart_obsolete(type, NETDATA_SHMDT_CHART,
  574. "Calls to syscall <code>shmdt(2)</code>.",
  575. EBPF_COMMON_DIMENSION_CALL,
  576. NETDATA_APPS_IPC_SHM_GROUP,
  577. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_DT_CONTEXT,
  578. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5802, update_every);
  579. ebpf_write_chart_obsolete(type, NETDATA_SHMCTL_CHART,
  580. "Calls to syscall <code>shmctl(2)</code>.",
  581. EBPF_COMMON_DIMENSION_CALL,
  582. NETDATA_APPS_IPC_SHM_GROUP,
  583. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_CGROUP_SHM_CTL_CONTEXT,
  584. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5803, update_every);
  585. }
  586. /**
  587. * Create Systemd Swap Charts
  588. *
  589. * Create charts when systemd is enabled
  590. *
  591. * @param update_every value to overwrite the update frequency set by the server.
  592. **/
  593. static void ebpf_create_systemd_shm_charts(int update_every)
  594. {
  595. ebpf_create_charts_on_systemd(NETDATA_SHMGET_CHART,
  596. "Calls to syscall <code>shmget(2)</code>.",
  597. EBPF_COMMON_DIMENSION_CALL,
  598. NETDATA_APPS_IPC_SHM_GROUP,
  599. NETDATA_EBPF_CHART_TYPE_STACKED,
  600. 20191,
  601. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  602. NETDATA_SYSTEMD_SHM_GET_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  603. ebpf_create_charts_on_systemd(NETDATA_SHMAT_CHART,
  604. "Calls to syscall <code>shmat(2)</code>.",
  605. EBPF_COMMON_DIMENSION_CALL,
  606. NETDATA_APPS_IPC_SHM_GROUP,
  607. NETDATA_EBPF_CHART_TYPE_STACKED,
  608. 20192,
  609. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  610. NETDATA_SYSTEMD_SHM_AT_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  611. ebpf_create_charts_on_systemd(NETDATA_SHMDT_CHART,
  612. "Calls to syscall <code>shmdt(2)</code>.",
  613. EBPF_COMMON_DIMENSION_CALL,
  614. NETDATA_APPS_IPC_SHM_GROUP,
  615. NETDATA_EBPF_CHART_TYPE_STACKED,
  616. 20193,
  617. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  618. NETDATA_SYSTEMD_SHM_DT_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  619. ebpf_create_charts_on_systemd(NETDATA_SHMCTL_CHART,
  620. "Calls to syscall <code>shmctl(2)</code>.",
  621. EBPF_COMMON_DIMENSION_CALL,
  622. NETDATA_APPS_IPC_SHM_GROUP,
  623. NETDATA_EBPF_CHART_TYPE_STACKED,
  624. 20193,
  625. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  626. NETDATA_SYSTEMD_SHM_CTL_CONTEXT, NETDATA_EBPF_MODULE_NAME_SHM, update_every);
  627. }
  628. /**
  629. * Send Systemd charts
  630. *
  631. * Send collected data to Netdata.
  632. */
  633. static void ebpf_send_systemd_shm_charts()
  634. {
  635. ebpf_cgroup_target_t *ect;
  636. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMGET_CHART);
  637. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  638. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  639. write_chart_dimension(ect->name, (long long)ect->publish_shm.get);
  640. }
  641. }
  642. write_end_chart();
  643. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMAT_CHART);
  644. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  645. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  646. write_chart_dimension(ect->name, (long long)ect->publish_shm.at);
  647. }
  648. }
  649. write_end_chart();
  650. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMDT_CHART);
  651. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  652. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  653. write_chart_dimension(ect->name, (long long)ect->publish_shm.dt);
  654. }
  655. }
  656. write_end_chart();
  657. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_SHMCTL_CHART);
  658. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  659. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  660. write_chart_dimension(ect->name, (long long)ect->publish_shm.ctl);
  661. }
  662. }
  663. write_end_chart();
  664. }
  665. /*
  666. * Send Specific Shared memory data
  667. *
  668. * Send data for specific cgroup/apps.
  669. *
  670. * @param type chart type
  671. * @param values structure with values that will be sent to netdata
  672. */
  673. static void ebpf_send_specific_shm_data(char *type, netdata_publish_shm_t *values)
  674. {
  675. write_begin_chart(type, NETDATA_SHMGET_CHART);
  676. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL].name, (long long)values->get);
  677. write_end_chart();
  678. write_begin_chart(type, NETDATA_SHMAT_CHART);
  679. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL].name, (long long)values->at);
  680. write_end_chart();
  681. write_begin_chart(type, NETDATA_SHMDT_CHART);
  682. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL].name, (long long)values->dt);
  683. write_end_chart();
  684. write_begin_chart(type, NETDATA_SHMCTL_CHART);
  685. write_chart_dimension(shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL].name, (long long)values->ctl);
  686. write_end_chart();
  687. }
  688. /**
  689. * Send data to Netdata calling auxiliary functions.
  690. *
  691. * @param update_every value to overwrite the update frequency set by the server.
  692. */
  693. void ebpf_shm_send_cgroup_data(int update_every)
  694. {
  695. if (!ebpf_cgroup_pids)
  696. return;
  697. pthread_mutex_lock(&mutex_cgroup_shm);
  698. ebpf_cgroup_target_t *ect;
  699. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  700. ebpf_shm_sum_cgroup_pids(&ect->publish_shm, ect->pids);
  701. }
  702. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  703. if (has_systemd) {
  704. if (send_cgroup_chart) {
  705. ebpf_create_systemd_shm_charts(update_every);
  706. }
  707. ebpf_send_systemd_shm_charts();
  708. }
  709. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  710. if (ect->systemd)
  711. continue;
  712. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_SHM_CHART) && ect->updated) {
  713. ebpf_create_specific_shm_charts(ect->name, update_every);
  714. ect->flags |= NETDATA_EBPF_CGROUP_HAS_SHM_CHART;
  715. }
  716. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_SHM_CHART) {
  717. if (ect->updated) {
  718. ebpf_send_specific_shm_data(ect->name, &ect->publish_shm);
  719. } else {
  720. ebpf_obsolete_specific_shm_charts(ect->name, update_every);
  721. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_SWAP_CHART;
  722. }
  723. }
  724. }
  725. pthread_mutex_unlock(&mutex_cgroup_shm);
  726. }
  727. /**
  728. * Main loop for this collector.
  729. */
  730. static void shm_collector(ebpf_module_t *em)
  731. {
  732. int cgroups = em->cgroup_charts;
  733. int update_every = em->update_every;
  734. heartbeat_t hb;
  735. heartbeat_init(&hb);
  736. int counter = update_every - 1;
  737. while (!ebpf_exit_plugin) {
  738. (void)heartbeat_next(&hb, USEC_PER_SEC);
  739. if (ebpf_exit_plugin || ++counter != update_every)
  740. continue;
  741. counter = 0;
  742. netdata_apps_integration_flags_t apps = em->apps_charts;
  743. ebpf_shm_read_global_table();
  744. pthread_mutex_lock(&collect_data_mutex);
  745. if (apps) {
  746. read_apps_table();
  747. }
  748. if (cgroups) {
  749. ebpf_update_shm_cgroup();
  750. }
  751. pthread_mutex_lock(&lock);
  752. shm_send_global();
  753. if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
  754. ebpf_shm_send_apps_data(apps_groups_root_target);
  755. }
  756. #ifdef NETDATA_DEV_MODE
  757. if (ebpf_aral_shm_pid)
  758. ebpf_send_data_aral_chart(ebpf_aral_shm_pid, em);
  759. #endif
  760. if (cgroups) {
  761. ebpf_shm_send_cgroup_data(update_every);
  762. }
  763. pthread_mutex_unlock(&lock);
  764. pthread_mutex_unlock(&collect_data_mutex);
  765. }
  766. }
  767. /*****************************************************************
  768. * INITIALIZE THREAD
  769. *****************************************************************/
  770. /**
  771. * Create apps charts
  772. *
  773. * Call ebpf_create_chart to create the charts on apps submenu.
  774. *
  775. * @param em a pointer to the structure with the default values.
  776. */
  777. void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr)
  778. {
  779. struct ebpf_target *root = ptr;
  780. ebpf_create_charts_on_apps(NETDATA_SHMGET_CHART,
  781. "Calls to syscall <code>shmget(2)</code>.",
  782. EBPF_COMMON_DIMENSION_CALL,
  783. NETDATA_APPS_IPC_SHM_GROUP,
  784. NETDATA_EBPF_CHART_TYPE_STACKED,
  785. 20191,
  786. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  787. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  788. ebpf_create_charts_on_apps(NETDATA_SHMAT_CHART,
  789. "Calls to syscall <code>shmat(2)</code>.",
  790. EBPF_COMMON_DIMENSION_CALL,
  791. NETDATA_APPS_IPC_SHM_GROUP,
  792. NETDATA_EBPF_CHART_TYPE_STACKED,
  793. 20192,
  794. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  795. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  796. ebpf_create_charts_on_apps(NETDATA_SHMDT_CHART,
  797. "Calls to syscall <code>shmdt(2)</code>.",
  798. EBPF_COMMON_DIMENSION_CALL,
  799. NETDATA_APPS_IPC_SHM_GROUP,
  800. NETDATA_EBPF_CHART_TYPE_STACKED,
  801. 20193,
  802. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  803. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  804. ebpf_create_charts_on_apps(NETDATA_SHMCTL_CHART,
  805. "Calls to syscall <code>shmctl(2)</code>.",
  806. EBPF_COMMON_DIMENSION_CALL,
  807. NETDATA_APPS_IPC_SHM_GROUP,
  808. NETDATA_EBPF_CHART_TYPE_STACKED,
  809. 20194,
  810. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  811. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SHM);
  812. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  813. }
  814. /**
  815. * Allocate vectors used with this thread.
  816. *
  817. * We are not testing the return, because callocz does this and shutdown the software
  818. * case it was not possible to allocate.
  819. *
  820. * @param apps is apps enabled?
  821. */
  822. static void ebpf_shm_allocate_global_vectors(int apps)
  823. {
  824. if (apps) {
  825. ebpf_shm_aral_init();
  826. shm_pid = callocz((size_t)pid_max, sizeof(netdata_publish_shm_t *));
  827. shm_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_shm_t));
  828. }
  829. shm_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
  830. memset(shm_hash_values, 0, sizeof(shm_hash_values));
  831. }
  832. /*****************************************************************
  833. * MAIN THREAD
  834. *****************************************************************/
  835. /**
  836. * Create global charts
  837. *
  838. * Call ebpf_create_chart to create the charts for the collector.
  839. *
  840. * @param update_every value to overwrite the update frequency set by the server.
  841. */
  842. static void ebpf_create_shm_charts(int update_every)
  843. {
  844. ebpf_create_chart(
  845. NETDATA_EBPF_SYSTEM_GROUP,
  846. NETDATA_SHM_GLOBAL_CHART,
  847. "Calls to shared memory system calls",
  848. EBPF_COMMON_DIMENSION_CALL,
  849. NETDATA_SYSTEM_IPC_SHM_SUBMENU,
  850. NULL,
  851. NETDATA_EBPF_CHART_TYPE_LINE,
  852. NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_CALLS,
  853. ebpf_create_global_dimension,
  854. shm_publish_aggregated,
  855. NETDATA_SHM_END,
  856. update_every, NETDATA_EBPF_MODULE_NAME_SHM
  857. );
  858. fflush(stdout);
  859. }
  860. /*
  861. * Load BPF
  862. *
  863. * Load BPF files.
  864. *
  865. * @param em the structure with configuration
  866. */
  867. static int ebpf_shm_load_bpf(ebpf_module_t *em)
  868. {
  869. int ret = 0;
  870. ebpf_adjust_apps_cgroup(em, em->targets[NETDATA_KEY_SHMGET_CALL].mode);
  871. if (em->load & EBPF_LOAD_LEGACY) {
  872. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  873. if (!em->probe_links) {
  874. ret = -1;
  875. }
  876. }
  877. #ifdef LIBBPF_MAJOR_VERSION
  878. else {
  879. shm_bpf_obj = shm_bpf__open();
  880. if (!shm_bpf_obj)
  881. ret = -1;
  882. else
  883. ret = ebpf_shm_load_and_attach(shm_bpf_obj, em);
  884. }
  885. #endif
  886. if (ret)
  887. error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
  888. return ret;
  889. }
  890. /**
  891. * Shared memory thread.
  892. *
  893. * @param ptr a pointer to `struct ebpf_module`
  894. * @return It always return NULL
  895. */
  896. void *ebpf_shm_thread(void *ptr)
  897. {
  898. netdata_thread_cleanup_push(ebpf_shm_exit, ptr);
  899. ebpf_module_t *em = (ebpf_module_t *)ptr;
  900. em->maps = shm_maps;
  901. ebpf_update_pid_table(&shm_maps[NETDATA_PID_SHM_TABLE], em);
  902. #ifdef LIBBPF_MAJOR_VERSION
  903. ebpf_adjust_thread_load(em, default_btf);
  904. #endif
  905. if (ebpf_shm_load_bpf(em)) {
  906. goto endshm;
  907. }
  908. ebpf_shm_allocate_global_vectors(em->apps_charts);
  909. int algorithms[NETDATA_SHM_END] = {
  910. NETDATA_EBPF_INCREMENTAL_IDX,
  911. NETDATA_EBPF_INCREMENTAL_IDX,
  912. NETDATA_EBPF_INCREMENTAL_IDX,
  913. NETDATA_EBPF_INCREMENTAL_IDX
  914. };
  915. ebpf_global_labels(
  916. shm_aggregated_data,
  917. shm_publish_aggregated,
  918. shm_dimension_name,
  919. shm_dimension_name,
  920. algorithms,
  921. NETDATA_SHM_END
  922. );
  923. pthread_mutex_lock(&lock);
  924. ebpf_create_shm_charts(em->update_every);
  925. ebpf_update_stats(&plugin_statistics, em);
  926. ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
  927. #ifdef NETDATA_DEV_MODE
  928. if (ebpf_aral_shm_pid)
  929. ebpf_statistic_create_aral_chart(NETDATA_EBPF_SHM_ARAL_NAME, em);
  930. #endif
  931. pthread_mutex_unlock(&lock);
  932. shm_collector(em);
  933. endshm:
  934. ebpf_update_disabled_plugin_stats(em);
  935. netdata_thread_cleanup_pop(1);
  936. return NULL;
  937. }