ebpf_shm.c 36 KB

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