ebpf.c 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include <sys/time.h>
  3. #include <sys/resource.h>
  4. #include <ifaddrs.h>
  5. #include "ebpf.h"
  6. #include "ebpf_socket.h"
  7. #include "libnetdata/required_dummies.h"
  8. /*****************************************************************
  9. *
  10. * GLOBAL VARIABLES
  11. *
  12. *****************************************************************/
  13. char *ebpf_plugin_dir = PLUGINS_DIR;
  14. static char *ebpf_configured_log_dir = LOG_DIR;
  15. char *ebpf_algorithms[] = {"absolute", "incremental"};
  16. struct config collector_config = { .first_section = NULL,
  17. .last_section = NULL,
  18. .mutex = NETDATA_MUTEX_INITIALIZER,
  19. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  20. .rwlock = AVL_LOCK_INITIALIZER } };
  21. int running_on_kernel = 0;
  22. int ebpf_nprocs;
  23. int isrh = 0;
  24. pthread_mutex_t lock;
  25. pthread_mutex_t collect_data_mutex;
  26. pthread_cond_t collect_data_cond_var;
  27. ebpf_module_t ebpf_modules[] = {
  28. { .thread_name = "process", .config_name = "process", .enabled = 0, .start_routine = ebpf_process_thread,
  29. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  30. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  31. .apps_routine = ebpf_process_create_apps_charts, .maps = NULL,
  32. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &process_config,
  33. .config_file = NETDATA_PROCESS_CONFIG_FILE,
  34. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10,
  35. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  36. { .thread_name = "socket", .config_name = "socket", .enabled = 0, .start_routine = ebpf_socket_thread,
  37. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  38. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  39. .apps_routine = ebpf_socket_create_apps_charts, .maps = NULL,
  40. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &socket_config,
  41. .config_file = NETDATA_NETWORK_CONFIG_FILE,
  42. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  43. .load = EBPF_LOAD_LEGACY, .targets = socket_targets, .probe_links = NULL, .objects = NULL},
  44. { .thread_name = "cachestat", .config_name = "cachestat", .enabled = 0, .start_routine = ebpf_cachestat_thread,
  45. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  46. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  47. .apps_routine = ebpf_cachestat_create_apps_charts, .maps = NULL,
  48. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &cachestat_config,
  49. .config_file = NETDATA_CACHESTAT_CONFIG_FILE,
  50. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18| NETDATA_V5_4 | NETDATA_V5_15 |
  51. NETDATA_V5_16,
  52. .load = EBPF_LOAD_LEGACY, .targets = cachestat_targets, .probe_links = NULL, .objects = NULL},
  53. { .thread_name = "sync", .config_name = "sync", .enabled = 0, .start_routine = ebpf_sync_thread,
  54. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  55. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  56. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &sync_config,
  57. .config_file = NETDATA_SYNC_CONFIG_FILE,
  58. // All syscalls have the same kernels
  59. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  60. .load = EBPF_LOAD_LEGACY, .targets = sync_targets, .probe_links = NULL, .objects = NULL},
  61. { .thread_name = "dc", .config_name = "dc", .enabled = 0, .start_routine = ebpf_dcstat_thread,
  62. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  63. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  64. .apps_routine = ebpf_dcstat_create_apps_charts, .maps = NULL,
  65. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &dcstat_config,
  66. .config_file = NETDATA_DIRECTORY_DCSTAT_CONFIG_FILE,
  67. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  68. .load = EBPF_LOAD_LEGACY, .targets = dc_targets, .probe_links = NULL, .objects = NULL},
  69. { .thread_name = "swap", .config_name = "swap", .enabled = 0, .start_routine = ebpf_swap_thread,
  70. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  71. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  72. .apps_routine = ebpf_swap_create_apps_charts, .maps = NULL,
  73. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &swap_config,
  74. .config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE,
  75. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  76. .load = EBPF_LOAD_LEGACY, .targets = swap_targets, .probe_links = NULL, .objects = NULL},
  77. { .thread_name = "vfs", .config_name = "vfs", .enabled = 0, .start_routine = ebpf_vfs_thread,
  78. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  79. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  80. .apps_routine = ebpf_vfs_create_apps_charts, .maps = NULL,
  81. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &vfs_config,
  82. .config_file = NETDATA_DIRECTORY_VFS_CONFIG_FILE,
  83. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  84. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  85. { .thread_name = "filesystem", .config_name = "filesystem", .enabled = 0, .start_routine = ebpf_filesystem_thread,
  86. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  87. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  88. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
  89. .config_file = NETDATA_FILESYSTEM_CONFIG_FILE,
  90. //We are setting kernels as zero, because we load eBPF programs according the kernel running.
  91. .kernels = 0, .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL },
  92. { .thread_name = "disk", .config_name = "disk", .enabled = 0, .start_routine = ebpf_disk_thread,
  93. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  94. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  95. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
  96. .config_file = NETDATA_DISK_CONFIG_FILE,
  97. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  98. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  99. { .thread_name = "mount", .config_name = "mount", .enabled = 0, .start_routine = ebpf_mount_thread,
  100. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  101. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  102. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
  103. .config_file = NETDATA_MOUNT_CONFIG_FILE,
  104. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  105. .load = EBPF_LOAD_LEGACY, .targets = mount_targets, .probe_links = NULL, .objects = NULL},
  106. { .thread_name = "fd", .config_name = "fd", .enabled = 0, .start_routine = ebpf_fd_thread,
  107. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  108. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  109. .apps_routine = ebpf_fd_create_apps_charts, .maps = NULL,
  110. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fd_config,
  111. .config_file = NETDATA_FD_CONFIG_FILE,
  112. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11,
  113. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  114. { .thread_name = "hardirq", .config_name = "hardirq", .enabled = 0, .start_routine = ebpf_hardirq_thread,
  115. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  116. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  117. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &hardirq_config,
  118. .config_file = NETDATA_HARDIRQ_CONFIG_FILE,
  119. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  120. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  121. { .thread_name = "softirq", .config_name = "softirq", .enabled = 0, .start_routine = ebpf_softirq_thread,
  122. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  123. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  124. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &softirq_config,
  125. .config_file = NETDATA_SOFTIRQ_CONFIG_FILE,
  126. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  127. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  128. { .thread_name = "oomkill", .config_name = "oomkill", .enabled = 0, .start_routine = ebpf_oomkill_thread,
  129. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  130. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  131. .apps_routine = ebpf_oomkill_create_apps_charts, .maps = NULL,
  132. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &oomkill_config,
  133. .config_file = NETDATA_OOMKILL_CONFIG_FILE,
  134. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  135. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  136. { .thread_name = "shm", .config_name = "shm", .enabled = 0, .start_routine = ebpf_shm_thread,
  137. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  138. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  139. .apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
  140. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
  141. .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
  142. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  143. .load = EBPF_LOAD_LEGACY, .targets = shm_targets, .probe_links = NULL, .objects = NULL},
  144. { .thread_name = "mdflush", .config_name = "mdflush", .enabled = 0, .start_routine = ebpf_mdflush_thread,
  145. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  146. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
  147. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
  148. .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE,
  149. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  150. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL},
  151. { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
  152. .global_charts = 0, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO, .cgroup_charts = CONFIG_BOOLEAN_NO,
  153. .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL, .pid_map_size = 0, .names = NULL,
  154. .cfg = NULL, .config_name = NULL, .kernels = 0, .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL,
  155. .objects = NULL},
  156. };
  157. struct netdata_static_thread ebpf_threads[] = {
  158. {"EBPF PROCESS", NULL, NULL, 1,
  159. NULL, NULL, NULL},
  160. {"EBPF SOCKET" , NULL, NULL, 1,
  161. NULL, NULL, NULL},
  162. {"EBPF CACHESTAT" , NULL, NULL, 1,
  163. NULL, NULL, NULL},
  164. {"EBPF SYNC" , NULL, NULL, 1,
  165. NULL, NULL, NULL},
  166. {"EBPF DCSTAT" , NULL, NULL, 1,
  167. NULL, NULL, NULL},
  168. {"EBPF SWAP" , NULL, NULL, 1,
  169. NULL, NULL, NULL},
  170. {"EBPF VFS" , NULL, NULL, 1,
  171. NULL, NULL, NULL},
  172. {"EBPF FILESYSTEM" , NULL, NULL, 1,
  173. NULL, NULL, NULL},
  174. {"EBPF DISK" , NULL, NULL, 1,
  175. NULL, NULL, NULL},
  176. {"EBPF MOUNT" , NULL, NULL, 1,
  177. NULL, NULL, NULL},
  178. {"EBPF FD" , NULL, NULL, 1,
  179. NULL, NULL, NULL},
  180. {"EBPF HARDIRQ" , NULL, NULL, 1,
  181. NULL, NULL, NULL},
  182. {"EBPF SOFTIRQ" , NULL, NULL, 1,
  183. NULL, NULL, NULL},
  184. {"EBPF OOMKILL" , NULL, NULL, 1,
  185. NULL, NULL, NULL},
  186. {"EBPF SHM" , NULL, NULL, 1,
  187. NULL, NULL, NULL},
  188. {"EBPF MDFLUSH" , NULL, NULL, 1,
  189. NULL, NULL, NULL},
  190. {NULL , NULL, NULL, 0,
  191. NULL, NULL, NULL}
  192. };
  193. ebpf_filesystem_partitions_t localfs[] =
  194. {{.filesystem = "ext4",
  195. .optional_filesystem = NULL,
  196. .family = "ext4",
  197. .objects = NULL,
  198. .probe_links = NULL,
  199. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  200. .enabled = CONFIG_BOOLEAN_YES,
  201. .addresses = {.function = NULL, .addr = 0},
  202. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4},
  203. {.filesystem = "xfs",
  204. .optional_filesystem = NULL,
  205. .family = "xfs",
  206. .objects = NULL,
  207. .probe_links = NULL,
  208. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  209. .enabled = CONFIG_BOOLEAN_YES,
  210. .addresses = {.function = NULL, .addr = 0},
  211. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4},
  212. {.filesystem = "nfs",
  213. .optional_filesystem = "nfs4",
  214. .family = "nfs",
  215. .objects = NULL,
  216. .probe_links = NULL,
  217. .flags = NETDATA_FILESYSTEM_ATTR_CHARTS,
  218. .enabled = CONFIG_BOOLEAN_YES,
  219. .addresses = {.function = NULL, .addr = 0},
  220. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4},
  221. {.filesystem = "zfs",
  222. .optional_filesystem = NULL,
  223. .family = "zfs",
  224. .objects = NULL,
  225. .probe_links = NULL,
  226. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  227. .enabled = CONFIG_BOOLEAN_YES,
  228. .addresses = {.function = NULL, .addr = 0},
  229. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4},
  230. {.filesystem = "btrfs",
  231. .optional_filesystem = NULL,
  232. .family = "btrfs",
  233. .objects = NULL,
  234. .probe_links = NULL,
  235. .flags = NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE,
  236. .enabled = CONFIG_BOOLEAN_YES,
  237. .addresses = {.function = "btrfs_file_operations", .addr = 0},
  238. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10},
  239. {.filesystem = NULL,
  240. .optional_filesystem = NULL,
  241. .family = NULL,
  242. .objects = NULL,
  243. .probe_links = NULL,
  244. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  245. .enabled = CONFIG_BOOLEAN_YES,
  246. .addresses = {.function = NULL, .addr = 0},
  247. .kernels = 0}};
  248. ebpf_sync_syscalls_t local_syscalls[] = {
  249. {.syscall = NETDATA_SYSCALLS_SYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  250. #ifdef LIBBPF_MAJOR_VERSION
  251. .sync_obj = NULL
  252. #endif
  253. },
  254. {.syscall = NETDATA_SYSCALLS_SYNCFS, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  255. #ifdef LIBBPF_MAJOR_VERSION
  256. .sync_obj = NULL
  257. #endif
  258. },
  259. {.syscall = NETDATA_SYSCALLS_MSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  260. #ifdef LIBBPF_MAJOR_VERSION
  261. .sync_obj = NULL
  262. #endif
  263. },
  264. {.syscall = NETDATA_SYSCALLS_FSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  265. #ifdef LIBBPF_MAJOR_VERSION
  266. .sync_obj = NULL
  267. #endif
  268. },
  269. {.syscall = NETDATA_SYSCALLS_FDATASYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  270. #ifdef LIBBPF_MAJOR_VERSION
  271. .sync_obj = NULL
  272. #endif
  273. },
  274. {.syscall = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  275. #ifdef LIBBPF_MAJOR_VERSION
  276. .sync_obj = NULL
  277. #endif
  278. },
  279. {.syscall = NULL, .enabled = CONFIG_BOOLEAN_NO, .objects = NULL, .probe_links = NULL,
  280. #ifdef LIBBPF_MAJOR_VERSION
  281. .sync_obj = NULL
  282. #endif
  283. }
  284. };
  285. // Link with apps.plugin
  286. ebpf_process_stat_t *global_process_stat = NULL;
  287. // Link with cgroup.plugin
  288. netdata_ebpf_cgroup_shm_t shm_ebpf_cgroup = {NULL, NULL};
  289. int shm_fd_ebpf_cgroup = -1;
  290. sem_t *shm_sem_ebpf_cgroup = SEM_FAILED;
  291. pthread_mutex_t mutex_cgroup_shm;
  292. //Network viewer
  293. ebpf_network_viewer_options_t network_viewer_opt;
  294. // Statistic
  295. ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, .threads = 0, .tracepoints = 0,
  296. .probes = 0, .retprobes = 0, .trampolines = 0};
  297. #ifdef LIBBPF_MAJOR_VERSION
  298. struct btf *default_btf = NULL;
  299. #endif
  300. char *btf_path = NULL;
  301. /*****************************************************************
  302. *
  303. * FUNCTIONS USED TO CLEAN MEMORY AND OPERATE SYSTEM FILES
  304. *
  305. *****************************************************************/
  306. /**
  307. * Close the collector gracefully
  308. *
  309. * @param sig is the signal number used to close the collector
  310. */
  311. static void ebpf_exit(int sig)
  312. {
  313. #ifdef LIBBPF_MAJOR_VERSION
  314. if (default_btf) {
  315. btf__free(default_btf);
  316. default_btf = NULL;
  317. }
  318. #endif
  319. char filename[FILENAME_MAX + 1];
  320. ebpf_pid_file(filename, FILENAME_MAX);
  321. if (unlink(filename))
  322. error("Cannot remove PID file %s", filename);
  323. exit(sig);
  324. }
  325. /**
  326. * Unload loegacy code
  327. *
  328. * @param objects objects loaded from eBPF programs
  329. * @param probe_links links from loader
  330. */
  331. static void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links)
  332. {
  333. if (!probe_links || !objects)
  334. return;
  335. struct bpf_program *prog;
  336. size_t j = 0 ;
  337. bpf_object__for_each_program(prog, objects) {
  338. bpf_link__destroy(probe_links[j]);
  339. j++;
  340. }
  341. freez(probe_links);
  342. if (objects)
  343. bpf_object__close(objects);
  344. }
  345. int ebpf_exit_plugin = 0;
  346. /**
  347. * Close the collector gracefully
  348. *
  349. * @param sig is the signal number used to close the collector
  350. */
  351. static void ebpf_stop_threads(int sig)
  352. {
  353. ebpf_exit_plugin = 1;
  354. int i;
  355. for (i = 0; ebpf_threads[i].name != NULL; i++);
  356. usec_t max = 2 * USEC_PER_SEC, step = 100000;
  357. while (i && max) {
  358. max -= step;
  359. sleep_usec(step);
  360. i = 0;
  361. int j;
  362. for (j = 0; ebpf_threads[j].name != NULL; j++) {
  363. if (ebpf_threads[j].enabled != NETDATA_MAIN_THREAD_EXITED)
  364. i++;
  365. }
  366. }
  367. //Unload threads(except sync and filesystem)
  368. for (i = 0; ebpf_threads[i].name != NULL; i++) {
  369. if (ebpf_threads[i].enabled == NETDATA_MAIN_THREAD_EXITED && i != EBPF_MODULE_FILESYSTEM_IDX &&
  370. i != EBPF_MODULE_SYNC_IDX)
  371. ebpf_unload_legacy_code(ebpf_modules[i].objects, ebpf_modules[i].probe_links);
  372. }
  373. //Unload filesystem
  374. if (ebpf_threads[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_MAIN_THREAD_EXITED) {
  375. for (i = 0; localfs[i].filesystem != NULL; i++) {
  376. ebpf_unload_legacy_code(localfs[i].objects, localfs[i].probe_links);
  377. }
  378. }
  379. //Unload Sync
  380. if (ebpf_threads[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_MAIN_THREAD_EXITED) {
  381. for (i = 0; local_syscalls[i].syscall != NULL; i++) {
  382. ebpf_unload_legacy_code(local_syscalls[i].objects, local_syscalls[i].probe_links);
  383. }
  384. }
  385. ebpf_exit(sig);
  386. }
  387. /*****************************************************************
  388. *
  389. * FUNCTIONS TO CREATE CHARTS
  390. *
  391. *****************************************************************/
  392. /**
  393. * Get a value from a structure.
  394. *
  395. * @param basis it is the first address of the structure
  396. * @param offset it is the offset of the data you want to access.
  397. * @return
  398. */
  399. collected_number get_value_from_structure(char *basis, size_t offset)
  400. {
  401. collected_number *value = (collected_number *)(basis + offset);
  402. collected_number ret = (collected_number)llabs(*value);
  403. // this reset is necessary to avoid keep a constant value while processing is not executing a task
  404. *value = 0;
  405. return ret;
  406. }
  407. /**
  408. * Write begin command on standard output
  409. *
  410. * @param family the chart family name
  411. * @param name the chart name
  412. */
  413. void write_begin_chart(char *family, char *name)
  414. {
  415. printf("BEGIN %s.%s\n", family, name);
  416. }
  417. /**
  418. * Write END command on stdout.
  419. */
  420. inline void write_end_chart()
  421. {
  422. printf("END\n");
  423. }
  424. /**
  425. * Write set command on standard output
  426. *
  427. * @param dim the dimension name
  428. * @param value the value for the dimension
  429. */
  430. void write_chart_dimension(char *dim, long long value)
  431. {
  432. printf("SET %s = %lld\n", dim, value);
  433. }
  434. /**
  435. * Call the necessary functions to create a chart.
  436. *
  437. * @param name the chart name
  438. * @param family the chart family
  439. * @param move the pointer with the values that will be published
  440. * @param end the number of values that will be written on standard output
  441. *
  442. * @return It returns a variable that maps the charts that did not have zero values.
  443. */
  444. void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move, uint32_t end)
  445. {
  446. write_begin_chart(family, name);
  447. uint32_t i = 0;
  448. while (move && i < end) {
  449. write_chart_dimension(move->name, move->ncall);
  450. move = move->next;
  451. i++;
  452. }
  453. write_end_chart();
  454. }
  455. /**
  456. * Call the necessary functions to create a chart.
  457. *
  458. * @param name the chart name
  459. * @param family the chart family
  460. * @param move the pointer with the values that will be published
  461. * @param end the number of values that will be written on standard output
  462. */
  463. void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end)
  464. {
  465. write_begin_chart(family, name);
  466. int i = 0;
  467. while (move && i < end) {
  468. write_chart_dimension(move->name, move->nerr);
  469. move = move->next;
  470. i++;
  471. }
  472. write_end_chart();
  473. }
  474. /**
  475. * Write charts
  476. *
  477. * Write the current information to publish the charts.
  478. *
  479. * @param family chart family
  480. * @param chart chart id
  481. * @param dim dimension name
  482. * @param v1 value.
  483. */
  484. void ebpf_one_dimension_write_charts(char *family, char *chart, char *dim, long long v1)
  485. {
  486. write_begin_chart(family, chart);
  487. write_chart_dimension(dim, v1);
  488. write_end_chart();
  489. }
  490. /**
  491. * Call the necessary functions to create a chart.
  492. *
  493. * @param chart the chart name
  494. * @param family the chart family
  495. * @param dwrite the dimension name
  496. * @param vwrite the value for previous dimension
  497. * @param dread the dimension name
  498. * @param vread the value for previous dimension
  499. *
  500. * @return It returns a variable that maps the charts that did not have zero values.
  501. */
  502. void write_io_chart(char *chart, char *family, char *dwrite, long long vwrite, char *dread, long long vread)
  503. {
  504. write_begin_chart(family, chart);
  505. write_chart_dimension(dwrite, vwrite);
  506. write_chart_dimension(dread, vread);
  507. write_end_chart();
  508. }
  509. /**
  510. * Write chart cmd on standard output
  511. *
  512. * @param type chart type
  513. * @param id chart id
  514. * @param title chart title
  515. * @param units units label
  516. * @param family group name used to attach the chart on dashboard
  517. * @param charttype chart type
  518. * @param context chart context
  519. * @param order chart order
  520. * @param update_every update interval used by plugin
  521. * @param module chart module name, this is the eBPF thread.
  522. */
  523. void ebpf_write_chart_cmd(char *type, char *id, char *title, char *units, char *family,
  524. char *charttype, char *context, int order, int update_every, char *module)
  525. {
  526. printf("CHART %s.%s '' '%s' '%s' '%s' '%s' '%s' %d %d '' 'ebpf.plugin' '%s'\n",
  527. type,
  528. id,
  529. title,
  530. units,
  531. (family)?family:"",
  532. (context)?context:"",
  533. (charttype)?charttype:"",
  534. order,
  535. update_every,
  536. module);
  537. }
  538. /**
  539. * Write chart cmd on standard output
  540. *
  541. * @param type chart type
  542. * @param id chart id
  543. * @param title chart title
  544. * @param units units label
  545. * @param family group name used to attach the chart on dashboard
  546. * @param charttype chart type
  547. * @param context chart context
  548. * @param order chart order
  549. * @param update_every value to overwrite the update frequency set by the server.
  550. */
  551. void ebpf_write_chart_obsolete(char *type, char *id, char *title, char *units, char *family,
  552. char *charttype, char *context, int order, int update_every)
  553. {
  554. printf("CHART %s.%s '' '%s' '%s' '%s' '%s' '%s' %d %d 'obsolete'\n",
  555. type,
  556. id,
  557. title,
  558. units,
  559. (family)?family:"",
  560. (context)?context:"",
  561. (charttype)?charttype:"",
  562. order,
  563. update_every);
  564. }
  565. /**
  566. * Write the dimension command on standard output
  567. *
  568. * @param name the dimension name
  569. * @param id the dimension id
  570. * @param algo the dimension algorithm
  571. */
  572. void ebpf_write_global_dimension(char *name, char *id, char *algorithm)
  573. {
  574. printf("DIMENSION %s %s %s 1 1\n", name, id, algorithm);
  575. }
  576. /**
  577. * Call ebpf_write_global_dimension to create the dimensions for a specific chart
  578. *
  579. * @param ptr a pointer to a structure of the type netdata_publish_syscall_t
  580. * @param end the number of dimensions for the structure ptr
  581. */
  582. void ebpf_create_global_dimension(void *ptr, int end)
  583. {
  584. netdata_publish_syscall_t *move = ptr;
  585. int i = 0;
  586. while (move && i < end) {
  587. ebpf_write_global_dimension(move->name, move->dimension, move->algorithm);
  588. move = move->next;
  589. i++;
  590. }
  591. }
  592. /**
  593. * Call write_chart_cmd to create the charts
  594. *
  595. * @param type chart type
  596. * @param id chart id
  597. * @param title chart title
  598. * @param units axis label
  599. * @param family group name used to attach the chart on dashboard
  600. * @param context chart context
  601. * @param charttype chart type
  602. * @param order order number of the specified chart
  603. * @param ncd a pointer to a function called to create dimensions
  604. * @param move a pointer for a structure that has the dimensions
  605. * @param end number of dimensions for the chart created
  606. * @param update_every update interval used with chart.
  607. * @param module chart module name, this is the eBPF thread.
  608. */
  609. void ebpf_create_chart(char *type,
  610. char *id,
  611. char *title,
  612. char *units,
  613. char *family,
  614. char *context,
  615. char *charttype,
  616. int order,
  617. void (*ncd)(void *, int),
  618. void *move,
  619. int end,
  620. int update_every,
  621. char *module)
  622. {
  623. ebpf_write_chart_cmd(type, id, title, units, family, charttype, context, order, update_every, module);
  624. if (ncd) {
  625. ncd(move, end);
  626. }
  627. }
  628. /**
  629. * Create charts on apps submenu
  630. *
  631. * @param id the chart id
  632. * @param title the value displayed on vertical axis.
  633. * @param units the value displayed on vertical axis.
  634. * @param family Submenu that the chart will be attached on dashboard.
  635. * @param charttype chart type
  636. * @param order the chart order
  637. * @param algorithm the algorithm used by dimension
  638. * @param root structure used to create the dimensions.
  639. * @param update_every update interval used by plugin
  640. * @param module chart module name, this is the eBPF thread.
  641. */
  642. void ebpf_create_charts_on_apps(char *id, char *title, char *units, char *family, char *charttype, int order,
  643. char *algorithm, struct target *root, int update_every, char *module)
  644. {
  645. struct target *w;
  646. ebpf_write_chart_cmd(NETDATA_APPS_FAMILY, id, title, units, family, charttype, NULL, order,
  647. update_every, module);
  648. for (w = root; w; w = w->next) {
  649. if (unlikely(w->exposed))
  650. fprintf(stdout, "DIMENSION %s '' %s 1 1\n", w->name, algorithm);
  651. }
  652. }
  653. /**
  654. * Call the necessary functions to create a name.
  655. *
  656. * @param family family name
  657. * @param name chart name
  658. * @param hist0 histogram values
  659. * @param dimensions dimension values.
  660. * @param end number of bins that will be sent to Netdata.
  661. *
  662. * @return It returns a variable that maps the charts that did not have zero values.
  663. */
  664. void write_histogram_chart(char *family, char *name, const netdata_idx_t *hist, char **dimensions, uint32_t end)
  665. {
  666. write_begin_chart(family, name);
  667. uint32_t i;
  668. for (i = 0; i < end; i++) {
  669. write_chart_dimension(dimensions[i], (long long) hist[i]);
  670. }
  671. write_end_chart();
  672. fflush(stdout);
  673. }
  674. /*****************************************************************
  675. *
  676. * FUNCTIONS TO DEFINE OPTIONS
  677. *
  678. *****************************************************************/
  679. /**
  680. * Define labels used to generate charts
  681. *
  682. * @param is structure with information about number of calls made for a function.
  683. * @param pio structure used to generate charts.
  684. * @param dim a pointer for the dimensions name
  685. * @param name a pointer for the tensor with the name of the functions.
  686. * @param algorithm a vector with the algorithms used to make the charts
  687. * @param end the number of elements in the previous 4 arguments.
  688. */
  689. void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *pio, char **dim,
  690. char **name, int *algorithm, int end)
  691. {
  692. int i;
  693. netdata_syscall_stat_t *prev = NULL;
  694. netdata_publish_syscall_t *publish_prev = NULL;
  695. for (i = 0; i < end; i++) {
  696. if (prev) {
  697. prev->next = &is[i];
  698. }
  699. prev = &is[i];
  700. pio[i].dimension = dim[i];
  701. pio[i].name = name[i];
  702. pio[i].algorithm = strdupz(ebpf_algorithms[algorithm[i]]);
  703. if (publish_prev) {
  704. publish_prev->next = &pio[i];
  705. }
  706. publish_prev = &pio[i];
  707. }
  708. }
  709. /**
  710. * Define thread mode for all ebpf program.
  711. *
  712. * @param lmode the mode that will be used for them.
  713. */
  714. static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode)
  715. {
  716. int i;
  717. for (i = 0; ebpf_modules[i].thread_name; i++) {
  718. ebpf_modules[i].mode = lmode;
  719. }
  720. }
  721. /**
  722. * Enable specific charts selected by user.
  723. *
  724. * @param em the structure that will be changed
  725. * @param disable_apps the status about the apps charts.
  726. * @param disable_cgroup the status about the cgroups charts.
  727. */
  728. static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disable_apps, int disable_cgroup)
  729. {
  730. em->enabled = CONFIG_BOOLEAN_YES;
  731. // oomkill stores data inside apps submenu, so it always need to have apps_enabled for plugin to create
  732. // its chart, without this comparison eBPF.plugin will try to store invalid data when apps is disabled.
  733. if (!disable_apps || !strcmp(em->thread_name, "oomkill")) {
  734. em->apps_charts = NETDATA_EBPF_APPS_FLAG_YES;
  735. }
  736. if (!disable_cgroup) {
  737. em->cgroup_charts = CONFIG_BOOLEAN_YES;
  738. }
  739. em->global_charts = CONFIG_BOOLEAN_YES;
  740. }
  741. /**
  742. * Enable all charts
  743. *
  744. * @param apps what is the current status of apps
  745. * @param cgroups what is the current status of cgroups
  746. */
  747. static inline void ebpf_enable_all_charts(int apps, int cgroups)
  748. {
  749. int i;
  750. for (i = 0; ebpf_modules[i].thread_name; i++) {
  751. ebpf_enable_specific_chart(&ebpf_modules[i], apps, cgroups);
  752. }
  753. }
  754. /**
  755. * Disable all Global charts
  756. *
  757. * Disable charts
  758. */
  759. static inline void disable_all_global_charts()
  760. {
  761. int i;
  762. for (i = 0; ebpf_modules[i].thread_name; i++) {
  763. ebpf_modules[i].enabled = 0;
  764. ebpf_modules[i].global_charts = 0;
  765. }
  766. }
  767. /**
  768. * Enable the specified chart group
  769. *
  770. * @param idx the index of ebpf_modules that I am enabling
  771. * @param disable_apps should I keep apps charts?
  772. */
  773. static inline void ebpf_enable_chart(int idx, int disable_apps, int disable_cgroup)
  774. {
  775. int i;
  776. for (i = 0; ebpf_modules[i].thread_name; i++) {
  777. if (i == idx) {
  778. ebpf_enable_specific_chart(&ebpf_modules[i], disable_apps, disable_cgroup);
  779. break;
  780. }
  781. }
  782. }
  783. /**
  784. * Disable APPs
  785. *
  786. * Disable charts for apps loading only global charts.
  787. */
  788. static inline void ebpf_disable_apps()
  789. {
  790. int i;
  791. for (i = 0; ebpf_modules[i].thread_name; i++) {
  792. ebpf_modules[i].apps_charts = NETDATA_EBPF_APPS_FLAG_NO;
  793. }
  794. }
  795. /**
  796. * Disable Cgroups
  797. *
  798. * Disable charts for apps loading only global charts.
  799. */
  800. static inline void ebpf_disable_cgroups()
  801. {
  802. int i;
  803. for (i = 0; ebpf_modules[i].thread_name; i++) {
  804. ebpf_modules[i].cgroup_charts = 0;
  805. }
  806. }
  807. /**
  808. * Update Disabled Plugins
  809. *
  810. * This function calls ebpf_update_stats to update statistics for collector.
  811. *
  812. * @param em a pointer to `struct ebpf_module`
  813. */
  814. void ebpf_update_disabled_plugin_stats(ebpf_module_t *em)
  815. {
  816. pthread_mutex_lock(&lock);
  817. ebpf_update_stats(&plugin_statistics, em);
  818. pthread_mutex_unlock(&lock);
  819. }
  820. /**
  821. * Print help on standard error for user knows how to use the collector.
  822. */
  823. void ebpf_print_help()
  824. {
  825. const time_t t = time(NULL);
  826. struct tm ct;
  827. struct tm *test = localtime_r(&t, &ct);
  828. int year;
  829. if (test)
  830. year = ct.tm_year;
  831. else
  832. year = 0;
  833. fprintf(stderr,
  834. "\n"
  835. " Netdata ebpf.plugin %s\n"
  836. " Copyright (C) 2016-%d Costa Tsaousis <costa@tsaousis.gr>\n"
  837. " Released under GNU General Public License v3 or later.\n"
  838. " All rights reserved.\n"
  839. "\n"
  840. " This eBPF.plugin is a data collector plugin for netdata.\n"
  841. "\n"
  842. " This plugin only accepts long options with one or two dashes. The available command line options are:\n"
  843. "\n"
  844. " SECONDS Set the data collection frequency.\n"
  845. "\n"
  846. " [-]-help Show this help.\n"
  847. "\n"
  848. " [-]-version Show software version.\n"
  849. "\n"
  850. " [-]-global Disable charts per application and cgroup.\n"
  851. "\n"
  852. " [-]-all Enable all chart groups (global, apps, and cgroup), unless -g is also given.\n"
  853. "\n"
  854. " [-]-cachestat Enable charts related to process run time.\n"
  855. "\n"
  856. " [-]-dcstat Enable charts related to directory cache.\n"
  857. "\n"
  858. " [-]-disk Enable charts related to disk monitoring.\n"
  859. "\n"
  860. " [-]-filesystem Enable chart related to filesystem run time.\n"
  861. "\n"
  862. " [-]-hardirq Enable chart related to hard IRQ latency.\n"
  863. "\n"
  864. " [-]-mdflush Enable charts related to multi-device flush.\n"
  865. "\n"
  866. " [-]-mount Enable charts related to mount monitoring.\n"
  867. "\n"
  868. " [-]-net Enable network viewer charts.\n"
  869. "\n"
  870. " [-]-oomkill Enable chart related to OOM kill tracking.\n"
  871. "\n"
  872. " [-]-process Enable charts related to process run time.\n"
  873. "\n"
  874. " [-]-return Run the collector in return mode.\n"
  875. "\n"
  876. " [-]-shm Enable chart related to shared memory tracking.\n"
  877. "\n"
  878. " [-]-softirq Enable chart related to soft IRQ latency.\n"
  879. "\n"
  880. " [-]-sync Enable chart related to sync run time.\n"
  881. "\n"
  882. " [-]-swap Enable chart related to swap run time.\n"
  883. "\n"
  884. " [-]-vfs Enable chart related to vfs run time.\n"
  885. "\n"
  886. " [-]-legacy Load legacy eBPF programs.\n"
  887. "\n"
  888. " [-]-core Use CO-RE when available(Working in progress).\n"
  889. "\n",
  890. VERSION,
  891. (year >= 116) ? year + 1900 : 2020);
  892. }
  893. /*****************************************************************
  894. *
  895. * TRACEPOINT MANAGEMENT FUNCTIONS
  896. *
  897. *****************************************************************/
  898. /**
  899. * Enable a tracepoint.
  900. *
  901. * @return 0 on success, -1 on error.
  902. */
  903. int ebpf_enable_tracepoint(ebpf_tracepoint_t *tp)
  904. {
  905. int test = ebpf_is_tracepoint_enabled(tp->class, tp->event);
  906. // err?
  907. if (test == -1) {
  908. return -1;
  909. }
  910. // disabled?
  911. else if (test == 0) {
  912. // enable it then.
  913. if (ebpf_enable_tracing_values(tp->class, tp->event)) {
  914. return -1;
  915. }
  916. }
  917. // enabled now or already was.
  918. tp->enabled = true;
  919. return 0;
  920. }
  921. /**
  922. * Disable a tracepoint if it's enabled.
  923. *
  924. * @return 0 on success, -1 on error.
  925. */
  926. int ebpf_disable_tracepoint(ebpf_tracepoint_t *tp)
  927. {
  928. int test = ebpf_is_tracepoint_enabled(tp->class, tp->event);
  929. // err?
  930. if (test == -1) {
  931. return -1;
  932. }
  933. // enabled?
  934. else if (test == 1) {
  935. // disable it then.
  936. if (ebpf_disable_tracing_values(tp->class, tp->event)) {
  937. return -1;
  938. }
  939. }
  940. // disable now or already was.
  941. tp->enabled = false;
  942. return 0;
  943. }
  944. /**
  945. * Enable multiple tracepoints on a list of tracepoints which end when the
  946. * class is NULL.
  947. *
  948. * @return the number of successful enables.
  949. */
  950. uint32_t ebpf_enable_tracepoints(ebpf_tracepoint_t *tps)
  951. {
  952. uint32_t cnt = 0;
  953. for (int i = 0; tps[i].class != NULL; i++) {
  954. if (ebpf_enable_tracepoint(&tps[i]) == -1) {
  955. infoerr("failed to enable tracepoint %s:%s",
  956. tps[i].class, tps[i].event);
  957. }
  958. else {
  959. cnt += 1;
  960. }
  961. }
  962. return cnt;
  963. }
  964. /*****************************************************************
  965. *
  966. * AUXILIARY FUNCTIONS USED DURING INITIALIZATION
  967. *
  968. *****************************************************************/
  969. /**
  970. * Read Local Ports
  971. *
  972. * Parse /proc/net/{tcp,udp} and get the ports Linux is listening.
  973. *
  974. * @param filename the proc file to parse.
  975. * @param proto is the magic number associated to the protocol file we are reading.
  976. */
  977. static void read_local_ports(char *filename, uint8_t proto)
  978. {
  979. procfile *ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
  980. if (!ff)
  981. return;
  982. ff = procfile_readall(ff);
  983. if (!ff)
  984. return;
  985. size_t lines = procfile_lines(ff), l;
  986. netdata_passive_connection_t values = {.counter = 0, .tgid = 0, .pid = 0};
  987. for(l = 0; l < lines ;l++) {
  988. size_t words = procfile_linewords(ff, l);
  989. // This is header or end of file
  990. if (unlikely(words < 14))
  991. continue;
  992. // https://elixir.bootlin.com/linux/v5.7.8/source/include/net/tcp_states.h
  993. // 0A = TCP_LISTEN
  994. if (strcmp("0A", procfile_lineword(ff, l, 5)))
  995. continue;
  996. // Read local port
  997. uint16_t port = (uint16_t)strtol(procfile_lineword(ff, l, 2), NULL, 16);
  998. update_listen_table(htons(port), proto, &values);
  999. }
  1000. procfile_close(ff);
  1001. }
  1002. /**
  1003. * Read Local addresseses
  1004. *
  1005. * Read the local address from the interfaces.
  1006. */
  1007. static void read_local_addresses()
  1008. {
  1009. struct ifaddrs *ifaddr, *ifa;
  1010. if (getifaddrs(&ifaddr) == -1) {
  1011. error("Cannot get the local IP addresses, it is no possible to do separation between inbound and outbound connections");
  1012. return;
  1013. }
  1014. char *notext = { "No text representation" };
  1015. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  1016. if (ifa->ifa_addr == NULL)
  1017. continue;
  1018. if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6))
  1019. continue;
  1020. ebpf_network_viewer_ip_list_t *w = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
  1021. int family = ifa->ifa_addr->sa_family;
  1022. w->ver = (uint8_t) family;
  1023. char text[INET6_ADDRSTRLEN];
  1024. if (family == AF_INET) {
  1025. struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
  1026. w->first.addr32[0] = in->sin_addr.s_addr;
  1027. w->last.addr32[0] = in->sin_addr.s_addr;
  1028. if (inet_ntop(AF_INET, w->first.addr8, text, INET_ADDRSTRLEN)) {
  1029. w->value = strdupz(text);
  1030. w->hash = simple_hash(text);
  1031. } else {
  1032. w->value = strdupz(notext);
  1033. w->hash = simple_hash(notext);
  1034. }
  1035. } else {
  1036. struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
  1037. memcpy(w->first.addr8, (void *)&in6->sin6_addr, sizeof(struct in6_addr));
  1038. memcpy(w->last.addr8, (void *)&in6->sin6_addr, sizeof(struct in6_addr));
  1039. if (inet_ntop(AF_INET6, w->first.addr8, text, INET_ADDRSTRLEN)) {
  1040. w->value = strdupz(text);
  1041. w->hash = simple_hash(text);
  1042. } else {
  1043. w->value = strdupz(notext);
  1044. w->hash = simple_hash(notext);
  1045. }
  1046. }
  1047. fill_ip_list((family == AF_INET)?&network_viewer_opt.ipv4_local_ip:&network_viewer_opt.ipv6_local_ip,
  1048. w,
  1049. "selector");
  1050. }
  1051. freeifaddrs(ifaddr);
  1052. }
  1053. /**
  1054. * Start Pthread Variable
  1055. *
  1056. * This function starts all pthread variables.
  1057. *
  1058. * @return It returns 0 on success and -1.
  1059. */
  1060. int ebpf_start_pthread_variables()
  1061. {
  1062. pthread_mutex_init(&lock, NULL);
  1063. pthread_mutex_init(&collect_data_mutex, NULL);
  1064. if (pthread_cond_init(&collect_data_cond_var, NULL)) {
  1065. error("Cannot start conditional variable to control Apps charts.");
  1066. return -1;
  1067. }
  1068. return 0;
  1069. }
  1070. /**
  1071. * Am I collecting PIDs?
  1072. *
  1073. * Test if eBPF plugin needs to collect PID information.
  1074. *
  1075. * @return It returns 1 if at least one thread needs to collect the data, or zero otherwise.
  1076. */
  1077. static inline uint32_t ebpf_am_i_collect_pids()
  1078. {
  1079. uint32_t ret = 0;
  1080. int i;
  1081. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1082. ret |= ebpf_modules[i].cgroup_charts | (ebpf_modules[i].apps_charts & NETDATA_EBPF_APPS_FLAG_YES);
  1083. }
  1084. return ret;
  1085. }
  1086. /**
  1087. * Allocate the vectors used for all threads.
  1088. */
  1089. static void ebpf_allocate_common_vectors()
  1090. {
  1091. if (unlikely(!ebpf_am_i_collect_pids())) {
  1092. return;
  1093. }
  1094. all_pids = callocz((size_t)pid_max, sizeof(struct pid_stat *));
  1095. global_process_stat = callocz((size_t)ebpf_nprocs, sizeof(ebpf_process_stat_t));
  1096. }
  1097. /**
  1098. * Define how to load the ebpf programs
  1099. *
  1100. * @param ptr the option given by users
  1101. */
  1102. static inline void how_to_load(char *ptr)
  1103. {
  1104. if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_RETURN))
  1105. ebpf_set_thread_mode(MODE_RETURN);
  1106. else if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_DEFAULT))
  1107. ebpf_set_thread_mode(MODE_ENTRY);
  1108. else
  1109. error("the option %s for \"ebpf load mode\" is not a valid option.", ptr);
  1110. }
  1111. /**
  1112. * Update interval
  1113. *
  1114. * Update default interval with value from user
  1115. *
  1116. * @param update_every value to overwrite the update frequency set by the server.
  1117. */
  1118. static void ebpf_update_interval(int update_every)
  1119. {
  1120. int i;
  1121. int value = (int) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY,
  1122. update_every);
  1123. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1124. ebpf_modules[i].update_every = value;
  1125. }
  1126. }
  1127. /**
  1128. * Update PID table size
  1129. *
  1130. * Update default size with value from user
  1131. */
  1132. static void ebpf_update_table_size()
  1133. {
  1134. int i;
  1135. uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
  1136. EBPF_CFG_PID_SIZE, ND_EBPF_DEFAULT_PID_SIZE);
  1137. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1138. ebpf_modules[i].pid_map_size = value;
  1139. }
  1140. }
  1141. /**
  1142. * Set Load mode
  1143. *
  1144. * @param load default load mode.
  1145. */
  1146. static inline void ebpf_set_load_mode(netdata_ebpf_load_mode_t load)
  1147. {
  1148. #ifdef LIBBPF_MAJOR_VERSION
  1149. if (load == EBPF_LOAD_CORE || load == EBPF_LOAD_PLAY_DICE) {
  1150. load = (!default_btf) ? EBPF_LOAD_LEGACY : EBPF_LOAD_CORE;
  1151. }
  1152. #else
  1153. load = EBPF_LOAD_LEGACY;
  1154. #endif
  1155. int i;
  1156. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1157. // TO DO: Use `load` variable after we change all threads.
  1158. ebpf_modules[i].load = EBPF_LOAD_LEGACY; // load ;
  1159. }
  1160. }
  1161. /**
  1162. * Update mode
  1163. *
  1164. * @param str value read from configuration file.
  1165. */
  1166. static inline void epbf_update_load_mode(char *str)
  1167. {
  1168. netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(str);
  1169. ebpf_set_load_mode(load);
  1170. }
  1171. /**
  1172. * Read collector values
  1173. *
  1174. * @param disable_apps variable to store information related to apps.
  1175. * @param disable_cgroups variable to store information related to cgroups.
  1176. * @param update_every value to overwrite the update frequency set by the server.
  1177. */
  1178. static void read_collector_values(int *disable_apps, int *disable_cgroups, int update_every)
  1179. {
  1180. // Read global section
  1181. char *value;
  1182. if (appconfig_exists(&collector_config, EBPF_GLOBAL_SECTION, "load")) // Backward compatibility
  1183. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "load",
  1184. EBPF_CFG_LOAD_MODE_DEFAULT);
  1185. else
  1186. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE,
  1187. EBPF_CFG_LOAD_MODE_DEFAULT);
  1188. how_to_load(value);
  1189. btf_path = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_PROGRAM_PATH,
  1190. EBPF_DEFAULT_BTF_PATH);
  1191. #ifdef LIBBPF_MAJOR_VERSION
  1192. default_btf = ebpf_load_btf_file(btf_path, EBPF_DEFAULT_BTF_FILE);
  1193. #endif
  1194. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, EBPF_CFG_DEFAULT_PROGRAM);
  1195. epbf_update_load_mode(value);
  1196. ebpf_update_interval(update_every);
  1197. ebpf_update_table_size();
  1198. // This is kept to keep compatibility
  1199. uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, "disable apps",
  1200. CONFIG_BOOLEAN_NO);
  1201. if (!enabled) {
  1202. // Apps is a positive sentence, so we need to invert the values to disable apps.
  1203. enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION,
  1204. CONFIG_BOOLEAN_YES);
  1205. enabled = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO;
  1206. }
  1207. *disable_apps = (int)enabled;
  1208. // Cgroup is a positive sentence, so we need to invert the values to disable apps.
  1209. // We are using the same pattern for cgroup and apps
  1210. enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_CGROUP, CONFIG_BOOLEAN_NO);
  1211. *disable_cgroups = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO;
  1212. // Read ebpf programs section
  1213. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
  1214. ebpf_modules[EBPF_MODULE_PROCESS_IDX].config_name, CONFIG_BOOLEAN_YES);
  1215. int started = 0;
  1216. if (enabled) {
  1217. ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_apps, *disable_cgroups);
  1218. started++;
  1219. }
  1220. // This is kept to keep compatibility
  1221. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network viewer",
  1222. CONFIG_BOOLEAN_NO);
  1223. if (!enabled)
  1224. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
  1225. ebpf_modules[EBPF_MODULE_SOCKET_IDX].config_name,
  1226. CONFIG_BOOLEAN_NO);
  1227. if (enabled) {
  1228. ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_apps, *disable_cgroups);
  1229. // Read network viewer section if network viewer is enabled
  1230. // This is kept here to keep backward compatibility
  1231. parse_network_viewer_section(&collector_config);
  1232. parse_service_name_section(&collector_config);
  1233. started++;
  1234. }
  1235. // This is kept to keep compatibility
  1236. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connection monitoring",
  1237. CONFIG_BOOLEAN_NO);
  1238. if (!enabled)
  1239. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connections",
  1240. CONFIG_BOOLEAN_NO);
  1241. ebpf_modules[EBPF_MODULE_SOCKET_IDX].optional = (int)enabled;
  1242. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "cachestat",
  1243. CONFIG_BOOLEAN_NO);
  1244. if (enabled) {
  1245. ebpf_enable_chart(EBPF_MODULE_CACHESTAT_IDX, *disable_apps, *disable_cgroups);
  1246. started++;
  1247. }
  1248. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "sync",
  1249. CONFIG_BOOLEAN_YES);
  1250. if (enabled) {
  1251. ebpf_enable_chart(EBPF_MODULE_SYNC_IDX, *disable_apps, *disable_cgroups);
  1252. started++;
  1253. }
  1254. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "dcstat",
  1255. CONFIG_BOOLEAN_NO);
  1256. if (enabled) {
  1257. ebpf_enable_chart(EBPF_MODULE_DCSTAT_IDX, *disable_apps, *disable_cgroups);
  1258. started++;
  1259. }
  1260. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "swap",
  1261. CONFIG_BOOLEAN_NO);
  1262. if (enabled) {
  1263. ebpf_enable_chart(EBPF_MODULE_SWAP_IDX, *disable_apps, *disable_cgroups);
  1264. started++;
  1265. }
  1266. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "vfs",
  1267. CONFIG_BOOLEAN_NO);
  1268. if (enabled) {
  1269. ebpf_enable_chart(EBPF_MODULE_VFS_IDX, *disable_apps, *disable_cgroups);
  1270. started++;
  1271. }
  1272. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "filesystem",
  1273. CONFIG_BOOLEAN_NO);
  1274. if (enabled) {
  1275. ebpf_enable_chart(EBPF_MODULE_FILESYSTEM_IDX, *disable_apps, *disable_cgroups);
  1276. started++;
  1277. }
  1278. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "disk",
  1279. CONFIG_BOOLEAN_NO);
  1280. if (enabled) {
  1281. ebpf_enable_chart(EBPF_MODULE_DISK_IDX, *disable_apps, *disable_cgroups);
  1282. started++;
  1283. }
  1284. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mount",
  1285. CONFIG_BOOLEAN_YES);
  1286. if (enabled) {
  1287. ebpf_enable_chart(EBPF_MODULE_MOUNT_IDX, *disable_apps, *disable_cgroups);
  1288. started++;
  1289. }
  1290. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "fd",
  1291. CONFIG_BOOLEAN_YES);
  1292. if (enabled) {
  1293. ebpf_enable_chart(EBPF_MODULE_FD_IDX, *disable_apps, *disable_cgroups);
  1294. started++;
  1295. }
  1296. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "hardirq",
  1297. CONFIG_BOOLEAN_YES);
  1298. if (enabled) {
  1299. ebpf_enable_chart(EBPF_MODULE_HARDIRQ_IDX, *disable_apps, *disable_cgroups);
  1300. started++;
  1301. }
  1302. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "softirq",
  1303. CONFIG_BOOLEAN_YES);
  1304. if (enabled) {
  1305. ebpf_enable_chart(EBPF_MODULE_SOFTIRQ_IDX, *disable_apps, *disable_cgroups);
  1306. started++;
  1307. }
  1308. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "oomkill",
  1309. CONFIG_BOOLEAN_YES);
  1310. if (enabled) {
  1311. ebpf_enable_chart(EBPF_MODULE_OOMKILL_IDX, *disable_apps, *disable_cgroups);
  1312. started++;
  1313. }
  1314. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "shm",
  1315. CONFIG_BOOLEAN_YES);
  1316. if (enabled) {
  1317. ebpf_enable_chart(EBPF_MODULE_SHM_IDX, *disable_apps, *disable_cgroups);
  1318. started++;
  1319. }
  1320. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mdflush",
  1321. CONFIG_BOOLEAN_NO);
  1322. if (enabled) {
  1323. ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_apps, *disable_cgroups);
  1324. started++;
  1325. }
  1326. if (!started){
  1327. ebpf_enable_all_charts(*disable_apps, *disable_cgroups);
  1328. // Read network viewer section
  1329. // This is kept here to keep backward compatibility
  1330. parse_network_viewer_section(&collector_config);
  1331. parse_service_name_section(&collector_config);
  1332. }
  1333. }
  1334. /**
  1335. * Load collector config
  1336. *
  1337. * @param path the path where the file ebpf.conf is stored.
  1338. * @param disable_apps variable to store the information about apps plugin status.
  1339. * @param disable_cgroups variable to store the information about cgroups plugin status.
  1340. * @param update_every value to overwrite the update frequency set by the server.
  1341. *
  1342. * @return 0 on success and -1 otherwise.
  1343. */
  1344. static int load_collector_config(char *path, int *disable_apps, int *disable_cgroups, int update_every)
  1345. {
  1346. char lpath[4096];
  1347. snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_CONFIG_FILE);
  1348. if (!appconfig_load(&collector_config, lpath, 0, NULL)) {
  1349. snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_OLD_CONFIG_FILE);
  1350. if (!appconfig_load(&collector_config, lpath, 0, NULL)) {
  1351. return -1;
  1352. }
  1353. }
  1354. read_collector_values(disable_apps, disable_cgroups, update_every);
  1355. return 0;
  1356. }
  1357. /**
  1358. * Set global variables reading environment variables
  1359. */
  1360. void set_global_variables()
  1361. {
  1362. // Get environment variables
  1363. ebpf_plugin_dir = getenv("NETDATA_PLUGINS_DIR");
  1364. if (!ebpf_plugin_dir)
  1365. ebpf_plugin_dir = PLUGINS_DIR;
  1366. ebpf_user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
  1367. if (!ebpf_user_config_dir)
  1368. ebpf_user_config_dir = CONFIG_DIR;
  1369. ebpf_stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
  1370. if (!ebpf_stock_config_dir)
  1371. ebpf_stock_config_dir = LIBCONFIG_DIR;
  1372. ebpf_configured_log_dir = getenv("NETDATA_LOG_DIR");
  1373. if (!ebpf_configured_log_dir)
  1374. ebpf_configured_log_dir = LOG_DIR;
  1375. ebpf_nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
  1376. if (ebpf_nprocs > NETDATA_MAX_PROCESSOR) {
  1377. ebpf_nprocs = NETDATA_MAX_PROCESSOR;
  1378. }
  1379. isrh = get_redhat_release();
  1380. pid_max = get_system_pid_max();
  1381. running_on_kernel = ebpf_get_kernel_version();
  1382. }
  1383. /**
  1384. * Load collector config
  1385. */
  1386. static inline void ebpf_load_thread_config()
  1387. {
  1388. int i;
  1389. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1390. ebpf_update_module(&ebpf_modules[i]);
  1391. }
  1392. }
  1393. /**
  1394. * Parse arguments given from user.
  1395. *
  1396. * @param argc the number of arguments
  1397. * @param argv the pointer to the arguments
  1398. */
  1399. static void ebpf_parse_args(int argc, char **argv)
  1400. {
  1401. int disable_apps = 0;
  1402. int disable_cgroups = 1;
  1403. int freq = 0;
  1404. int option_index = 0;
  1405. uint64_t select_threads = 0;
  1406. static struct option long_options[] = {
  1407. {"process", no_argument, 0, 0 },
  1408. {"net", no_argument, 0, 0 },
  1409. {"cachestat", no_argument, 0, 0 },
  1410. {"sync", no_argument, 0, 0 },
  1411. {"dcstat", no_argument, 0, 0 },
  1412. {"swap", no_argument, 0, 0 },
  1413. {"vfs", no_argument, 0, 0 },
  1414. {"filesystem", no_argument, 0, 0 },
  1415. {"disk", no_argument, 0, 0 },
  1416. {"mount", no_argument, 0, 0 },
  1417. {"filedescriptor", no_argument, 0, 0 },
  1418. {"hardirq", no_argument, 0, 0 },
  1419. {"softirq", no_argument, 0, 0 },
  1420. {"oomkill", no_argument, 0, 0 },
  1421. {"shm", no_argument, 0, 0 },
  1422. {"mdflush", no_argument, 0, 0 },
  1423. /* INSERT NEW THREADS BEFORE THIS COMMENT TO KEEP COMPATIBILITY WITH enum ebpf_module_indexes */
  1424. {"all", no_argument, 0, 0 },
  1425. {"version", no_argument, 0, 0 },
  1426. {"help", no_argument, 0, 0 },
  1427. {"global", no_argument, 0, 0 },
  1428. {"return", no_argument, 0, 0 },
  1429. {"legacy", no_argument, 0, 0 },
  1430. {"core", no_argument, 0, 0 },
  1431. {0, 0, 0, 0}
  1432. };
  1433. memset(&network_viewer_opt, 0, sizeof(network_viewer_opt));
  1434. network_viewer_opt.max_dim = NETDATA_NV_CAP_VALUE;
  1435. if (argc > 1) {
  1436. int n = (int)str2l(argv[1]);
  1437. if (n > 0) {
  1438. freq = n;
  1439. }
  1440. }
  1441. if (!freq)
  1442. freq = EBPF_DEFAULT_UPDATE_EVERY;
  1443. if (load_collector_config(ebpf_user_config_dir, &disable_apps, &disable_cgroups, freq)) {
  1444. info(
  1445. "Does not have a configuration file inside `%s/ebpf.d.conf. It will try to load stock file.",
  1446. ebpf_user_config_dir);
  1447. if (load_collector_config(ebpf_stock_config_dir, &disable_apps, &disable_cgroups, freq)) {
  1448. info("Does not have a stock file. It is starting with default options.");
  1449. }
  1450. }
  1451. ebpf_load_thread_config();
  1452. while (1) {
  1453. int c = getopt_long_only(argc, argv, "", long_options, &option_index);
  1454. if (c == -1)
  1455. break;
  1456. switch (option_index) {
  1457. case EBPF_MODULE_PROCESS_IDX: {
  1458. select_threads |= 1<<EBPF_MODULE_PROCESS_IDX;
  1459. #ifdef NETDATA_INTERNAL_CHECKS
  1460. info("EBPF enabling \"PROCESS\" charts, because it was started with the option \"[-]-process\".");
  1461. #endif
  1462. break;
  1463. }
  1464. case EBPF_MODULE_SOCKET_IDX: {
  1465. select_threads |= 1<<EBPF_MODULE_SOCKET_IDX;
  1466. #ifdef NETDATA_INTERNAL_CHECKS
  1467. info("EBPF enabling \"NET\" charts, because it was started with the option \"[-]-net\".");
  1468. #endif
  1469. break;
  1470. }
  1471. case EBPF_MODULE_CACHESTAT_IDX: {
  1472. select_threads |= 1<<EBPF_MODULE_CACHESTAT_IDX;
  1473. #ifdef NETDATA_INTERNAL_CHECKS
  1474. info("EBPF enabling \"CACHESTAT\" charts, because it was started with the option \"[-]-cachestat\".");
  1475. #endif
  1476. break;
  1477. }
  1478. case EBPF_MODULE_SYNC_IDX: {
  1479. select_threads |= 1<<EBPF_MODULE_SYNC_IDX;
  1480. #ifdef NETDATA_INTERNAL_CHECKS
  1481. info("EBPF enabling \"SYNC\" chart, because it was started with the option \"[-]-sync\".");
  1482. #endif
  1483. break;
  1484. }
  1485. case EBPF_MODULE_DCSTAT_IDX: {
  1486. select_threads |= 1<<EBPF_MODULE_DCSTAT_IDX;
  1487. #ifdef NETDATA_INTERNAL_CHECKS
  1488. info("EBPF enabling \"DCSTAT\" charts, because it was started with the option \"[-]-dcstat\".");
  1489. #endif
  1490. break;
  1491. }
  1492. case EBPF_MODULE_SWAP_IDX: {
  1493. select_threads |= 1<<EBPF_MODULE_SWAP_IDX;
  1494. #ifdef NETDATA_INTERNAL_CHECKS
  1495. info("EBPF enabling \"SWAP\" chart, because it was started with the option \"[-]-swap\".");
  1496. #endif
  1497. break;
  1498. }
  1499. case EBPF_MODULE_VFS_IDX: {
  1500. select_threads |= 1<<EBPF_MODULE_VFS_IDX;
  1501. #ifdef NETDATA_INTERNAL_CHECKS
  1502. info("EBPF enabling \"VFS\" chart, because it was started with the option \"[-]-vfs\".");
  1503. #endif
  1504. break;
  1505. }
  1506. case EBPF_MODULE_FILESYSTEM_IDX: {
  1507. select_threads |= 1<<EBPF_MODULE_FILESYSTEM_IDX;
  1508. #ifdef NETDATA_INTERNAL_CHECKS
  1509. info("EBPF enabling \"FILESYSTEM\" chart, because it was started with the option \"[-]-filesystem\".");
  1510. #endif
  1511. break;
  1512. }
  1513. case EBPF_MODULE_DISK_IDX: {
  1514. select_threads |= 1<<EBPF_MODULE_DISK_IDX;
  1515. #ifdef NETDATA_INTERNAL_CHECKS
  1516. info("EBPF enabling \"DISK\" chart, because it was started with the option \"[-]-disk\".");
  1517. #endif
  1518. break;
  1519. }
  1520. case EBPF_MODULE_MOUNT_IDX: {
  1521. select_threads |= 1<<EBPF_MODULE_MOUNT_IDX;
  1522. #ifdef NETDATA_INTERNAL_CHECKS
  1523. info("EBPF enabling \"MOUNT\" chart, because it was started with the option \"[-]-mount\".");
  1524. #endif
  1525. break;
  1526. }
  1527. case EBPF_MODULE_FD_IDX: {
  1528. select_threads |= 1<<EBPF_MODULE_FD_IDX;
  1529. #ifdef NETDATA_INTERNAL_CHECKS
  1530. info("EBPF enabling \"FILEDESCRIPTOR\" chart, because it was started with the option \"[-]-filedescriptor\".");
  1531. #endif
  1532. break;
  1533. }
  1534. case EBPF_MODULE_HARDIRQ_IDX: {
  1535. select_threads |= 1<<EBPF_MODULE_HARDIRQ_IDX;
  1536. #ifdef NETDATA_INTERNAL_CHECKS
  1537. info("EBPF enabling \"HARDIRQ\" chart, because it was started with the option \"[-]-hardirq\".");
  1538. #endif
  1539. break;
  1540. }
  1541. case EBPF_MODULE_SOFTIRQ_IDX: {
  1542. select_threads |= 1<<EBPF_MODULE_SOFTIRQ_IDX;
  1543. #ifdef NETDATA_INTERNAL_CHECKS
  1544. info("EBPF enabling \"SOFTIRQ\" chart, because it was started with the option \"[-]-softirq\".");
  1545. #endif
  1546. break;
  1547. }
  1548. case EBPF_MODULE_OOMKILL_IDX: {
  1549. select_threads |= 1<<EBPF_MODULE_OOMKILL_IDX;
  1550. #ifdef NETDATA_INTERNAL_CHECKS
  1551. info("EBPF enabling \"OOMKILL\" chart, because it was started with the option \"[-]-oomkill\".");
  1552. #endif
  1553. break;
  1554. }
  1555. case EBPF_MODULE_SHM_IDX: {
  1556. select_threads |= 1<<EBPF_MODULE_SHM_IDX;
  1557. #ifdef NETDATA_INTERNAL_CHECKS
  1558. info("EBPF enabling \"SHM\" chart, because it was started with the option \"[-]-shm\".");
  1559. #endif
  1560. break;
  1561. }
  1562. case EBPF_MODULE_MDFLUSH_IDX: {
  1563. select_threads |= 1<<EBPF_MODULE_MDFLUSH_IDX;
  1564. #ifdef NETDATA_INTERNAL_CHECKS
  1565. info("EBPF enabling \"MDFLUSH\" chart, because it was started with the option \"[-]-mdflush\".");
  1566. #endif
  1567. break;
  1568. }
  1569. case EBPF_OPTION_ALL_CHARTS: {
  1570. disable_apps = 0;
  1571. disable_cgroups = 0;
  1572. #ifdef NETDATA_INTERNAL_CHECKS
  1573. info("EBPF running with all chart groups, because it was started with the option \"[-]-all\".");
  1574. #endif
  1575. break;
  1576. }
  1577. case EBPF_OPTION_VERSION: {
  1578. printf("ebpf.plugin %s\n", VERSION);
  1579. exit(0);
  1580. }
  1581. case EBPF_OPTION_HELP: {
  1582. ebpf_print_help();
  1583. exit(0);
  1584. }
  1585. case EBPF_OPTION_GLOBAL_CHART: {
  1586. disable_apps = 1;
  1587. disable_cgroups = 1;
  1588. #ifdef NETDATA_INTERNAL_CHECKS
  1589. info("EBPF running with global chart group, because it was started with the option \"[-]-global\".");
  1590. #endif
  1591. break;
  1592. }
  1593. case EBPF_OPTION_RETURN_MODE: {
  1594. ebpf_set_thread_mode(MODE_RETURN);
  1595. #ifdef NETDATA_INTERNAL_CHECKS
  1596. info("EBPF running in \"RETURN\" mode, because it was started with the option \"[-]-return\".");
  1597. #endif
  1598. break;
  1599. }
  1600. case EBPF_OPTION_LEGACY: {
  1601. ebpf_set_load_mode(EBPF_LOAD_LEGACY);
  1602. #ifdef NETDATA_INTERNAL_CHECKS
  1603. info("EBPF running with \"LEGACY\" code, because it was started with the option \"[-]-legacy\".");
  1604. #endif
  1605. break;
  1606. }
  1607. case EBPF_OPTION_CORE: {
  1608. ebpf_set_load_mode(EBPF_LOAD_CORE);
  1609. #ifdef NETDATA_INTERNAL_CHECKS
  1610. info("EBPF running with \"CO-RE\" code, because it was started with the option \"[-]-core\".");
  1611. #endif
  1612. break;
  1613. }
  1614. default: {
  1615. break;
  1616. }
  1617. }
  1618. }
  1619. if (disable_apps || disable_cgroups) {
  1620. if (disable_apps)
  1621. ebpf_disable_apps();
  1622. if (disable_cgroups)
  1623. ebpf_disable_cgroups();
  1624. }
  1625. if (select_threads) {
  1626. disable_all_global_charts();
  1627. uint64_t idx;
  1628. for (idx = 0; idx < EBPF_OPTION_ALL_CHARTS; idx++) {
  1629. if (select_threads & 1<<idx)
  1630. ebpf_enable_specific_chart(&ebpf_modules[idx], disable_apps, disable_cgroups);
  1631. }
  1632. }
  1633. // Load apps_groups.conf
  1634. if (ebpf_read_apps_groups_conf(
  1635. &apps_groups_default_target, &apps_groups_root_target, ebpf_user_config_dir, "groups")) {
  1636. info("Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'",
  1637. ebpf_user_config_dir, ebpf_stock_config_dir);
  1638. if (ebpf_read_apps_groups_conf(
  1639. &apps_groups_default_target, &apps_groups_root_target, ebpf_stock_config_dir, "groups")) {
  1640. error("Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.",
  1641. ebpf_stock_config_dir);
  1642. ebpf_exit(1);
  1643. }
  1644. } else
  1645. info("Loaded config file '%s/apps_groups.conf'", ebpf_user_config_dir);
  1646. }
  1647. /*****************************************************************
  1648. *
  1649. * COLLECTOR ENTRY POINT
  1650. *
  1651. *****************************************************************/
  1652. /**
  1653. * Update PID file
  1654. *
  1655. * Update the content of PID file
  1656. *
  1657. * @param filename is the full name of the file.
  1658. * @param pid that identifies the process
  1659. */
  1660. static void ebpf_update_pid_file(char *filename, pid_t pid)
  1661. {
  1662. FILE *fp = fopen(filename, "w");
  1663. if (!fp)
  1664. return;
  1665. fprintf(fp, "%d", pid);
  1666. fclose(fp);
  1667. }
  1668. /**
  1669. * Get Process Name
  1670. *
  1671. * Get process name from /proc/PID/status
  1672. *
  1673. * @param pid that identifies the process
  1674. */
  1675. static char *ebpf_get_process_name(pid_t pid)
  1676. {
  1677. char *name = NULL;
  1678. char filename[FILENAME_MAX + 1];
  1679. snprintfz(filename, FILENAME_MAX, "/proc/%d/status", pid);
  1680. procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
  1681. if(unlikely(!ff)) {
  1682. error("Cannot open %s", filename);
  1683. return name;
  1684. }
  1685. ff = procfile_readall(ff);
  1686. if(unlikely(!ff))
  1687. return name;
  1688. unsigned long i, lines = procfile_lines(ff);
  1689. for(i = 0; i < lines ; i++) {
  1690. char *cmp = procfile_lineword(ff, i, 0);
  1691. if (!strcmp(cmp, "Name:")) {
  1692. name = strdupz(procfile_lineword(ff, i, 1));
  1693. break;
  1694. }
  1695. }
  1696. procfile_close(ff);
  1697. return name;
  1698. }
  1699. /**
  1700. * Read Previous PID
  1701. *
  1702. * @param filename is the full name of the file.
  1703. *
  1704. * @return It returns the PID used during previous execution on success or 0 otherwise
  1705. */
  1706. static pid_t ebpf_read_previous_pid(char *filename)
  1707. {
  1708. FILE *fp = fopen(filename, "r");
  1709. if (!fp)
  1710. return 0;
  1711. char buffer[64];
  1712. size_t length = fread(buffer, sizeof(*buffer), 63, fp);
  1713. pid_t old_pid = 0;
  1714. if (length) {
  1715. if (length > 63)
  1716. length = 63;
  1717. buffer[length] = '\0';
  1718. old_pid = (pid_t)str2uint32_t(buffer);
  1719. }
  1720. fclose(fp);
  1721. return old_pid;
  1722. }
  1723. /**
  1724. * Kill previous process
  1725. *
  1726. * Kill previous process whether it was not closed.
  1727. *
  1728. * @param filename is the full name of the file.
  1729. * @param pid that identifies the process
  1730. */
  1731. static void ebpf_kill_previous_process(char *filename, pid_t pid)
  1732. {
  1733. pid_t old_pid = ebpf_read_previous_pid(filename);
  1734. if (!old_pid)
  1735. return;
  1736. // Process is not running
  1737. char *prev_name = ebpf_get_process_name(old_pid);
  1738. if (!prev_name)
  1739. return;
  1740. char *current_name = ebpf_get_process_name(pid);
  1741. if (!strcmp(prev_name, current_name))
  1742. kill(old_pid, SIGKILL);
  1743. freez(prev_name);
  1744. freez(current_name);
  1745. // wait few microseconds before start new plugin
  1746. sleep_usec(USEC_PER_MS * 300);
  1747. }
  1748. /**
  1749. * PID file
  1750. *
  1751. * Write the filename for PID inside the given vector.
  1752. *
  1753. * @param filename vector where we will store the name.
  1754. * @param length number of bytes available in filename vector
  1755. */
  1756. void ebpf_pid_file(char *filename, size_t length)
  1757. {
  1758. snprintfz(filename, length, "%s%s/ebpf.d/ebpf.pid", netdata_configured_host_prefix, ebpf_plugin_dir);
  1759. }
  1760. /**
  1761. * Manage PID
  1762. *
  1763. * This function kills another instance of eBPF whether it is necessary and update the file content.
  1764. *
  1765. * @param pid that identifies the process
  1766. */
  1767. static void ebpf_manage_pid(pid_t pid)
  1768. {
  1769. char filename[FILENAME_MAX + 1];
  1770. ebpf_pid_file(filename, FILENAME_MAX);
  1771. ebpf_kill_previous_process(filename, pid);
  1772. ebpf_update_pid_file(filename, pid);
  1773. }
  1774. /**
  1775. * Set start routine
  1776. *
  1777. * Set static routine before threads to be created.
  1778. */
  1779. static void ebpf_set_static_routine()
  1780. {
  1781. int i;
  1782. for (i = 0; ebpf_modules[i].thread_name; i++) {
  1783. ebpf_threads[i].start_routine = ebpf_modules[i].start_routine;
  1784. }
  1785. }
  1786. /**
  1787. * Entry point
  1788. *
  1789. * @param argc the number of arguments
  1790. * @param argv the pointer to the arguments
  1791. *
  1792. * @return it returns 0 on success and another integer otherwise
  1793. */
  1794. int main(int argc, char **argv)
  1795. {
  1796. clocks_init();
  1797. set_global_variables();
  1798. ebpf_parse_args(argc, argv);
  1799. ebpf_manage_pid(getpid());
  1800. if (!has_condition_to_run(running_on_kernel)) {
  1801. error("The current collector cannot run on this kernel.");
  1802. return 2;
  1803. }
  1804. if (!am_i_running_as_root()) {
  1805. error(
  1806. "ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
  1807. (unsigned int)getuid(), (unsigned int)geteuid());
  1808. return 3;
  1809. }
  1810. // set name
  1811. program_name = "ebpf.plugin";
  1812. // disable syslog
  1813. error_log_syslog = 0;
  1814. // set errors flood protection to 100 logs per hour
  1815. error_log_errors_per_period = 100;
  1816. error_log_throttle_period = 3600;
  1817. struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
  1818. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  1819. error("Setrlimit(RLIMIT_MEMLOCK)");
  1820. return 4;
  1821. }
  1822. signal(SIGINT, ebpf_stop_threads);
  1823. signal(SIGQUIT, ebpf_stop_threads);
  1824. signal(SIGTERM, ebpf_stop_threads);
  1825. signal(SIGPIPE, ebpf_stop_threads);
  1826. if (ebpf_start_pthread_variables()) {
  1827. error("Cannot start mutex to control overall charts.");
  1828. ebpf_exit(5);
  1829. }
  1830. netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
  1831. if(verify_netdata_host_prefix() == -1) ebpf_exit(6);
  1832. ebpf_allocate_common_vectors();
  1833. #ifdef LIBBPF_MAJOR_VERSION
  1834. libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
  1835. #endif
  1836. read_local_addresses();
  1837. read_local_ports("/proc/net/tcp", IPPROTO_TCP);
  1838. read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
  1839. read_local_ports("/proc/net/udp", IPPROTO_UDP);
  1840. read_local_ports("/proc/net/udp6", IPPROTO_UDP);
  1841. ebpf_set_static_routine();
  1842. int i;
  1843. for (i = 0; ebpf_threads[i].name != NULL; i++) {
  1844. struct netdata_static_thread *st = &ebpf_threads[i];
  1845. st->thread = mallocz(sizeof(netdata_thread_t));
  1846. ebpf_module_t *em = &ebpf_modules[i];
  1847. em->thread_id = i;
  1848. netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
  1849. }
  1850. usec_t step = 60 * USEC_PER_SEC;
  1851. heartbeat_t hb;
  1852. heartbeat_init(&hb);
  1853. //Plugin will be killed when it receives a signal
  1854. for (;;) {
  1855. (void)heartbeat_next(&hb, step);
  1856. }
  1857. return 0;
  1858. }