ebpf_shm.c 36 KB

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