ebpf.c 141 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126
  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 "ebpf_unittest.h"
  8. #include "libnetdata/required_dummies.h"
  9. /*****************************************************************
  10. *
  11. * GLOBAL VARIABLES
  12. *
  13. *****************************************************************/
  14. char *ebpf_plugin_dir = PLUGINS_DIR;
  15. static char *ebpf_configured_log_dir = LOG_DIR;
  16. char *ebpf_algorithms[] = {"absolute", "incremental"};
  17. struct config collector_config = { .first_section = NULL,
  18. .last_section = NULL,
  19. .mutex = NETDATA_MUTEX_INITIALIZER,
  20. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  21. .rwlock = AVL_LOCK_INITIALIZER } };
  22. int running_on_kernel = 0;
  23. int ebpf_nprocs;
  24. int isrh = 0;
  25. int main_thread_id = 0;
  26. int process_pid_fd = -1;
  27. static size_t global_iterations_counter = 1;
  28. bool publish_internal_metrics = true;
  29. pthread_mutex_t lock;
  30. pthread_mutex_t ebpf_exit_cleanup;
  31. pthread_mutex_t collect_data_mutex;
  32. struct netdata_static_thread cgroup_integration_thread = {
  33. .name = "EBPF CGROUP INT",
  34. .config_section = NULL,
  35. .config_name = NULL,
  36. .env_name = NULL,
  37. .enabled = 1,
  38. .thread = NULL,
  39. .init_routine = NULL,
  40. .start_routine = NULL
  41. };
  42. ebpf_module_t ebpf_modules[] = {
  43. { .info = {.thread_name = "process",
  44. .config_name = "process",
  45. .thread_description = NETDATA_EBPF_MODULE_PROCESS_DESC},
  46. .functions = {.start_routine = ebpf_process_thread,
  47. .apps_routine = ebpf_process_create_apps_charts,
  48. .fnct_routine = NULL},
  49. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  50. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  51. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  52. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &process_config,
  53. .config_file = NETDATA_PROCESS_CONFIG_FILE,
  54. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 |
  55. NETDATA_V5_14,
  56. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  57. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0 },
  58. { .info = {.thread_name = "socket",
  59. .config_name = "socket",
  60. .thread_description = NETDATA_EBPF_SOCKET_MODULE_DESC},
  61. .functions = {.start_routine = ebpf_socket_thread,
  62. .apps_routine = ebpf_socket_create_apps_charts,
  63. .fnct_routine = ebpf_socket_read_open_connections,
  64. .fcnt_name = EBPF_FUNCTION_SOCKET,
  65. .fcnt_desc = EBPF_PLUGIN_SOCKET_FUNCTION_DESCRIPTION,
  66. .fcnt_thread_chart_name = NULL,
  67. .fcnt_thread_lifetime_name = NULL},
  68. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  69. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  70. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  71. .maps = NULL,
  72. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &socket_config,
  73. .config_file = NETDATA_NETWORK_CONFIG_FILE,
  74. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  75. .load = EBPF_LOAD_LEGACY, .targets = socket_targets, .probe_links = NULL, .objects = NULL,
  76. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  77. { .info = {.thread_name = "cachestat", .config_name = "cachestat", .thread_description = NETDATA_EBPF_CACHESTAT_MODULE_DESC},
  78. .functions = {.start_routine = ebpf_cachestat_thread,
  79. .apps_routine = ebpf_cachestat_create_apps_charts,
  80. .fnct_routine = NULL},
  81. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  82. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  83. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  84. .maps = cachestat_maps, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &cachestat_config,
  85. .config_file = NETDATA_CACHESTAT_CONFIG_FILE,
  86. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18|
  87. NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16,
  88. .load = EBPF_LOAD_LEGACY, .targets = cachestat_targets, .probe_links = NULL, .objects = NULL,
  89. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  90. { .info = {.thread_name = "sync",
  91. .config_name = "sync",
  92. .thread_description = NETDATA_EBPF_SYNC_MODULE_DESC},
  93. .functions = {.start_routine = ebpf_sync_thread,
  94. .apps_routine = NULL,
  95. .fnct_routine = NULL},
  96. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING, .maps = NULL,
  97. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  98. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  99. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &sync_config,
  100. .config_file = NETDATA_SYNC_CONFIG_FILE,
  101. // All syscalls have the same kernels
  102. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  103. .load = EBPF_LOAD_LEGACY, .targets = sync_targets, .probe_links = NULL, .objects = NULL,
  104. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  105. { .info = {.thread_name = "dc",
  106. .config_name = "dc",
  107. .thread_description = NETDATA_EBPF_DC_MODULE_DESC},
  108. .functions = {.start_routine = ebpf_dcstat_thread,
  109. .apps_routine = ebpf_dcstat_create_apps_charts,
  110. .fnct_routine = NULL},
  111. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  112. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  113. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  114. .maps = dcstat_maps,
  115. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &dcstat_config,
  116. .config_file = NETDATA_DIRECTORY_DCSTAT_CONFIG_FILE,
  117. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  118. .load = EBPF_LOAD_LEGACY, .targets = dc_targets, .probe_links = NULL, .objects = NULL,
  119. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  120. { .info = {.thread_name = "swap", .config_name = "swap", .thread_description = NETDATA_EBPF_SWAP_MODULE_DESC},
  121. .functions = {.start_routine = ebpf_swap_thread,
  122. .apps_routine = ebpf_swap_create_apps_charts,
  123. .fnct_routine = NULL},
  124. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  125. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  126. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  127. .maps = NULL,
  128. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &swap_config,
  129. .config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE,
  130. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  131. .load = EBPF_LOAD_LEGACY, .targets = swap_targets, .probe_links = NULL, .objects = NULL,
  132. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  133. { .info = {.thread_name = "vfs",
  134. .config_name = "vfs",
  135. .thread_description = NETDATA_EBPF_VFS_MODULE_DESC},
  136. .functions = {.start_routine = ebpf_vfs_thread,
  137. .apps_routine = ebpf_vfs_create_apps_charts,
  138. .fnct_routine = NULL},
  139. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  140. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  141. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  142. .maps = NULL,
  143. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &vfs_config,
  144. .config_file = NETDATA_DIRECTORY_VFS_CONFIG_FILE,
  145. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  146. .load = EBPF_LOAD_LEGACY, .targets = vfs_targets, .probe_links = NULL, .objects = NULL,
  147. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  148. { .info = {.thread_name = "filesystem", .config_name = "filesystem", .thread_description = NETDATA_EBPF_FS_MODULE_DESC},
  149. .functions = {.start_routine = ebpf_filesystem_thread,
  150. .apps_routine = NULL,
  151. .fnct_routine = NULL},
  152. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  153. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  154. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  155. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
  156. .config_file = NETDATA_FILESYSTEM_CONFIG_FILE,
  157. //We are setting kernels as zero, because we load eBPF programs according the kernel running.
  158. .kernels = 0, .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  159. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  160. { .info = {.thread_name = "disk",
  161. .config_name = "disk",
  162. .thread_description = NETDATA_EBPF_DISK_MODULE_DESC},
  163. .functions = {.start_routine = ebpf_disk_thread,
  164. .apps_routine = NULL,
  165. .fnct_routine = NULL},
  166. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  167. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  168. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  169. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
  170. .config_file = NETDATA_DISK_CONFIG_FILE,
  171. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  172. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  173. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  174. { .info = {.thread_name = "mount",
  175. .config_name = "mount",
  176. .thread_description = NETDATA_EBPF_MOUNT_MODULE_DESC},
  177. .functions = {.start_routine = ebpf_mount_thread,
  178. .apps_routine = NULL,
  179. .fnct_routine = NULL},
  180. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  181. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  182. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  183. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
  184. .config_file = NETDATA_MOUNT_CONFIG_FILE,
  185. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  186. .load = EBPF_LOAD_LEGACY, .targets = mount_targets, .probe_links = NULL, .objects = NULL,
  187. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  188. { .info = { .thread_name = "fd",
  189. .config_name = "fd",
  190. .thread_description = NETDATA_EBPF_FD_MODULE_DESC},
  191. .functions = {.start_routine = ebpf_fd_thread,
  192. .apps_routine = ebpf_fd_create_apps_charts,
  193. .fnct_routine = NULL},
  194. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  195. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  196. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  197. .maps = NULL,
  198. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fd_config,
  199. .config_file = NETDATA_FD_CONFIG_FILE,
  200. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11 |
  201. NETDATA_V5_14,
  202. .load = EBPF_LOAD_LEGACY, .targets = fd_targets, .probe_links = NULL, .objects = NULL,
  203. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  204. { .info = { .thread_name = "hardirq",
  205. .config_name = "hardirq",
  206. .thread_description = NETDATA_EBPF_HARDIRQ_MODULE_DESC},
  207. .functions = {.start_routine = ebpf_hardirq_thread,
  208. .apps_routine = NULL,
  209. .fnct_routine = NULL},
  210. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  211. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  212. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  213. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &hardirq_config,
  214. .config_file = NETDATA_HARDIRQ_CONFIG_FILE,
  215. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  216. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  217. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  218. { .info = { .thread_name = "softirq",
  219. .config_name = "softirq",
  220. .thread_description = NETDATA_EBPF_SOFTIRQ_MODULE_DESC},
  221. .functions = {.start_routine = ebpf_softirq_thread,
  222. .apps_routine = NULL,
  223. .fnct_routine = NULL },
  224. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  225. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  226. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  227. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &softirq_config,
  228. .config_file = NETDATA_SOFTIRQ_CONFIG_FILE,
  229. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  230. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  231. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  232. { .info = {.thread_name = "oomkill",
  233. .config_name = "oomkill",
  234. .thread_description = NETDATA_EBPF_OOMKILL_MODULE_DESC},
  235. .functions = {.start_routine = ebpf_oomkill_thread,
  236. .apps_routine = ebpf_oomkill_create_apps_charts,
  237. .fnct_routine = NULL},.enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  238. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  239. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  240. .maps = NULL,
  241. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &oomkill_config,
  242. .config_file = NETDATA_OOMKILL_CONFIG_FILE,
  243. .kernels = NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  244. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  245. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  246. { .info = {.thread_name = "shm",
  247. .config_name = "shm",
  248. .thread_description = NETDATA_EBPF_SHM_MODULE_DESC},
  249. .functions = {.start_routine = ebpf_shm_thread,
  250. .apps_routine = ebpf_shm_create_apps_charts,
  251. .fnct_routine = NULL},
  252. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  253. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  254. .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  255. .maps = NULL,
  256. .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
  257. .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
  258. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  259. .load = EBPF_LOAD_LEGACY, .targets = shm_targets, .probe_links = NULL, .objects = NULL,
  260. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  261. { .info = { .thread_name = "mdflush",
  262. .config_name = "mdflush",
  263. .thread_description = NETDATA_EBPF_MD_MODULE_DESC},
  264. .functions = {.start_routine = ebpf_mdflush_thread,
  265. .apps_routine = NULL,
  266. .fnct_routine = NULL},
  267. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING,
  268. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  269. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  270. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
  271. .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE,
  272. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  273. .load = EBPF_LOAD_LEGACY, .targets = mdflush_targets, .probe_links = NULL, .objects = NULL,
  274. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  275. { .info = { .thread_name = "functions",
  276. .config_name = "functions",
  277. .thread_description = NETDATA_EBPF_FUNCTIONS_MODULE_DESC},
  278. .functions = {.start_routine = ebpf_function_thread,
  279. .apps_routine = NULL,
  280. .fnct_routine = NULL},
  281. .enabled = NETDATA_THREAD_EBPF_RUNNING,
  282. .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
  283. .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
  284. .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = NULL,
  285. .config_file = NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE,
  286. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
  287. .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
  288. .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
  289. { .info = {.thread_name = NULL, .config_name = NULL},
  290. .functions = {.start_routine = NULL, .apps_routine = NULL, .fnct_routine = NULL},
  291. .enabled = NETDATA_THREAD_EBPF_NOT_RUNNING, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
  292. .global_charts = 0, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO, .apps_level = NETDATA_APPS_NOT_SET,
  293. .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .maps = NULL,
  294. .pid_map_size = 0, .names = NULL, .cfg = NULL, .kernels = 0, .load = EBPF_LOAD_LEGACY,
  295. .targets = NULL, .probe_links = NULL, .objects = NULL, .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
  296. };
  297. struct netdata_static_thread ebpf_threads[] = {
  298. {
  299. .name = "EBPF PROCESS",
  300. .config_section = NULL,
  301. .config_name = NULL,
  302. .env_name = NULL,
  303. .enabled = 1,
  304. .thread = NULL,
  305. .init_routine = NULL,
  306. .start_routine = NULL
  307. },
  308. {
  309. .name = "EBPF SOCKET",
  310. .config_section = NULL,
  311. .config_name = NULL,
  312. .env_name = NULL,
  313. .enabled = 1,
  314. .thread = NULL,
  315. .init_routine = NULL,
  316. .start_routine = NULL
  317. },
  318. {
  319. .name = "EBPF CACHESTAT",
  320. .config_section = NULL,
  321. .config_name = NULL,
  322. .env_name = NULL,
  323. .enabled = 1,
  324. .thread = NULL,
  325. .init_routine = NULL,
  326. .start_routine = NULL
  327. },
  328. {
  329. .name = "EBPF SYNC",
  330. .config_section = NULL,
  331. .config_name = NULL,
  332. .env_name = NULL,
  333. .enabled = 1,
  334. .thread = NULL,
  335. .init_routine = NULL,
  336. .start_routine = NULL
  337. },
  338. {
  339. .name = "EBPF DCSTAT",
  340. .config_section = NULL,
  341. .config_name = NULL,
  342. .env_name = NULL,
  343. .enabled = 1,
  344. .thread = NULL,
  345. .init_routine = NULL,
  346. .start_routine = NULL
  347. },
  348. {
  349. .name = "EBPF SWAP",
  350. .config_section = NULL,
  351. .config_name = NULL,
  352. .env_name = NULL,
  353. .enabled = 1,
  354. .thread = NULL,
  355. .init_routine = NULL,
  356. .start_routine = NULL
  357. },
  358. {
  359. .name = "EBPF VFS",
  360. .config_section = NULL,
  361. .config_name = NULL,
  362. .env_name = NULL,
  363. .enabled = 1,
  364. .thread = NULL,
  365. .init_routine = NULL,
  366. .start_routine = NULL
  367. },
  368. {
  369. .name = "EBPF FILESYSTEM",
  370. .config_section = NULL,
  371. .config_name = NULL,
  372. .env_name = NULL,
  373. .enabled = 1,
  374. .thread = NULL,
  375. .init_routine = NULL,
  376. .start_routine = NULL
  377. },
  378. {
  379. .name = "EBPF DISK",
  380. .config_section = NULL,
  381. .config_name = NULL,
  382. .env_name = NULL,
  383. .enabled = 1,
  384. .thread = NULL,
  385. .init_routine = NULL,
  386. .start_routine = NULL
  387. },
  388. {
  389. .name = "EBPF MOUNT",
  390. .config_section = NULL,
  391. .config_name = NULL,
  392. .env_name = NULL,
  393. .enabled = 1,
  394. .thread = NULL,
  395. .init_routine = NULL,
  396. .start_routine = NULL
  397. },
  398. {
  399. .name = "EBPF FD",
  400. .config_section = NULL,
  401. .config_name = NULL,
  402. .env_name = NULL,
  403. .enabled = 1,
  404. .thread = NULL,
  405. .init_routine = NULL,
  406. .start_routine = NULL
  407. },
  408. {
  409. .name = "EBPF HARDIRQ",
  410. .config_section = NULL,
  411. .config_name = NULL,
  412. .env_name = NULL,
  413. .enabled = 1,
  414. .thread = NULL,
  415. .init_routine = NULL,
  416. .start_routine = NULL
  417. },
  418. {
  419. .name = "EBPF SOFTIRQ",
  420. .config_section = NULL,
  421. .config_name = NULL,
  422. .env_name = NULL,
  423. .enabled = 1,
  424. .thread = NULL,
  425. .init_routine = NULL,
  426. .start_routine = NULL
  427. },
  428. {
  429. .name = "EBPF OOMKILL",
  430. .config_section = NULL,
  431. .config_name = NULL,
  432. .env_name = NULL,
  433. .enabled = 1,
  434. .thread = NULL,
  435. .init_routine = NULL,
  436. .start_routine = NULL
  437. },
  438. {
  439. .name = "EBPF SHM",
  440. .config_section = NULL,
  441. .config_name = NULL,
  442. .env_name = NULL,
  443. .enabled = 1,
  444. .thread = NULL,
  445. .init_routine = NULL,
  446. .start_routine = NULL
  447. },
  448. {
  449. .name = "EBPF MDFLUSH",
  450. .config_section = NULL,
  451. .config_name = NULL,
  452. .env_name = NULL,
  453. .enabled = 1,
  454. .thread = NULL,
  455. .init_routine = NULL,
  456. .start_routine = NULL
  457. },
  458. {
  459. .name = "EBPF FUNCTIONS",
  460. .config_section = NULL,
  461. .config_name = NULL,
  462. .env_name = NULL,
  463. #ifdef NETDATA_DEV_MODE
  464. .enabled = 1,
  465. #else
  466. .enabled = 0,
  467. #endif
  468. .thread = NULL,
  469. .init_routine = NULL,
  470. .start_routine = NULL
  471. },
  472. {
  473. .name = NULL,
  474. .config_section = NULL,
  475. .config_name = NULL,
  476. .env_name = NULL,
  477. .enabled = 0,
  478. .thread = NULL,
  479. .init_routine = NULL,
  480. .start_routine = NULL
  481. },
  482. };
  483. ebpf_filesystem_partitions_t localfs[] =
  484. {{.filesystem = "ext4",
  485. .optional_filesystem = NULL,
  486. .family = "ext4",
  487. .objects = NULL,
  488. .probe_links = NULL,
  489. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  490. .enabled = CONFIG_BOOLEAN_YES,
  491. .addresses = {.function = NULL, .addr = 0},
  492. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  493. .fs_maps = NULL,
  494. .fs_obj = NULL,
  495. .functions = { "ext4_file_read_iter",
  496. "ext4_file_write_iter",
  497. "ext4_file_open",
  498. "ext4_sync_file",
  499. NULL }},
  500. {.filesystem = "xfs",
  501. .optional_filesystem = NULL,
  502. .family = "xfs",
  503. .objects = NULL,
  504. .probe_links = NULL,
  505. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  506. .enabled = CONFIG_BOOLEAN_YES,
  507. .addresses = {.function = NULL, .addr = 0},
  508. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  509. .fs_maps = NULL,
  510. .fs_obj = NULL,
  511. .functions = { "xfs_file_read_iter",
  512. "xfs_file_write_iter",
  513. "xfs_file_open",
  514. "xfs_file_fsync",
  515. NULL }},
  516. {.filesystem = "nfs",
  517. .optional_filesystem = "nfs4",
  518. .family = "nfs",
  519. .objects = NULL,
  520. .probe_links = NULL,
  521. .flags = NETDATA_FILESYSTEM_ATTR_CHARTS,
  522. .enabled = CONFIG_BOOLEAN_YES,
  523. .addresses = {.function = NULL, .addr = 0},
  524. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  525. .fs_maps = NULL,
  526. .fs_obj = NULL,
  527. .functions = { "nfs_file_read",
  528. "nfs_file_write",
  529. "nfs_open",
  530. "nfs_getattr",
  531. NULL }}, // // "nfs4_file_open" - not present on all kernels
  532. {.filesystem = "zfs",
  533. .optional_filesystem = NULL,
  534. .family = "zfs",
  535. .objects = NULL,
  536. .probe_links = NULL,
  537. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  538. .enabled = CONFIG_BOOLEAN_YES,
  539. .addresses = {.function = NULL, .addr = 0},
  540. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4,
  541. .fs_maps = NULL,
  542. .fs_obj = NULL,
  543. .functions = { "zpl_iter_read",
  544. "zpl_iter_write",
  545. "zpl_open",
  546. "zpl_fsync",
  547. NULL }},
  548. {.filesystem = "btrfs",
  549. .optional_filesystem = NULL,
  550. .family = "btrfs",
  551. .objects = NULL,
  552. .probe_links = NULL,
  553. .flags = NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE,
  554. .enabled = CONFIG_BOOLEAN_YES,
  555. .addresses = {.function = "btrfs_file_operations", .addr = 0},
  556. .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10,
  557. .fs_maps = NULL,
  558. .fs_obj = NULL,
  559. .functions = { "btrfs_file_read_iter",
  560. "btrfs_file_write_iter",
  561. "btrfs_file_open",
  562. "btrfs_sync_file",
  563. NULL }},
  564. {.filesystem = NULL,
  565. .optional_filesystem = NULL,
  566. .family = NULL,
  567. .objects = NULL,
  568. .probe_links = NULL,
  569. .flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION,
  570. .enabled = CONFIG_BOOLEAN_YES,
  571. .addresses = {.function = NULL, .addr = 0},
  572. .kernels = 0, .fs_maps = NULL, .fs_obj = NULL}};
  573. ebpf_sync_syscalls_t local_syscalls[] = {
  574. {.syscall = NETDATA_SYSCALLS_SYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  575. #ifdef LIBBPF_MAJOR_VERSION
  576. .sync_obj = NULL,
  577. #endif
  578. .sync_maps = NULL
  579. },
  580. {.syscall = NETDATA_SYSCALLS_SYNCFS, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  581. #ifdef LIBBPF_MAJOR_VERSION
  582. .sync_obj = NULL,
  583. #endif
  584. .sync_maps = NULL
  585. },
  586. {.syscall = NETDATA_SYSCALLS_MSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  587. #ifdef LIBBPF_MAJOR_VERSION
  588. .sync_obj = NULL,
  589. #endif
  590. .sync_maps = NULL
  591. },
  592. {.syscall = NETDATA_SYSCALLS_FSYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  593. #ifdef LIBBPF_MAJOR_VERSION
  594. .sync_obj = NULL,
  595. #endif
  596. .sync_maps = NULL
  597. },
  598. {.syscall = NETDATA_SYSCALLS_FDATASYNC, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  599. #ifdef LIBBPF_MAJOR_VERSION
  600. .sync_obj = NULL,
  601. #endif
  602. .sync_maps = NULL
  603. },
  604. {.syscall = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .enabled = CONFIG_BOOLEAN_YES, .objects = NULL, .probe_links = NULL,
  605. #ifdef LIBBPF_MAJOR_VERSION
  606. .sync_obj = NULL,
  607. #endif
  608. .sync_maps = NULL
  609. },
  610. {.syscall = NULL, .enabled = CONFIG_BOOLEAN_NO, .objects = NULL, .probe_links = NULL,
  611. #ifdef LIBBPF_MAJOR_VERSION
  612. .sync_obj = NULL,
  613. #endif
  614. .sync_maps = NULL
  615. }
  616. };
  617. // Link with cgroup.plugin
  618. netdata_ebpf_cgroup_shm_t shm_ebpf_cgroup = {NULL, NULL};
  619. int shm_fd_ebpf_cgroup = -1;
  620. sem_t *shm_sem_ebpf_cgroup = SEM_FAILED;
  621. pthread_mutex_t mutex_cgroup_shm;
  622. //Network viewer
  623. ebpf_network_viewer_options_t network_viewer_opt;
  624. // Statistic
  625. ebpf_plugin_stats_t plugin_statistics = {.core = 0, .legacy = 0, .running = 0, .threads = 0, .tracepoints = 0,
  626. .probes = 0, .retprobes = 0, .trampolines = 0, .memlock_kern = 0,
  627. .hash_tables = 0};
  628. netdata_ebpf_judy_pid_t ebpf_judy_pid = {.pid_table = NULL, .index = {.JudyLArray = NULL}};
  629. bool ebpf_plugin_exit = false;
  630. #ifdef LIBBPF_MAJOR_VERSION
  631. struct btf *default_btf = NULL;
  632. struct cachestat_bpf *cachestat_bpf_obj = NULL;
  633. struct dc_bpf *dc_bpf_obj = NULL;
  634. struct disk_bpf *disk_bpf_obj = NULL;
  635. struct fd_bpf *fd_bpf_obj = NULL;
  636. struct hardirq_bpf *hardirq_bpf_obj = NULL;
  637. struct mdflush_bpf *mdflush_bpf_obj = NULL;
  638. struct mount_bpf *mount_bpf_obj = NULL;
  639. struct shm_bpf *shm_bpf_obj = NULL;
  640. struct socket_bpf *socket_bpf_obj = NULL;
  641. struct swap_bpf *bpf_obj = NULL;
  642. struct vfs_bpf *vfs_bpf_obj = NULL;
  643. #else
  644. void *default_btf = NULL;
  645. #endif
  646. char *btf_path = NULL;
  647. /*****************************************************************
  648. *
  649. * FUNCTIONS USED TO MANIPULATE JUDY ARRAY
  650. *
  651. *****************************************************************/
  652. /**
  653. * Hashtable insert unsafe
  654. *
  655. * Find or create a value associated to the index
  656. *
  657. * @return The lsocket = 0 when new item added to the array otherwise the existing item value is returned in *lsocket
  658. * we return a pointer to a pointer, so that the caller can put anything needed at the value of the index.
  659. * The pointer to pointer we return has to be used before any other operation that may change the index (insert/delete).
  660. *
  661. */
  662. void **ebpf_judy_insert_unsafe(PPvoid_t arr, Word_t key)
  663. {
  664. JError_t J_Error;
  665. Pvoid_t *idx = JudyLIns(arr, key, &J_Error);
  666. if (unlikely(idx == PJERR)) {
  667. netdata_log_error("Cannot add PID to JudyL, JU_ERRNO_* == %u, ID == %d",
  668. JU_ERRNO(&J_Error), JU_ERRID(&J_Error));
  669. }
  670. return idx;
  671. }
  672. /**
  673. * Get PID from judy
  674. *
  675. * Get a pointer for the `pid` from judy_array;
  676. *
  677. * @param judy_array a judy array where PID is the primary key
  678. * @param pid pid stored.
  679. */
  680. netdata_ebpf_judy_pid_stats_t *ebpf_get_pid_from_judy_unsafe(PPvoid_t judy_array, uint32_t pid)
  681. {
  682. netdata_ebpf_judy_pid_stats_t **pid_pptr =
  683. (netdata_ebpf_judy_pid_stats_t **)ebpf_judy_insert_unsafe(judy_array, pid);
  684. netdata_ebpf_judy_pid_stats_t *pid_ptr = *pid_pptr;
  685. if (likely(*pid_pptr == NULL)) {
  686. // a new PID added to the index
  687. *pid_pptr = aral_mallocz(ebpf_judy_pid.pid_table);
  688. pid_ptr = *pid_pptr;
  689. pid_ptr->cmdline = NULL;
  690. pid_ptr->socket_stats.JudyLArray = NULL;
  691. rw_spinlock_init(&pid_ptr->socket_stats.rw_spinlock);
  692. }
  693. return pid_ptr;
  694. }
  695. /*****************************************************************
  696. *
  697. * FUNCTIONS USED TO ALLOCATE APPS/CGROUP MEMORIES (ARAL)
  698. *
  699. *****************************************************************/
  700. /**
  701. * Allocate PID ARAL
  702. *
  703. * Allocate memory using ARAL functions to speed up processing.
  704. *
  705. * @param name the internal name used for allocated region.
  706. * @param size size of each element inside allocated space
  707. *
  708. * @return It returns the address on success and NULL otherwise.
  709. */
  710. ARAL *ebpf_allocate_pid_aral(char *name, size_t size)
  711. {
  712. static size_t max_elements = NETDATA_EBPF_ALLOC_MAX_PID;
  713. if (max_elements < NETDATA_EBPF_ALLOC_MIN_ELEMENTS) {
  714. netdata_log_error("Number of elements given is too small, adjusting it for %d", NETDATA_EBPF_ALLOC_MIN_ELEMENTS);
  715. max_elements = NETDATA_EBPF_ALLOC_MIN_ELEMENTS;
  716. }
  717. return aral_create(name, size,
  718. 0, max_elements,
  719. NULL, NULL, NULL, false, false);
  720. }
  721. /*****************************************************************
  722. *
  723. * FUNCTIONS USED TO CLEAN MEMORY AND OPERATE SYSTEM FILES
  724. *
  725. *****************************************************************/
  726. /**
  727. * Wait to avoid possible coredumps while process is closing.
  728. */
  729. static inline void ebpf_check_before2go()
  730. {
  731. int i = EBPF_OPTION_ALL_CHARTS;
  732. usec_t max = USEC_PER_SEC, step = 200000;
  733. while (i && max) {
  734. max -= step;
  735. sleep_usec(step);
  736. i = 0;
  737. int j;
  738. pthread_mutex_lock(&ebpf_exit_cleanup);
  739. for (j = 0; ebpf_modules[j].info.thread_name != NULL; j++) {
  740. if (ebpf_modules[j].enabled < NETDATA_THREAD_EBPF_STOPPING)
  741. i++;
  742. }
  743. pthread_mutex_unlock(&ebpf_exit_cleanup);
  744. }
  745. if (i) {
  746. netdata_log_error("eBPF cannot unload all threads on time, but it will go away");
  747. }
  748. }
  749. /**
  750. * Close the collector gracefully
  751. */
  752. static void ebpf_exit()
  753. {
  754. #ifdef LIBBPF_MAJOR_VERSION
  755. pthread_mutex_lock(&ebpf_exit_cleanup);
  756. if (default_btf) {
  757. btf__free(default_btf);
  758. default_btf = NULL;
  759. }
  760. pthread_mutex_unlock(&ebpf_exit_cleanup);
  761. #endif
  762. char filename[FILENAME_MAX + 1];
  763. ebpf_pid_file(filename, FILENAME_MAX);
  764. if (unlink(filename))
  765. netdata_log_error("Cannot remove PID file %s", filename);
  766. #ifdef NETDATA_INTERNAL_CHECKS
  767. netdata_log_error("Good bye world! I was PID %d", main_thread_id);
  768. #endif
  769. fprintf(stdout, "EXIT\n");
  770. fflush(stdout);
  771. ebpf_check_before2go();
  772. pthread_mutex_lock(&mutex_cgroup_shm);
  773. if (shm_ebpf_cgroup.header) {
  774. ebpf_unmap_cgroup_shared_memory();
  775. shm_unlink(NETDATA_SHARED_MEMORY_EBPF_CGROUP_NAME);
  776. }
  777. pthread_mutex_unlock(&mutex_cgroup_shm);
  778. exit(0);
  779. }
  780. /**
  781. * Unload loegacy code
  782. *
  783. * @param objects objects loaded from eBPF programs
  784. * @param probe_links links from loader
  785. */
  786. void ebpf_unload_legacy_code(struct bpf_object *objects, struct bpf_link **probe_links)
  787. {
  788. if (!probe_links || !objects)
  789. return;
  790. struct bpf_program *prog;
  791. size_t j = 0 ;
  792. bpf_object__for_each_program(prog, objects) {
  793. bpf_link__destroy(probe_links[j]);
  794. j++;
  795. }
  796. freez(probe_links);
  797. if (objects)
  798. bpf_object__close(objects);
  799. }
  800. /**
  801. * Unload Unique maps
  802. *
  803. * This function unload all BPF maps from threads using one unique BPF object.
  804. */
  805. static void ebpf_unload_unique_maps()
  806. {
  807. int i;
  808. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  809. // These threads are cleaned with other functions
  810. if (i != EBPF_MODULE_SOCKET_IDX)
  811. continue;
  812. if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_STOPPED) {
  813. if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_NOT_RUNNING)
  814. netdata_log_error("Cannot unload maps for thread %s, because it is not stopped.",
  815. ebpf_modules[i].info.thread_name);
  816. continue;
  817. }
  818. if (ebpf_modules[i].load == EBPF_LOAD_LEGACY) {
  819. ebpf_unload_legacy_code(ebpf_modules[i].objects, ebpf_modules[i].probe_links);
  820. continue;
  821. }
  822. #ifdef LIBBPF_MAJOR_VERSION
  823. if (socket_bpf_obj)
  824. socket_bpf__destroy(socket_bpf_obj);
  825. #endif
  826. }
  827. }
  828. /**
  829. * Unload filesystem maps
  830. *
  831. * This function unload all BPF maps from filesystem thread.
  832. */
  833. static void ebpf_unload_filesystems()
  834. {
  835. if (ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
  836. ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled < NETDATA_THREAD_EBPF_STOPPING ||
  837. ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].load != EBPF_LOAD_LEGACY)
  838. return;
  839. int i;
  840. for (i = 0; localfs[i].filesystem != NULL; i++) {
  841. if (!localfs[i].objects)
  842. continue;
  843. ebpf_unload_legacy_code(localfs[i].objects, localfs[i].probe_links);
  844. }
  845. }
  846. /**
  847. * Unload sync maps
  848. *
  849. * This function unload all BPF maps from sync thread.
  850. */
  851. static void ebpf_unload_sync()
  852. {
  853. if (ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
  854. ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled < NETDATA_THREAD_EBPF_STOPPING)
  855. return;
  856. int i;
  857. for (i = 0; local_syscalls[i].syscall != NULL; i++) {
  858. if (!local_syscalls[i].enabled)
  859. continue;
  860. #ifdef LIBBPF_MAJOR_VERSION
  861. if (local_syscalls[i].sync_obj) {
  862. sync_bpf__destroy(local_syscalls[i].sync_obj);
  863. continue;
  864. }
  865. #endif
  866. ebpf_unload_legacy_code(local_syscalls[i].objects, local_syscalls[i].probe_links);
  867. }
  868. }
  869. /**
  870. * Close the collector gracefully
  871. *
  872. * @param sig is the signal number used to close the collector
  873. */
  874. void ebpf_stop_threads(int sig)
  875. {
  876. UNUSED(sig);
  877. static int only_one = 0;
  878. // Child thread should be closed by itself.
  879. pthread_mutex_lock(&ebpf_exit_cleanup);
  880. if (main_thread_id != gettid() || only_one) {
  881. pthread_mutex_unlock(&ebpf_exit_cleanup);
  882. return;
  883. }
  884. only_one = 1;
  885. int i;
  886. for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
  887. if (ebpf_modules[i].enabled < NETDATA_THREAD_EBPF_STOPPING) {
  888. netdata_thread_cancel(*ebpf_modules[i].thread->thread);
  889. #ifdef NETDATA_DEV_MODE
  890. netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].info.thread_name);
  891. #endif
  892. }
  893. }
  894. pthread_mutex_unlock(&ebpf_exit_cleanup);
  895. pthread_mutex_lock(&mutex_cgroup_shm);
  896. netdata_thread_cancel(*cgroup_integration_thread.thread);
  897. #ifdef NETDATA_DEV_MODE
  898. netdata_log_info("Sending cancel for thread %s", cgroup_integration_thread.name);
  899. #endif
  900. pthread_mutex_unlock(&mutex_cgroup_shm);
  901. ebpf_plugin_exit = true;
  902. ebpf_check_before2go();
  903. pthread_mutex_lock(&ebpf_exit_cleanup);
  904. ebpf_unload_unique_maps();
  905. ebpf_unload_filesystems();
  906. ebpf_unload_sync();
  907. pthread_mutex_unlock(&ebpf_exit_cleanup);
  908. ebpf_exit();
  909. }
  910. /*****************************************************************
  911. *
  912. * FUNCTIONS TO CREATE CHARTS
  913. *
  914. *****************************************************************/
  915. /**
  916. * Create apps for module
  917. *
  918. * Create apps chart that will be used with specific module
  919. *
  920. * @param em the module main structure.
  921. * @param root a pointer for the targets.
  922. */
  923. static inline void ebpf_create_apps_for_module(ebpf_module_t *em, struct ebpf_target *root) {
  924. if (em->enabled < NETDATA_THREAD_EBPF_STOPPING && em->apps_charts && em->functions.apps_routine)
  925. em->functions.apps_routine(em, root);
  926. }
  927. /**
  928. * Create apps charts
  929. *
  930. * Call ebpf_create_chart to create the charts on apps submenu.
  931. *
  932. * @param root a pointer for the targets.
  933. */
  934. static void ebpf_create_apps_charts(struct ebpf_target *root)
  935. {
  936. if (unlikely(!ebpf_all_pids))
  937. return;
  938. struct ebpf_target *w;
  939. int newly_added = 0;
  940. for (w = root; w; w = w->next) {
  941. if (w->target)
  942. continue;
  943. if (unlikely(w->processes && (debug_enabled || w->debug_enabled))) {
  944. struct ebpf_pid_on_target *pid_on_target;
  945. fprintf(
  946. stderr, "ebpf.plugin: target '%s' has aggregated %u process%s:", w->name, w->processes,
  947. (w->processes == 1) ? "" : "es");
  948. for (pid_on_target = w->root_pid; pid_on_target; pid_on_target = pid_on_target->next) {
  949. fprintf(stderr, " %d", pid_on_target->pid);
  950. }
  951. fputc('\n', stderr);
  952. }
  953. if (!w->exposed && w->processes) {
  954. newly_added++;
  955. w->exposed = 1;
  956. if (debug_enabled || w->debug_enabled)
  957. debug_log_int("%s just added - regenerating charts.", w->name);
  958. }
  959. }
  960. int i;
  961. if (!newly_added) {
  962. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
  963. ebpf_module_t *current = &ebpf_modules[i];
  964. if (current->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
  965. continue;
  966. ebpf_create_apps_for_module(current, root);
  967. }
  968. return;
  969. }
  970. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
  971. ebpf_module_t *current = &ebpf_modules[i];
  972. ebpf_create_apps_for_module(current, root);
  973. }
  974. }
  975. /**
  976. * Get a value from a structure.
  977. *
  978. * @param basis it is the first address of the structure
  979. * @param offset it is the offset of the data you want to access.
  980. * @return
  981. */
  982. collected_number get_value_from_structure(char *basis, size_t offset)
  983. {
  984. collected_number *value = (collected_number *)(basis + offset);
  985. collected_number ret = (collected_number)llabs(*value);
  986. // this reset is necessary to avoid keep a constant value while processing is not executing a task
  987. *value = 0;
  988. return ret;
  989. }
  990. /**
  991. * Write set command on standard output
  992. *
  993. * @param dim the dimension name
  994. * @param value the value for the dimension
  995. */
  996. void write_chart_dimension(char *dim, long long value)
  997. {
  998. printf("SET %s = %lld\n", dim, value);
  999. }
  1000. /**
  1001. * Call the necessary functions to create a chart.
  1002. *
  1003. * @param name the chart name
  1004. * @param family the chart family
  1005. * @param move the pointer with the values that will be published
  1006. * @param end the number of values that will be written on standard output
  1007. *
  1008. * @return It returns a variable that maps the charts that did not have zero values.
  1009. */
  1010. void write_count_chart(char *name, char *family, netdata_publish_syscall_t *move, uint32_t end)
  1011. {
  1012. ebpf_write_begin_chart(family, name, "");
  1013. uint32_t i = 0;
  1014. while (move && i < end) {
  1015. write_chart_dimension(move->name, move->ncall);
  1016. move = move->next;
  1017. i++;
  1018. }
  1019. ebpf_write_end_chart();
  1020. }
  1021. /**
  1022. * Call the necessary functions to create a chart.
  1023. *
  1024. * @param name the chart name
  1025. * @param family the chart family
  1026. * @param move the pointer with the values that will be published
  1027. * @param end the number of values that will be written on standard output
  1028. */
  1029. void write_err_chart(char *name, char *family, netdata_publish_syscall_t *move, int end)
  1030. {
  1031. ebpf_write_begin_chart(family, name, "");
  1032. int i = 0;
  1033. while (move && i < end) {
  1034. write_chart_dimension(move->name, move->nerr);
  1035. move = move->next;
  1036. i++;
  1037. }
  1038. ebpf_write_end_chart();
  1039. }
  1040. /**
  1041. * Write charts
  1042. *
  1043. * Write the current information to publish the charts.
  1044. *
  1045. * @param family chart family
  1046. * @param chart chart id
  1047. * @param dim dimension name
  1048. * @param v1 value.
  1049. */
  1050. void ebpf_one_dimension_write_charts(char *family, char *chart, char *dim, long long v1)
  1051. {
  1052. ebpf_write_begin_chart(family, chart, "");
  1053. write_chart_dimension(dim, v1);
  1054. ebpf_write_end_chart();
  1055. }
  1056. /**
  1057. * Call the necessary functions to create a chart.
  1058. *
  1059. * @param chart the chart name
  1060. * @param family the chart family
  1061. * @param dwrite the dimension name
  1062. * @param vwrite the value for previous dimension
  1063. * @param dread the dimension name
  1064. * @param vread the value for previous dimension
  1065. *
  1066. * @return It returns a variable that maps the charts that did not have zero values.
  1067. */
  1068. void write_io_chart(char *chart, char *family, char *dwrite, long long vwrite, char *dread, long long vread)
  1069. {
  1070. ebpf_write_begin_chart(family, chart, "");
  1071. write_chart_dimension(dwrite, vwrite);
  1072. write_chart_dimension(dread, vread);
  1073. ebpf_write_end_chart();
  1074. }
  1075. /**
  1076. * Write chart cmd on standard output
  1077. *
  1078. * @param type chart type
  1079. * @param id chart id (the apps group name).
  1080. * @param suffix suffix to differentiate charts
  1081. * @param title chart title
  1082. * @param units units label
  1083. * @param family group name used to attach the chart on dashboard
  1084. * @param charttype chart type
  1085. * @param context chart context
  1086. * @param order chart order
  1087. * @param update_every update interval used by plugin
  1088. * @param module chart module name, this is the eBPF thread.
  1089. */
  1090. void ebpf_write_chart_cmd(char *type, char *id, char *suffix, char *title, char *units, char *family,
  1091. char *charttype, char *context, int order, int update_every, char *module)
  1092. {
  1093. printf("CHART %s.%s%s '' '%s' '%s' '%s' '%s' '%s' %d %d '' 'ebpf.plugin' '%s'\n",
  1094. type,
  1095. id,
  1096. suffix,
  1097. title,
  1098. units,
  1099. (family)?family:"",
  1100. (context)?context:"",
  1101. (charttype)?charttype:"",
  1102. order,
  1103. update_every,
  1104. module);
  1105. }
  1106. /**
  1107. * Write chart cmd on standard output
  1108. *
  1109. * @param type chart type
  1110. * @param id chart id
  1111. * @param suffix add suffix to obsolete charts.
  1112. * @param title chart title
  1113. * @param units units label
  1114. * @param family group name used to attach the chart on dashboard
  1115. * @param charttype chart type
  1116. * @param context chart context
  1117. * @param order chart order
  1118. * @param update_every value to overwrite the update frequency set by the server.
  1119. */
  1120. void ebpf_write_chart_obsolete(char *type, char *id, char *suffix, char *title, char *units, char *family,
  1121. char *charttype, char *context, int order, int update_every)
  1122. {
  1123. printf("CHART %s.%s%s '' '%s' '%s' '%s' '%s' '%s' %d %d 'obsolete'\n",
  1124. type,
  1125. id,
  1126. suffix,
  1127. title,
  1128. units,
  1129. (family)?family:"",
  1130. (context)?context:"",
  1131. (charttype)?charttype:"",
  1132. order,
  1133. update_every);
  1134. }
  1135. /**
  1136. * Write the dimension command on standard output
  1137. *
  1138. * @param name the dimension name
  1139. * @param id the dimension id
  1140. * @param algo the dimension algorithm
  1141. */
  1142. void ebpf_write_global_dimension(char *name, char *id, char *algorithm)
  1143. {
  1144. printf("DIMENSION %s %s %s 1 1\n", name, id, algorithm);
  1145. }
  1146. /**
  1147. * Call ebpf_write_global_dimension to create the dimensions for a specific chart
  1148. *
  1149. * @param ptr a pointer to a structure of the type netdata_publish_syscall_t
  1150. * @param end the number of dimensions for the structure ptr
  1151. */
  1152. void ebpf_create_global_dimension(void *ptr, int end)
  1153. {
  1154. netdata_publish_syscall_t *move = ptr;
  1155. int i = 0;
  1156. while (move && i < end) {
  1157. ebpf_write_global_dimension(move->name, move->dimension, move->algorithm);
  1158. move = move->next;
  1159. i++;
  1160. }
  1161. }
  1162. /**
  1163. * Call write_chart_cmd to create the charts
  1164. *
  1165. * @param type chart type
  1166. * @param id chart id
  1167. * @param title chart title
  1168. * @param units axis label
  1169. * @param family group name used to attach the chart on dashboard
  1170. * @param context chart context
  1171. * @param charttype chart type
  1172. * @param order order number of the specified chart
  1173. * @param ncd a pointer to a function called to create dimensions
  1174. * @param move a pointer for a structure that has the dimensions
  1175. * @param end number of dimensions for the chart created
  1176. * @param update_every update interval used with chart.
  1177. * @param module chart module name, this is the eBPF thread.
  1178. */
  1179. void ebpf_create_chart(char *type,
  1180. char *id,
  1181. char *title,
  1182. char *units,
  1183. char *family,
  1184. char *context,
  1185. char *charttype,
  1186. int order,
  1187. void (*ncd)(void *, int),
  1188. void *move,
  1189. int end,
  1190. int update_every,
  1191. char *module)
  1192. {
  1193. ebpf_write_chart_cmd(type, id, "", title, units, family, charttype, context, order, update_every, module);
  1194. if (ncd) {
  1195. ncd(move, end);
  1196. }
  1197. }
  1198. /**
  1199. * Call the necessary functions to create a name.
  1200. *
  1201. * @param family family name
  1202. * @param name chart name
  1203. * @param hist0 histogram values
  1204. * @param dimensions dimension values.
  1205. * @param end number of bins that will be sent to Netdata.
  1206. *
  1207. * @return It returns a variable that maps the charts that did not have zero values.
  1208. */
  1209. void write_histogram_chart(char *family, char *name, const netdata_idx_t *hist, char **dimensions, uint32_t end)
  1210. {
  1211. ebpf_write_begin_chart(family, name, "");
  1212. uint32_t i;
  1213. for (i = 0; i < end; i++) {
  1214. write_chart_dimension(dimensions[i], (long long) hist[i]);
  1215. }
  1216. ebpf_write_end_chart();
  1217. fflush(stdout);
  1218. }
  1219. /**
  1220. * ARAL Charts
  1221. *
  1222. * Add chart to monitor ARAL usage
  1223. * Caller must call this function with mutex locked.
  1224. *
  1225. * @param name the name used to create aral
  1226. * @param em a pointer to the structure with the default values.
  1227. */
  1228. int ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em)
  1229. {
  1230. static int priority = NETATA_EBPF_ORDER_STAT_ARAL_BEGIN;
  1231. char *mem = { NETDATA_EBPF_STAT_DIMENSION_MEMORY };
  1232. char *aral = { NETDATA_EBPF_STAT_DIMENSION_ARAL };
  1233. snprintfz(em->memory_usage, NETDATA_EBPF_CHART_MEM_LENGTH -1, "aral_%s_size", name);
  1234. snprintfz(em->memory_allocations, NETDATA_EBPF_CHART_MEM_LENGTH -1, "aral_%s_alloc", name);
  1235. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  1236. em->memory_usage,
  1237. "",
  1238. "Bytes allocated for ARAL.",
  1239. "bytes",
  1240. NETDATA_EBPF_FAMILY,
  1241. NETDATA_EBPF_CHART_TYPE_STACKED,
  1242. "netdata.ebpf_aral_stat_size",
  1243. priority++,
  1244. em->update_every,
  1245. NETDATA_EBPF_MODULE_NAME_PROCESS);
  1246. ebpf_write_global_dimension(mem,
  1247. mem,
  1248. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  1249. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  1250. em->memory_allocations,
  1251. "",
  1252. "Calls to allocate memory.",
  1253. "calls",
  1254. NETDATA_EBPF_FAMILY,
  1255. NETDATA_EBPF_CHART_TYPE_STACKED,
  1256. "netdata.ebpf_aral_stat_alloc",
  1257. priority++,
  1258. em->update_every,
  1259. NETDATA_EBPF_MODULE_NAME_PROCESS);
  1260. ebpf_write_global_dimension(aral,
  1261. aral,
  1262. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  1263. return priority - 2;
  1264. }
  1265. /**
  1266. * ARAL Charts
  1267. *
  1268. * Add chart to monitor ARAL usage
  1269. * Caller must call this function with mutex locked.
  1270. *
  1271. * @param em a pointer to the structure with the default values.
  1272. * @param prio the initial priority used to disable charts.
  1273. */
  1274. void ebpf_statistic_obsolete_aral_chart(ebpf_module_t *em, int prio)
  1275. {
  1276. ebpf_write_chart_obsolete(NETDATA_MONITORING_FAMILY,
  1277. em->memory_allocations,
  1278. "",
  1279. "Calls to allocate memory.",
  1280. "calls",
  1281. NETDATA_EBPF_FAMILY,
  1282. NETDATA_EBPF_CHART_TYPE_STACKED,
  1283. "netdata.ebpf_aral_stat_alloc",
  1284. prio++,
  1285. em->update_every);
  1286. ebpf_write_chart_obsolete(NETDATA_MONITORING_FAMILY,
  1287. em->memory_allocations,
  1288. "",
  1289. "Calls to allocate memory.",
  1290. "calls",
  1291. NETDATA_EBPF_FAMILY,
  1292. NETDATA_EBPF_CHART_TYPE_STACKED,
  1293. "netdata.ebpf_aral_stat_alloc",
  1294. prio++,
  1295. em->update_every);
  1296. }
  1297. /**
  1298. * Send data from aral chart
  1299. *
  1300. * Send data for eBPF plugin
  1301. *
  1302. * @param memory a pointer to the allocated address
  1303. * @param em a pointer to the structure with the default values.
  1304. */
  1305. void ebpf_send_data_aral_chart(ARAL *memory, ebpf_module_t *em)
  1306. {
  1307. char *mem = { NETDATA_EBPF_STAT_DIMENSION_MEMORY };
  1308. char *aral = { NETDATA_EBPF_STAT_DIMENSION_ARAL };
  1309. struct aral_statistics *stats = aral_statistics(memory);
  1310. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, em->memory_usage, "");
  1311. write_chart_dimension(mem, (long long)stats->structures.allocated_bytes);
  1312. ebpf_write_end_chart();
  1313. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, em->memory_allocations, "");
  1314. write_chart_dimension(aral, (long long)stats->structures.allocations);
  1315. ebpf_write_end_chart();
  1316. }
  1317. /*****************************************************************
  1318. *
  1319. * FUNCTIONS TO READ GLOBAL HASH TABLES
  1320. *
  1321. *****************************************************************/
  1322. /**
  1323. * Read Global Table Stats
  1324. *
  1325. * Read data from specified table (map_fd) using array allocated inside thread(values) and storing
  1326. * them in stats vector starting from the first position.
  1327. *
  1328. * For PID tables is recommended to use a function to parse the specific data.
  1329. *
  1330. * @param stats vector used to store data
  1331. * @param values helper to read data from hash tables.
  1332. * @param map_fd table that has data
  1333. * @param maps_per_core Is necessary to read data from all cores?
  1334. * @param begin initial value to query hash table
  1335. * @param end last value that will not be used.
  1336. */
  1337. void ebpf_read_global_table_stats(netdata_idx_t *stats,
  1338. netdata_idx_t *values,
  1339. int map_fd,
  1340. int maps_per_core,
  1341. uint32_t begin,
  1342. uint32_t end)
  1343. {
  1344. uint32_t idx, order;
  1345. for (idx = begin, order = 0; idx < end; idx++, order++) {
  1346. if (!bpf_map_lookup_elem(map_fd, &idx, values)) {
  1347. int i;
  1348. int before = (maps_per_core) ? ebpf_nprocs: 1;
  1349. netdata_idx_t total = 0;
  1350. for (i = 0; i < before; i++)
  1351. total += values[i];
  1352. stats[order] = total;
  1353. }
  1354. }
  1355. }
  1356. /*****************************************************************
  1357. *
  1358. * FUNCTIONS USED WITH SOCKET
  1359. *
  1360. *****************************************************************/
  1361. /**
  1362. * Netmask
  1363. *
  1364. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1365. *
  1366. * @param prefix create the netmask based in the CIDR value.
  1367. *
  1368. * @return
  1369. */
  1370. static inline in_addr_t ebpf_netmask(int prefix) {
  1371. if (prefix == 0)
  1372. return (~((in_addr_t) - 1));
  1373. else
  1374. return (in_addr_t)(~((1 << (32 - prefix)) - 1));
  1375. }
  1376. /**
  1377. * Broadcast
  1378. *
  1379. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1380. *
  1381. * @param addr is the ip address
  1382. * @param prefix is the CIDR value.
  1383. *
  1384. * @return It returns the last address of the range
  1385. */
  1386. static inline in_addr_t ebpf_broadcast(in_addr_t addr, int prefix)
  1387. {
  1388. return (addr | ~ebpf_netmask(prefix));
  1389. }
  1390. /**
  1391. * Network
  1392. *
  1393. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1394. *
  1395. * @param addr is the ip address
  1396. * @param prefix is the CIDR value.
  1397. *
  1398. * @return It returns the first address of the range.
  1399. */
  1400. static inline in_addr_t ebpf_ipv4_network(in_addr_t addr, int prefix)
  1401. {
  1402. return (addr & ebpf_netmask(prefix));
  1403. }
  1404. /**
  1405. * Calculate ipv6 first address
  1406. *
  1407. * @param out the address to store the first address.
  1408. * @param in the address used to do the math.
  1409. * @param prefix number of bits used to calculate the address
  1410. */
  1411. static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  1412. {
  1413. uint64_t mask,tmp;
  1414. uint64_t ret[2];
  1415. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  1416. if (prefix == 128) {
  1417. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  1418. return;
  1419. } else if (!prefix) {
  1420. ret[0] = ret[1] = 0;
  1421. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1422. return;
  1423. } else if (prefix <= 64) {
  1424. ret[1] = 0ULL;
  1425. tmp = be64toh(ret[0]);
  1426. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  1427. tmp &= mask;
  1428. ret[0] = htobe64(tmp);
  1429. } else {
  1430. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  1431. tmp = be64toh(ret[1]);
  1432. tmp &= mask;
  1433. ret[1] = htobe64(tmp);
  1434. }
  1435. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1436. }
  1437. /**
  1438. * Get IPV6 Last Address
  1439. *
  1440. * @param out the address to store the last address.
  1441. * @param in the address used to do the math.
  1442. * @param prefix number of bits used to calculate the address
  1443. */
  1444. static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  1445. {
  1446. uint64_t mask,tmp;
  1447. uint64_t ret[2];
  1448. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  1449. if (prefix == 128) {
  1450. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  1451. return;
  1452. } else if (!prefix) {
  1453. ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF;
  1454. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1455. return;
  1456. } else if (prefix <= 64) {
  1457. ret[1] = 0xFFFFFFFFFFFFFFFFULL;
  1458. tmp = be64toh(ret[0]);
  1459. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  1460. tmp |= ~mask;
  1461. ret[0] = htobe64(tmp);
  1462. } else {
  1463. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  1464. tmp = be64toh(ret[1]);
  1465. tmp |= ~mask;
  1466. ret[1] = htobe64(tmp);
  1467. }
  1468. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1469. }
  1470. /**
  1471. * IP to network long
  1472. *
  1473. * @param dst the vector to store the result
  1474. * @param ip the source ip given by our users.
  1475. * @param domain the ip domain (IPV4 or IPV6)
  1476. * @param source the original string
  1477. *
  1478. * @return it returns 0 on success and -1 otherwise.
  1479. */
  1480. static inline int ebpf_ip2nl(uint8_t *dst, char *ip, int domain, char *source)
  1481. {
  1482. if (inet_pton(domain, ip, dst) <= 0) {
  1483. netdata_log_error("The address specified (%s) is invalid ", source);
  1484. return -1;
  1485. }
  1486. return 0;
  1487. }
  1488. /**
  1489. * Clean port Structure
  1490. *
  1491. * Clean the allocated list.
  1492. *
  1493. * @param clean the list that will be cleaned
  1494. */
  1495. void ebpf_clean_port_structure(ebpf_network_viewer_port_list_t **clean)
  1496. {
  1497. ebpf_network_viewer_port_list_t *move = *clean;
  1498. while (move) {
  1499. ebpf_network_viewer_port_list_t *next = move->next;
  1500. freez(move->value);
  1501. freez(move);
  1502. move = next;
  1503. }
  1504. *clean = NULL;
  1505. }
  1506. /**
  1507. * Clean IP structure
  1508. *
  1509. * Clean the allocated list.
  1510. *
  1511. * @param clean the list that will be cleaned
  1512. */
  1513. void ebpf_clean_ip_structure(ebpf_network_viewer_ip_list_t **clean)
  1514. {
  1515. ebpf_network_viewer_ip_list_t *move = *clean;
  1516. while (move) {
  1517. ebpf_network_viewer_ip_list_t *next = move->next;
  1518. freez(move->value);
  1519. freez(move);
  1520. move = next;
  1521. }
  1522. *clean = NULL;
  1523. }
  1524. /**
  1525. * Parse IP List
  1526. *
  1527. * Parse IP list and link it.
  1528. *
  1529. * @param out a pointer to store the link list
  1530. * @param ip the value given as parameter
  1531. */
  1532. static void ebpf_parse_ip_list_unsafe(void **out, char *ip)
  1533. {
  1534. ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out;
  1535. char *ipdup = strdupz(ip);
  1536. union netdata_ip_t first = { };
  1537. union netdata_ip_t last = { };
  1538. char *is_ipv6;
  1539. if (*ip == '*' && *(ip+1) == '\0') {
  1540. memset(first.addr8, 0, sizeof(first.addr8));
  1541. memset(last.addr8, 0xFF, sizeof(last.addr8));
  1542. is_ipv6 = ip;
  1543. ebpf_clean_ip_structure(list);
  1544. goto storethisip;
  1545. }
  1546. char *end = ip;
  1547. // Move while I cannot find a separator
  1548. while (*end && *end != '/' && *end != '-') end++;
  1549. // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future
  1550. // https://tools.ietf.org/html/rfc1924
  1551. is_ipv6 = strchr(ip, ':');
  1552. int select;
  1553. if (*end && !is_ipv6) { // IPV4 range
  1554. select = (*end == '/') ? 0 : 1;
  1555. *end++ = '\0';
  1556. if (*end == '!') {
  1557. netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  1558. goto cleanipdup;
  1559. }
  1560. if (!select) { // CIDR
  1561. select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
  1562. if (select)
  1563. goto cleanipdup;
  1564. select = (int) str2i(end);
  1565. if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) {
  1566. netdata_log_info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip);
  1567. goto cleanipdup;
  1568. }
  1569. last.addr32[0] = htonl(ebpf_broadcast(ntohl(first.addr32[0]), select));
  1570. // This was added to remove
  1571. // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977
  1572. UNUSED(last.addr32[0]);
  1573. uint32_t ipv4_test = htonl(ebpf_ipv4_network(ntohl(first.addr32[0]), select));
  1574. if (first.addr32[0] != ipv4_test) {
  1575. first.addr32[0] = ipv4_test;
  1576. struct in_addr ipv4_convert;
  1577. ipv4_convert.s_addr = ipv4_test;
  1578. char ipv4_msg[INET_ADDRSTRLEN];
  1579. if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN))
  1580. netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg);
  1581. }
  1582. } else { // Range
  1583. select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
  1584. if (select)
  1585. goto cleanipdup;
  1586. select = ebpf_ip2nl(last.addr8, end, AF_INET, ipdup);
  1587. if (select)
  1588. goto cleanipdup;
  1589. }
  1590. if (htonl(first.addr32[0]) > htonl(last.addr32[0])) {
  1591. netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  1592. ipdup);
  1593. goto cleanipdup;
  1594. }
  1595. } else if (is_ipv6) { // IPV6
  1596. if (!*end) { // Unique
  1597. select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
  1598. if (select)
  1599. goto cleanipdup;
  1600. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  1601. } else if (*end == '-') {
  1602. *end++ = 0x00;
  1603. if (*end == '!') {
  1604. netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  1605. goto cleanipdup;
  1606. }
  1607. select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
  1608. if (select)
  1609. goto cleanipdup;
  1610. select = ebpf_ip2nl(last.addr8, end, AF_INET6, ipdup);
  1611. if (select)
  1612. goto cleanipdup;
  1613. } else { // CIDR
  1614. *end++ = 0x00;
  1615. if (*end == '!') {
  1616. netdata_log_info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  1617. goto cleanipdup;
  1618. }
  1619. select = str2i(end);
  1620. if (select < 0 || select > 128) {
  1621. netdata_log_info("The CIDR %s is not valid, the address %s will be ignored.", end, ip);
  1622. goto cleanipdup;
  1623. }
  1624. uint64_t prefix = (uint64_t)select;
  1625. select = ebpf_ip2nl(first.addr8, ip, AF_INET6, ipdup);
  1626. if (select)
  1627. goto cleanipdup;
  1628. get_ipv6_last_addr(&last, &first, prefix);
  1629. union netdata_ip_t ipv6_test;
  1630. get_ipv6_first_addr(&ipv6_test, &first, prefix);
  1631. if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) {
  1632. memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t));
  1633. struct in6_addr ipv6_convert;
  1634. memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t));
  1635. char ipv6_msg[INET6_ADDRSTRLEN];
  1636. if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN))
  1637. netdata_log_info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg);
  1638. }
  1639. }
  1640. if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) &&
  1641. !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) ||
  1642. (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) {
  1643. netdata_log_info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  1644. ipdup);
  1645. goto cleanipdup;
  1646. }
  1647. } else { // Unique ip
  1648. select = ebpf_ip2nl(first.addr8, ip, AF_INET, ipdup);
  1649. if (select)
  1650. goto cleanipdup;
  1651. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  1652. }
  1653. ebpf_network_viewer_ip_list_t *store;
  1654. storethisip:
  1655. store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
  1656. store->value = ipdup;
  1657. store->hash = simple_hash(ipdup);
  1658. store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6;
  1659. memcpy(store->first.addr8, first.addr8, sizeof(first.addr8));
  1660. memcpy(store->last.addr8, last.addr8, sizeof(last.addr8));
  1661. ebpf_fill_ip_list_unsafe(list, store, "socket");
  1662. return;
  1663. cleanipdup:
  1664. freez(ipdup);
  1665. }
  1666. /**
  1667. * Parse IP Range
  1668. *
  1669. * Parse the IP ranges given and create Network Viewer IP Structure
  1670. *
  1671. * @param ptr is a pointer with the text to parse.
  1672. */
  1673. void ebpf_parse_ips_unsafe(char *ptr)
  1674. {
  1675. // No value
  1676. if (unlikely(!ptr))
  1677. return;
  1678. while (likely(ptr)) {
  1679. // Move forward until next valid character
  1680. while (isspace(*ptr)) ptr++;
  1681. // No valid value found
  1682. if (unlikely(!*ptr))
  1683. return;
  1684. // Find space that ends the list
  1685. char *end = strchr(ptr, ' ');
  1686. if (end) {
  1687. *end++ = '\0';
  1688. }
  1689. int neg = 0;
  1690. if (*ptr == '!') {
  1691. neg++;
  1692. ptr++;
  1693. }
  1694. if (isascii(*ptr)) { // Parse port
  1695. ebpf_parse_ip_list_unsafe(
  1696. (!neg) ? (void **)&network_viewer_opt.included_ips : (void **)&network_viewer_opt.excluded_ips, ptr);
  1697. }
  1698. ptr = end;
  1699. }
  1700. }
  1701. /**
  1702. * Fill Port list
  1703. *
  1704. * @param out a pointer to the link list.
  1705. * @param in the structure that will be linked.
  1706. */
  1707. static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in)
  1708. {
  1709. if (likely(*out)) {
  1710. ebpf_network_viewer_port_list_t *move = *out, *store = *out;
  1711. uint16_t first = ntohs(in->first);
  1712. uint16_t last = ntohs(in->last);
  1713. while (move) {
  1714. uint16_t cmp_first = ntohs(move->first);
  1715. uint16_t cmp_last = ntohs(move->last);
  1716. if (cmp_first <= first && first <= cmp_last &&
  1717. cmp_first <= last && last <= cmp_last ) {
  1718. netdata_log_info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.",
  1719. first, last, cmp_first, cmp_last);
  1720. freez(in->value);
  1721. freez(in);
  1722. return;
  1723. } else if (first <= cmp_first && cmp_first <= last &&
  1724. first <= cmp_last && cmp_last <= last) {
  1725. netdata_log_info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.",
  1726. first, last, cmp_first, cmp_last);
  1727. freez(move->value);
  1728. move->value = in->value;
  1729. move->first = in->first;
  1730. move->last = in->last;
  1731. freez(in);
  1732. return;
  1733. }
  1734. store = move;
  1735. move = move->next;
  1736. }
  1737. store->next = in;
  1738. } else {
  1739. *out = in;
  1740. }
  1741. #ifdef NETDATA_INTERNAL_CHECKS
  1742. netdata_log_info("Adding values %s( %u, %u) to %s port list used on network viewer",
  1743. in->value, in->first, in->last,
  1744. (*out == network_viewer_opt.included_port)?"included":"excluded");
  1745. #endif
  1746. }
  1747. /**
  1748. * Parse Service List
  1749. *
  1750. * @param out a pointer to store the link list
  1751. * @param service the service used to create the structure that will be linked.
  1752. */
  1753. static void ebpf_parse_service_list(void **out, char *service)
  1754. {
  1755. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  1756. struct servent *serv = getservbyname((const char *)service, "tcp");
  1757. if (!serv)
  1758. serv = getservbyname((const char *)service, "udp");
  1759. if (!serv) {
  1760. netdata_log_info("Cannot resolve the service '%s' with protocols TCP and UDP, it will be ignored", service);
  1761. return;
  1762. }
  1763. ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1764. w->value = strdupz(service);
  1765. w->hash = simple_hash(service);
  1766. w->first = w->last = (uint16_t)serv->s_port;
  1767. fill_port_list(list, w);
  1768. }
  1769. /**
  1770. * Parse port list
  1771. *
  1772. * Parse an allocated port list with the range given
  1773. *
  1774. * @param out a pointer to store the link list
  1775. * @param range the informed range for the user.
  1776. */
  1777. static void ebpf_parse_port_list(void **out, char *range)
  1778. {
  1779. int first, last;
  1780. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  1781. char *copied = strdupz(range);
  1782. if (*range == '*' && *(range+1) == '\0') {
  1783. first = 1;
  1784. last = 65535;
  1785. ebpf_clean_port_structure(list);
  1786. goto fillenvpl;
  1787. }
  1788. char *end = range;
  1789. //Move while I cannot find a separator
  1790. while (*end && *end != ':' && *end != '-') end++;
  1791. //It has a range
  1792. if (likely(*end)) {
  1793. *end++ = '\0';
  1794. if (*end == '!') {
  1795. netdata_log_info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
  1796. freez(copied);
  1797. return;
  1798. }
  1799. last = str2i((const char *)end);
  1800. } else {
  1801. last = 0;
  1802. }
  1803. first = str2i((const char *)range);
  1804. if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
  1805. netdata_log_info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
  1806. freez(copied);
  1807. return;
  1808. }
  1809. if (!last)
  1810. last = first;
  1811. if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) {
  1812. netdata_log_info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
  1813. freez(copied);
  1814. return;
  1815. }
  1816. if (first > last) {
  1817. netdata_log_info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
  1818. freez(copied);
  1819. return;
  1820. }
  1821. ebpf_network_viewer_port_list_t *w;
  1822. fillenvpl:
  1823. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1824. w->value = copied;
  1825. w->hash = simple_hash(copied);
  1826. w->first = (uint16_t)first;
  1827. w->last = (uint16_t)last;
  1828. w->cmp_first = (uint16_t)first;
  1829. w->cmp_last = (uint16_t)last;
  1830. fill_port_list(list, w);
  1831. }
  1832. /**
  1833. * Parse Port Range
  1834. *
  1835. * Parse the port ranges given and create Network Viewer Port Structure
  1836. *
  1837. * @param ptr is a pointer with the text to parse.
  1838. */
  1839. void ebpf_parse_ports(char *ptr)
  1840. {
  1841. // No value
  1842. if (unlikely(!ptr))
  1843. return;
  1844. while (likely(ptr)) {
  1845. // Move forward until next valid character
  1846. while (isspace(*ptr)) ptr++;
  1847. // No valid value found
  1848. if (unlikely(!*ptr))
  1849. return;
  1850. // Find space that ends the list
  1851. char *end = strchr(ptr, ' ');
  1852. if (end) {
  1853. *end++ = '\0';
  1854. }
  1855. int neg = 0;
  1856. if (*ptr == '!') {
  1857. neg++;
  1858. ptr++;
  1859. }
  1860. if (isdigit(*ptr)) { // Parse port
  1861. ebpf_parse_port_list(
  1862. (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
  1863. } else if (isalpha(*ptr)) { // Parse service
  1864. ebpf_parse_service_list(
  1865. (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
  1866. } else if (*ptr == '*') { // All
  1867. ebpf_parse_port_list(
  1868. (!neg) ? (void **)&network_viewer_opt.included_port : (void **)&network_viewer_opt.excluded_port, ptr);
  1869. }
  1870. ptr = end;
  1871. }
  1872. }
  1873. /*****************************************************************
  1874. *
  1875. * FUNCTIONS TO DEFINE OPTIONS
  1876. *
  1877. *****************************************************************/
  1878. /**
  1879. * Define labels used to generate charts
  1880. *
  1881. * @param is structure with information about number of calls made for a function.
  1882. * @param pio structure used to generate charts.
  1883. * @param dim a pointer for the dimensions name
  1884. * @param name a pointer for the tensor with the name of the functions.
  1885. * @param algorithm a vector with the algorithms used to make the charts
  1886. * @param end the number of elements in the previous 4 arguments.
  1887. */
  1888. void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *pio, char **dim,
  1889. char **name, int *algorithm, int end)
  1890. {
  1891. int i;
  1892. netdata_syscall_stat_t *prev = NULL;
  1893. netdata_publish_syscall_t *publish_prev = NULL;
  1894. for (i = 0; i < end; i++) {
  1895. if (prev) {
  1896. prev->next = &is[i];
  1897. }
  1898. prev = &is[i];
  1899. pio[i].dimension = dim[i];
  1900. pio[i].name = name[i];
  1901. pio[i].algorithm = ebpf_algorithms[algorithm[i]];
  1902. if (publish_prev) {
  1903. publish_prev->next = &pio[i];
  1904. }
  1905. publish_prev = &pio[i];
  1906. }
  1907. }
  1908. /**
  1909. * Define thread mode for all ebpf program.
  1910. *
  1911. * @param lmode the mode that will be used for them.
  1912. */
  1913. static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode)
  1914. {
  1915. int i;
  1916. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  1917. ebpf_modules[i].mode = lmode;
  1918. }
  1919. }
  1920. /**
  1921. * Enable specific charts selected by user.
  1922. *
  1923. * @param em the structure that will be changed
  1924. * @param disable_cgroup the status about the cgroups charts.
  1925. */
  1926. static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disable_cgroup)
  1927. {
  1928. em->enabled = NETDATA_THREAD_EBPF_RUNNING;
  1929. if (!disable_cgroup) {
  1930. em->cgroup_charts = CONFIG_BOOLEAN_YES;
  1931. }
  1932. em->global_charts = CONFIG_BOOLEAN_YES;
  1933. }
  1934. /**
  1935. * Disable all Global charts
  1936. *
  1937. * Disable charts
  1938. */
  1939. static inline void disable_all_global_charts()
  1940. {
  1941. int i;
  1942. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  1943. ebpf_modules[i].enabled = NETDATA_THREAD_EBPF_NOT_RUNNING;
  1944. ebpf_modules[i].global_charts = 0;
  1945. }
  1946. }
  1947. /**
  1948. * Enable the specified chart group
  1949. *
  1950. * @param idx the index of ebpf_modules that I am enabling
  1951. */
  1952. static inline void ebpf_enable_chart(int idx, int disable_cgroup)
  1953. {
  1954. int i;
  1955. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  1956. if (i == idx) {
  1957. ebpf_enable_specific_chart(&ebpf_modules[i], disable_cgroup);
  1958. break;
  1959. }
  1960. }
  1961. }
  1962. /**
  1963. * Disable Cgroups
  1964. *
  1965. * Disable charts for apps loading only global charts.
  1966. */
  1967. static inline void ebpf_disable_cgroups()
  1968. {
  1969. int i;
  1970. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  1971. ebpf_modules[i].cgroup_charts = 0;
  1972. }
  1973. }
  1974. /**
  1975. * Update Disabled Plugins
  1976. *
  1977. * This function calls ebpf_update_stats to update statistics for collector.
  1978. *
  1979. * @param em a pointer to `struct ebpf_module`
  1980. */
  1981. void ebpf_update_disabled_plugin_stats(ebpf_module_t *em)
  1982. {
  1983. pthread_mutex_lock(&lock);
  1984. ebpf_update_stats(&plugin_statistics, em);
  1985. pthread_mutex_unlock(&lock);
  1986. }
  1987. /**
  1988. * Print help on standard error for user knows how to use the collector.
  1989. */
  1990. void ebpf_print_help()
  1991. {
  1992. const time_t t = time(NULL);
  1993. struct tm ct;
  1994. struct tm *test = localtime_r(&t, &ct);
  1995. int year;
  1996. if (test)
  1997. year = ct.tm_year;
  1998. else
  1999. year = 0;
  2000. fprintf(stderr,
  2001. "\n"
  2002. " Netdata ebpf.plugin %s\n"
  2003. " Copyright (C) 2016-%d Costa Tsaousis <costa@tsaousis.gr>\n"
  2004. " Released under GNU General Public License v3 or later.\n"
  2005. " All rights reserved.\n"
  2006. "\n"
  2007. " This eBPF.plugin is a data collector plugin for netdata.\n"
  2008. "\n"
  2009. " This plugin only accepts long options with one or two dashes. The available command line options are:\n"
  2010. "\n"
  2011. " SECONDS Set the data collection frequency.\n"
  2012. "\n"
  2013. " [-]-help Show this help.\n"
  2014. "\n"
  2015. " [-]-version Show software version.\n"
  2016. "\n"
  2017. " [-]-global Disable charts per application and cgroup.\n"
  2018. "\n"
  2019. " [-]-all Enable all chart groups (global, apps, and cgroup), unless -g is also given.\n"
  2020. "\n"
  2021. " [-]-cachestat Enable charts related to process run time.\n"
  2022. "\n"
  2023. " [-]-dcstat Enable charts related to directory cache.\n"
  2024. "\n"
  2025. " [-]-disk Enable charts related to disk monitoring.\n"
  2026. "\n"
  2027. " [-]-filesystem Enable chart related to filesystem run time.\n"
  2028. "\n"
  2029. " [-]-hardirq Enable chart related to hard IRQ latency.\n"
  2030. "\n"
  2031. " [-]-mdflush Enable charts related to multi-device flush.\n"
  2032. "\n"
  2033. " [-]-mount Enable charts related to mount monitoring.\n"
  2034. "\n"
  2035. " [-]-net Enable network viewer charts.\n"
  2036. "\n"
  2037. " [-]-oomkill Enable chart related to OOM kill tracking.\n"
  2038. "\n"
  2039. " [-]-process Enable charts related to process run time.\n"
  2040. "\n"
  2041. " [-]-return Run the collector in return mode.\n"
  2042. "\n"
  2043. " [-]-shm Enable chart related to shared memory tracking.\n"
  2044. "\n"
  2045. " [-]-softirq Enable chart related to soft IRQ latency.\n"
  2046. "\n"
  2047. " [-]-sync Enable chart related to sync run time.\n"
  2048. "\n"
  2049. " [-]-swap Enable chart related to swap run time.\n"
  2050. "\n"
  2051. " [-]-vfs Enable chart related to vfs run time.\n"
  2052. "\n"
  2053. " [-]-legacy Load legacy eBPF programs.\n"
  2054. "\n"
  2055. " [-]-core Use CO-RE when available(Working in progress).\n"
  2056. "\n",
  2057. VERSION,
  2058. (year >= 116) ? year + 1900 : 2020);
  2059. }
  2060. /*****************************************************************
  2061. *
  2062. * TRACEPOINT MANAGEMENT FUNCTIONS
  2063. *
  2064. *****************************************************************/
  2065. /**
  2066. * Enable a tracepoint.
  2067. *
  2068. * @return 0 on success, -1 on error.
  2069. */
  2070. int ebpf_enable_tracepoint(ebpf_tracepoint_t *tp)
  2071. {
  2072. int test = ebpf_is_tracepoint_enabled(tp->class, tp->event);
  2073. // err?
  2074. if (test == -1) {
  2075. return -1;
  2076. }
  2077. // disabled?
  2078. else if (test == 0) {
  2079. // enable it then.
  2080. if (ebpf_enable_tracing_values(tp->class, tp->event)) {
  2081. return -1;
  2082. }
  2083. }
  2084. // enabled now or already was.
  2085. tp->enabled = true;
  2086. return 0;
  2087. }
  2088. /**
  2089. * Disable a tracepoint if it's enabled.
  2090. *
  2091. * @return 0 on success, -1 on error.
  2092. */
  2093. int ebpf_disable_tracepoint(ebpf_tracepoint_t *tp)
  2094. {
  2095. int test = ebpf_is_tracepoint_enabled(tp->class, tp->event);
  2096. // err?
  2097. if (test == -1) {
  2098. return -1;
  2099. }
  2100. // enabled?
  2101. else if (test == 1) {
  2102. // disable it then.
  2103. if (ebpf_disable_tracing_values(tp->class, tp->event)) {
  2104. return -1;
  2105. }
  2106. }
  2107. // disable now or already was.
  2108. tp->enabled = false;
  2109. return 0;
  2110. }
  2111. /**
  2112. * Enable multiple tracepoints on a list of tracepoints which end when the
  2113. * class is NULL.
  2114. *
  2115. * @return the number of successful enables.
  2116. */
  2117. uint32_t ebpf_enable_tracepoints(ebpf_tracepoint_t *tps)
  2118. {
  2119. uint32_t cnt = 0;
  2120. for (int i = 0; tps[i].class != NULL; i++) {
  2121. if (ebpf_enable_tracepoint(&tps[i]) == -1) {
  2122. netdata_log_error("Failed to enable tracepoint %s:%s", tps[i].class, tps[i].event);
  2123. }
  2124. else {
  2125. cnt += 1;
  2126. }
  2127. }
  2128. return cnt;
  2129. }
  2130. /*****************************************************************
  2131. *
  2132. * AUXILIARY FUNCTIONS USED DURING INITIALIZATION
  2133. *
  2134. *****************************************************************/
  2135. /**
  2136. * Is ip inside the range
  2137. *
  2138. * Check if the ip is inside a IP range
  2139. *
  2140. * @param rfirst the first ip address of the range
  2141. * @param rlast the last ip address of the range
  2142. * @param cmpfirst the first ip to compare
  2143. * @param cmplast the last ip to compare
  2144. * @param family the IP family
  2145. *
  2146. * @return It returns 1 if the IP is inside the range and 0 otherwise
  2147. */
  2148. static int ebpf_is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast,
  2149. union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family)
  2150. {
  2151. if (family == AF_INET) {
  2152. if ((rfirst->addr32[0] <= cmpfirst->addr32[0]) && (rlast->addr32[0] >= cmplast->addr32[0]))
  2153. return 1;
  2154. } else {
  2155. if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  2156. memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) {
  2157. return 1;
  2158. }
  2159. }
  2160. return 0;
  2161. }
  2162. /**
  2163. * Fill IP list
  2164. *
  2165. * @param out a pointer to the link list.
  2166. * @param in the structure that will be linked.
  2167. * @param table the modified table.
  2168. */
  2169. void ebpf_fill_ip_list_unsafe(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in,
  2170. char *table __maybe_unused)
  2171. {
  2172. if (in->ver == AF_INET) { // It is simpler to compare using host order
  2173. in->first.addr32[0] = ntohl(in->first.addr32[0]);
  2174. in->last.addr32[0] = ntohl(in->last.addr32[0]);
  2175. }
  2176. if (likely(*out)) {
  2177. ebpf_network_viewer_ip_list_t *move = *out, *store = *out;
  2178. while (move) {
  2179. if (in->ver == move->ver &&
  2180. ebpf_is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) {
  2181. #ifdef NETDATA_DEV_MODE
  2182. netdata_log_info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.",
  2183. in->value, move->value);
  2184. #endif
  2185. freez(in->value);
  2186. freez(in);
  2187. return;
  2188. }
  2189. store = move;
  2190. move = move->next;
  2191. }
  2192. store->next = in;
  2193. } else {
  2194. *out = in;
  2195. }
  2196. #ifdef NETDATA_DEV_MODE
  2197. char first[256], last[512];
  2198. if (in->ver == AF_INET) {
  2199. netdata_log_info("Adding values %s: (%u - %u) to %s IP list \"%s\" used on network viewer",
  2200. in->value, in->first.addr32[0], in->last.addr32[0],
  2201. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  2202. table);
  2203. } else {
  2204. if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) &&
  2205. inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN))
  2206. netdata_log_info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
  2207. first, last,
  2208. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  2209. table);
  2210. }
  2211. #endif
  2212. }
  2213. /**
  2214. * Link hostname
  2215. *
  2216. * @param out is the output link list
  2217. * @param in the hostname to add to list.
  2218. */
  2219. static void ebpf_link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in)
  2220. {
  2221. if (likely(*out)) {
  2222. ebpf_network_viewer_hostname_list_t *move = *out;
  2223. for (; move->next ; move = move->next ) {
  2224. if (move->hash == in->hash && !strcmp(move->value, in->value)) {
  2225. netdata_log_info("The hostname %s was already inserted, it will be ignored.", in->value);
  2226. freez(in->value);
  2227. simple_pattern_free(in->value_pattern);
  2228. freez(in);
  2229. return;
  2230. }
  2231. }
  2232. move->next = in;
  2233. } else {
  2234. *out = in;
  2235. }
  2236. #ifdef NETDATA_INTERNAL_CHECKS
  2237. netdata_log_info("Adding value %s to %s hostname list used on network viewer",
  2238. in->value,
  2239. (*out == network_viewer_opt.included_hostnames)?"included":"excluded");
  2240. #endif
  2241. }
  2242. /**
  2243. * Link Hostnames
  2244. *
  2245. * Parse the list of hostnames to create the link list.
  2246. * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP.
  2247. *
  2248. * @param out is the output link list
  2249. * @param parse is a pointer with the text to parser.
  2250. */
  2251. static void ebpf_link_hostnames(char *parse)
  2252. {
  2253. // No value
  2254. if (unlikely(!parse))
  2255. return;
  2256. while (likely(parse)) {
  2257. // Find the first valid value
  2258. while (isspace(*parse)) parse++;
  2259. // No valid value found
  2260. if (unlikely(!*parse))
  2261. return;
  2262. // Find space that ends the list
  2263. char *end = strchr(parse, ' ');
  2264. if (end) {
  2265. *end++ = '\0';
  2266. }
  2267. int neg = 0;
  2268. if (*parse == '!') {
  2269. neg++;
  2270. parse++;
  2271. }
  2272. ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t));
  2273. hostname->value = strdupz(parse);
  2274. hostname->hash = simple_hash(parse);
  2275. hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT, true);
  2276. ebpf_link_hostname((!neg) ? &network_viewer_opt.included_hostnames :
  2277. &network_viewer_opt.excluded_hostnames,
  2278. hostname);
  2279. parse = end;
  2280. }
  2281. }
  2282. /**
  2283. * Parse network viewer section
  2284. *
  2285. * @param cfg the configuration structure
  2286. */
  2287. void parse_network_viewer_section(struct config *cfg)
  2288. {
  2289. network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(cfg,
  2290. EBPF_NETWORK_VIEWER_SECTION,
  2291. EBPF_CONFIG_RESOLVE_HOSTNAME,
  2292. CONFIG_BOOLEAN_NO);
  2293. network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(cfg,
  2294. EBPF_NETWORK_VIEWER_SECTION,
  2295. EBPF_CONFIG_RESOLVE_SERVICE,
  2296. CONFIG_BOOLEAN_YES);
  2297. char *value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_PORTS, NULL);
  2298. ebpf_parse_ports(value);
  2299. if (network_viewer_opt.hostname_resolution_enabled) {
  2300. value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_HOSTNAMES, NULL);
  2301. ebpf_link_hostnames(value);
  2302. } else {
  2303. netdata_log_info("Name resolution is disabled, collector will not parse \"hostnames\" list.");
  2304. }
  2305. value = appconfig_get(cfg,
  2306. EBPF_NETWORK_VIEWER_SECTION,
  2307. "ips",
  2308. NULL);
  2309. //"ips", "!127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 !::1/128");
  2310. ebpf_parse_ips_unsafe(value);
  2311. }
  2312. /**
  2313. * Read Local Ports
  2314. *
  2315. * Parse /proc/net/{tcp,udp} and get the ports Linux is listening.
  2316. *
  2317. * @param filename the proc file to parse.
  2318. * @param proto is the magic number associated to the protocol file we are reading.
  2319. */
  2320. static void read_local_ports(char *filename, uint8_t proto)
  2321. {
  2322. procfile *ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
  2323. if (!ff)
  2324. return;
  2325. ff = procfile_readall(ff);
  2326. if (!ff)
  2327. return;
  2328. size_t lines = procfile_lines(ff), l;
  2329. netdata_passive_connection_t values = {.counter = 0, .tgid = 0, .pid = 0};
  2330. for(l = 0; l < lines ;l++) {
  2331. size_t words = procfile_linewords(ff, l);
  2332. // This is header or end of file
  2333. if (unlikely(words < 14))
  2334. continue;
  2335. // https://elixir.bootlin.com/linux/v5.7.8/source/include/net/tcp_states.h
  2336. // 0A = TCP_LISTEN
  2337. if (strcmp("0A", procfile_lineword(ff, l, 5)))
  2338. continue;
  2339. // Read local port
  2340. uint16_t port = (uint16_t)strtol(procfile_lineword(ff, l, 2), NULL, 16);
  2341. update_listen_table(htons(port), proto, &values);
  2342. }
  2343. procfile_close(ff);
  2344. }
  2345. /**
  2346. * Read Local addresseses
  2347. *
  2348. * Read the local address from the interfaces.
  2349. */
  2350. void ebpf_read_local_addresses_unsafe()
  2351. {
  2352. struct ifaddrs *ifaddr, *ifa;
  2353. if (getifaddrs(&ifaddr) == -1) {
  2354. netdata_log_error("Cannot get the local IP addresses, it is no possible to do separation between inbound and outbound connections");
  2355. return;
  2356. }
  2357. char *notext = { "No text representation" };
  2358. for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
  2359. if (ifa->ifa_addr == NULL)
  2360. continue;
  2361. if ((ifa->ifa_addr->sa_family != AF_INET) && (ifa->ifa_addr->sa_family != AF_INET6))
  2362. continue;
  2363. ebpf_network_viewer_ip_list_t *w = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
  2364. int family = ifa->ifa_addr->sa_family;
  2365. w->ver = (uint8_t) family;
  2366. char text[INET6_ADDRSTRLEN];
  2367. if (family == AF_INET) {
  2368. struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
  2369. w->first.addr32[0] = in->sin_addr.s_addr;
  2370. w->last.addr32[0] = in->sin_addr.s_addr;
  2371. if (inet_ntop(AF_INET, w->first.addr8, text, INET_ADDRSTRLEN)) {
  2372. w->value = strdupz(text);
  2373. w->hash = simple_hash(text);
  2374. } else {
  2375. w->value = strdupz(notext);
  2376. w->hash = simple_hash(notext);
  2377. }
  2378. } else {
  2379. struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
  2380. memcpy(w->first.addr8, (void *)&in6->sin6_addr, sizeof(struct in6_addr));
  2381. memcpy(w->last.addr8, (void *)&in6->sin6_addr, sizeof(struct in6_addr));
  2382. if (inet_ntop(AF_INET6, w->first.addr8, text, INET_ADDRSTRLEN)) {
  2383. w->value = strdupz(text);
  2384. w->hash = simple_hash(text);
  2385. } else {
  2386. w->value = strdupz(notext);
  2387. w->hash = simple_hash(notext);
  2388. }
  2389. }
  2390. ebpf_fill_ip_list_unsafe(
  2391. (family == AF_INET) ? &network_viewer_opt.ipv4_local_ip : &network_viewer_opt.ipv6_local_ip, w, "selector");
  2392. }
  2393. freeifaddrs(ifaddr);
  2394. }
  2395. /**
  2396. * Start Pthread Variable
  2397. *
  2398. * This function starts all pthread variables.
  2399. */
  2400. void ebpf_start_pthread_variables()
  2401. {
  2402. pthread_mutex_init(&lock, NULL);
  2403. pthread_mutex_init(&ebpf_exit_cleanup, NULL);
  2404. pthread_mutex_init(&collect_data_mutex, NULL);
  2405. pthread_mutex_init(&mutex_cgroup_shm, NULL);
  2406. rw_spinlock_init(&ebpf_judy_pid.index.rw_spinlock);
  2407. }
  2408. /**
  2409. * Allocate the vectors used for all threads.
  2410. */
  2411. static void ebpf_allocate_common_vectors()
  2412. {
  2413. ebpf_judy_pid.pid_table = ebpf_allocate_pid_aral(NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME,
  2414. sizeof(netdata_ebpf_judy_pid_stats_t));
  2415. ebpf_all_pids = callocz((size_t)pid_max, sizeof(struct ebpf_pid_stat *));
  2416. ebpf_aral_init();
  2417. }
  2418. /**
  2419. * Define how to load the ebpf programs
  2420. *
  2421. * @param ptr the option given by users
  2422. */
  2423. static inline void ebpf_how_to_load(char *ptr)
  2424. {
  2425. if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_RETURN))
  2426. ebpf_set_thread_mode(MODE_RETURN);
  2427. else if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_DEFAULT))
  2428. ebpf_set_thread_mode(MODE_ENTRY);
  2429. else
  2430. netdata_log_error("the option %s for \"ebpf load mode\" is not a valid option.", ptr);
  2431. }
  2432. /**
  2433. * Define whether we should have charts for apps
  2434. *
  2435. * @param lmode the mode that will be used for them.
  2436. */
  2437. static inline void ebpf_set_apps_mode(netdata_apps_integration_flags_t value)
  2438. {
  2439. int i;
  2440. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  2441. ebpf_modules[i].apps_charts = value;
  2442. }
  2443. }
  2444. /**
  2445. * Update interval
  2446. *
  2447. * Update default interval with value from user
  2448. *
  2449. * @param update_every value to overwrite the update frequency set by the server.
  2450. */
  2451. static void ebpf_update_interval(int update_every)
  2452. {
  2453. int i;
  2454. int value = (int) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_UPDATE_EVERY,
  2455. update_every);
  2456. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  2457. ebpf_modules[i].update_every = value;
  2458. }
  2459. }
  2460. /**
  2461. * Update PID table size
  2462. *
  2463. * Update default size with value from user
  2464. */
  2465. static void ebpf_update_table_size()
  2466. {
  2467. int i;
  2468. uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
  2469. EBPF_CFG_PID_SIZE, ND_EBPF_DEFAULT_PID_SIZE);
  2470. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  2471. ebpf_modules[i].pid_map_size = value;
  2472. }
  2473. }
  2474. /**
  2475. * Update lifetime
  2476. *
  2477. * Update the period of time that specific thread will run
  2478. */
  2479. static void ebpf_update_lifetime()
  2480. {
  2481. int i;
  2482. uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
  2483. EBPF_CFG_LIFETIME, EBPF_DEFAULT_LIFETIME);
  2484. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  2485. ebpf_modules[i].lifetime = value;
  2486. }
  2487. }
  2488. /**
  2489. * Set Load mode
  2490. *
  2491. * @param origin specify the configuration file loaded
  2492. */
  2493. static inline void ebpf_set_load_mode(netdata_ebpf_load_mode_t load, netdata_ebpf_load_mode_t origin)
  2494. {
  2495. int i;
  2496. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  2497. ebpf_modules[i].load &= ~NETDATA_EBPF_LOAD_METHODS;
  2498. ebpf_modules[i].load |= load | origin ;
  2499. }
  2500. }
  2501. /**
  2502. * Update mode
  2503. *
  2504. * @param str value read from configuration file.
  2505. * @param origin specify the configuration file loaded
  2506. */
  2507. static inline void epbf_update_load_mode(char *str, netdata_ebpf_load_mode_t origin)
  2508. {
  2509. netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(str);
  2510. ebpf_set_load_mode(load, origin);
  2511. }
  2512. /**
  2513. * Update Map per core
  2514. *
  2515. * Define the map type used with some hash tables.
  2516. */
  2517. static void ebpf_update_map_per_core()
  2518. {
  2519. int i;
  2520. int value = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION,
  2521. EBPF_CFG_MAPS_PER_CORE, CONFIG_BOOLEAN_YES);
  2522. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  2523. ebpf_modules[i].maps_per_core = value;
  2524. }
  2525. }
  2526. /**
  2527. * Read collector values
  2528. *
  2529. * @param disable_cgroups variable to store information related to cgroups.
  2530. * @param update_every value to overwrite the update frequency set by the server.
  2531. * @param origin specify the configuration file loaded
  2532. */
  2533. static void read_collector_values(int *disable_cgroups,
  2534. int update_every, netdata_ebpf_load_mode_t origin)
  2535. {
  2536. // Read global section
  2537. char *value;
  2538. if (appconfig_exists(&collector_config, EBPF_GLOBAL_SECTION, "load")) // Backward compatibility
  2539. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, "load",
  2540. EBPF_CFG_LOAD_MODE_DEFAULT);
  2541. else
  2542. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE,
  2543. EBPF_CFG_LOAD_MODE_DEFAULT);
  2544. ebpf_how_to_load(value);
  2545. btf_path = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_PROGRAM_PATH,
  2546. EBPF_DEFAULT_BTF_PATH);
  2547. #ifdef LIBBPF_MAJOR_VERSION
  2548. default_btf = ebpf_load_btf_file(btf_path, EBPF_DEFAULT_BTF_FILE);
  2549. #endif
  2550. value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, EBPF_CFG_DEFAULT_PROGRAM);
  2551. epbf_update_load_mode(value, origin);
  2552. ebpf_update_interval(update_every);
  2553. ebpf_update_table_size();
  2554. ebpf_update_lifetime();
  2555. // This is kept to keep compatibility
  2556. uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, "disable apps",
  2557. CONFIG_BOOLEAN_NO);
  2558. if (!enabled) {
  2559. // Apps is a positive sentence, so we need to invert the values to disable apps.
  2560. enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_APPLICATION,
  2561. CONFIG_BOOLEAN_YES);
  2562. enabled = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO;
  2563. }
  2564. ebpf_set_apps_mode(!enabled);
  2565. // Cgroup is a positive sentence, so we need to invert the values to disable apps.
  2566. // We are using the same pattern for cgroup and apps
  2567. enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_CGROUP, CONFIG_BOOLEAN_NO);
  2568. *disable_cgroups = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO;
  2569. ebpf_update_map_per_core();
  2570. // Read ebpf programs section
  2571. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
  2572. ebpf_modules[EBPF_MODULE_PROCESS_IDX].info.config_name, CONFIG_BOOLEAN_YES);
  2573. if (enabled) {
  2574. ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_cgroups);
  2575. }
  2576. // This is kept to keep compatibility
  2577. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network viewer",
  2578. CONFIG_BOOLEAN_NO);
  2579. if (!enabled)
  2580. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
  2581. ebpf_modules[EBPF_MODULE_SOCKET_IDX].info.config_name,
  2582. CONFIG_BOOLEAN_NO);
  2583. if (enabled) {
  2584. ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_cgroups);
  2585. }
  2586. // This is kept to keep compatibility
  2587. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connection monitoring",
  2588. CONFIG_BOOLEAN_YES);
  2589. if (!enabled)
  2590. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "network connections",
  2591. CONFIG_BOOLEAN_YES);
  2592. network_viewer_opt.enabled = enabled;
  2593. if (enabled) {
  2594. if (!ebpf_modules[EBPF_MODULE_SOCKET_IDX].enabled)
  2595. ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_cgroups);
  2596. // Read network viewer section if network viewer is enabled
  2597. // This is kept here to keep backward compatibility
  2598. parse_network_viewer_section(&collector_config);
  2599. ebpf_parse_service_name_section(&collector_config);
  2600. }
  2601. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "cachestat",
  2602. CONFIG_BOOLEAN_NO);
  2603. if (enabled) {
  2604. ebpf_enable_chart(EBPF_MODULE_CACHESTAT_IDX, *disable_cgroups);
  2605. }
  2606. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "sync",
  2607. CONFIG_BOOLEAN_YES);
  2608. if (enabled) {
  2609. ebpf_enable_chart(EBPF_MODULE_SYNC_IDX, *disable_cgroups);
  2610. }
  2611. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "dcstat",
  2612. CONFIG_BOOLEAN_NO);
  2613. if (enabled) {
  2614. ebpf_enable_chart(EBPF_MODULE_DCSTAT_IDX, *disable_cgroups);
  2615. }
  2616. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "swap",
  2617. CONFIG_BOOLEAN_NO);
  2618. if (enabled) {
  2619. ebpf_enable_chart(EBPF_MODULE_SWAP_IDX, *disable_cgroups);
  2620. }
  2621. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "vfs",
  2622. CONFIG_BOOLEAN_NO);
  2623. if (enabled) {
  2624. ebpf_enable_chart(EBPF_MODULE_VFS_IDX, *disable_cgroups);
  2625. }
  2626. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "filesystem",
  2627. CONFIG_BOOLEAN_NO);
  2628. if (enabled) {
  2629. ebpf_enable_chart(EBPF_MODULE_FILESYSTEM_IDX, *disable_cgroups);
  2630. }
  2631. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "disk",
  2632. CONFIG_BOOLEAN_NO);
  2633. if (enabled) {
  2634. ebpf_enable_chart(EBPF_MODULE_DISK_IDX, *disable_cgroups);
  2635. }
  2636. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mount",
  2637. CONFIG_BOOLEAN_YES);
  2638. if (enabled) {
  2639. ebpf_enable_chart(EBPF_MODULE_MOUNT_IDX, *disable_cgroups);
  2640. }
  2641. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "fd",
  2642. CONFIG_BOOLEAN_YES);
  2643. if (enabled) {
  2644. ebpf_enable_chart(EBPF_MODULE_FD_IDX, *disable_cgroups);
  2645. }
  2646. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "hardirq",
  2647. CONFIG_BOOLEAN_YES);
  2648. if (enabled) {
  2649. ebpf_enable_chart(EBPF_MODULE_HARDIRQ_IDX, *disable_cgroups);
  2650. }
  2651. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "softirq",
  2652. CONFIG_BOOLEAN_YES);
  2653. if (enabled) {
  2654. ebpf_enable_chart(EBPF_MODULE_SOFTIRQ_IDX, *disable_cgroups);
  2655. }
  2656. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "oomkill",
  2657. CONFIG_BOOLEAN_YES);
  2658. if (enabled) {
  2659. ebpf_enable_chart(EBPF_MODULE_OOMKILL_IDX, *disable_cgroups);
  2660. }
  2661. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "shm",
  2662. CONFIG_BOOLEAN_YES);
  2663. if (enabled) {
  2664. ebpf_enable_chart(EBPF_MODULE_SHM_IDX, *disable_cgroups);
  2665. }
  2666. enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mdflush",
  2667. CONFIG_BOOLEAN_NO);
  2668. if (enabled) {
  2669. ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_cgroups);
  2670. }
  2671. }
  2672. /**
  2673. * Load collector config
  2674. *
  2675. * @param path the path where the file ebpf.conf is stored.
  2676. * @param disable_cgroups variable to store the information about cgroups plugin status.
  2677. * @param update_every value to overwrite the update frequency set by the server.
  2678. *
  2679. * @return 0 on success and -1 otherwise.
  2680. */
  2681. static int ebpf_load_collector_config(char *path, int *disable_cgroups, int update_every)
  2682. {
  2683. char lpath[4096];
  2684. netdata_ebpf_load_mode_t origin;
  2685. snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_CONFIG_FILE);
  2686. if (!appconfig_load(&collector_config, lpath, 0, NULL)) {
  2687. snprintf(lpath, 4095, "%s/%s", path, NETDATA_EBPF_OLD_CONFIG_FILE);
  2688. if (!appconfig_load(&collector_config, lpath, 0, NULL)) {
  2689. return -1;
  2690. }
  2691. origin = EBPF_LOADED_FROM_STOCK;
  2692. } else
  2693. origin = EBPF_LOADED_FROM_USER;
  2694. read_collector_values(disable_cgroups, update_every, origin);
  2695. return 0;
  2696. }
  2697. /**
  2698. * Set global variables reading environment variables
  2699. */
  2700. void set_global_variables()
  2701. {
  2702. // Get environment variables
  2703. ebpf_plugin_dir = getenv("NETDATA_PLUGINS_DIR");
  2704. if (!ebpf_plugin_dir)
  2705. ebpf_plugin_dir = PLUGINS_DIR;
  2706. ebpf_user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
  2707. if (!ebpf_user_config_dir)
  2708. ebpf_user_config_dir = CONFIG_DIR;
  2709. ebpf_stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
  2710. if (!ebpf_stock_config_dir)
  2711. ebpf_stock_config_dir = LIBCONFIG_DIR;
  2712. ebpf_configured_log_dir = getenv("NETDATA_LOG_DIR");
  2713. if (!ebpf_configured_log_dir)
  2714. ebpf_configured_log_dir = LOG_DIR;
  2715. ebpf_nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
  2716. if (ebpf_nprocs < 0) {
  2717. ebpf_nprocs = NETDATA_MAX_PROCESSOR;
  2718. netdata_log_error("Cannot identify number of process, using default value %d", ebpf_nprocs);
  2719. }
  2720. isrh = get_redhat_release();
  2721. pid_max = get_system_pid_max();
  2722. running_on_kernel = ebpf_get_kernel_version();
  2723. }
  2724. /**
  2725. * Load collector config
  2726. */
  2727. static inline void ebpf_load_thread_config()
  2728. {
  2729. int i;
  2730. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  2731. ebpf_update_module(&ebpf_modules[i], default_btf, running_on_kernel, isrh);
  2732. }
  2733. }
  2734. /**
  2735. * Check Conditions
  2736. *
  2737. * This function checks kernel that plugin is running and permissions.
  2738. *
  2739. * @return It returns 0 on success and -1 otherwise
  2740. */
  2741. int ebpf_check_conditions()
  2742. {
  2743. if (!has_condition_to_run(running_on_kernel)) {
  2744. netdata_log_error("The current collector cannot run on this kernel.");
  2745. return -1;
  2746. }
  2747. if (!am_i_running_as_root()) {
  2748. netdata_log_error(
  2749. "ebpf.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities..",
  2750. (unsigned int)getuid(), (unsigned int)geteuid());
  2751. return -1;
  2752. }
  2753. return 0;
  2754. }
  2755. /**
  2756. * Adjust memory
  2757. *
  2758. * Adjust memory values to load eBPF programs.
  2759. *
  2760. * @return It returns 0 on success and -1 otherwise
  2761. */
  2762. int ebpf_adjust_memory_limit()
  2763. {
  2764. struct rlimit r = { RLIM_INFINITY, RLIM_INFINITY };
  2765. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  2766. netdata_log_error("Setrlimit(RLIMIT_MEMLOCK)");
  2767. return -1;
  2768. }
  2769. return 0;
  2770. }
  2771. /**
  2772. * Parse arguments given from user.
  2773. *
  2774. * @param argc the number of arguments
  2775. * @param argv the pointer to the arguments
  2776. */
  2777. static void ebpf_parse_args(int argc, char **argv)
  2778. {
  2779. int disable_cgroups = 1;
  2780. int freq = 0;
  2781. int option_index = 0;
  2782. uint64_t select_threads = 0;
  2783. static struct option long_options[] = {
  2784. {"process", no_argument, 0, 0 },
  2785. {"net", no_argument, 0, 0 },
  2786. {"cachestat", no_argument, 0, 0 },
  2787. {"sync", no_argument, 0, 0 },
  2788. {"dcstat", no_argument, 0, 0 },
  2789. {"swap", no_argument, 0, 0 },
  2790. {"vfs", no_argument, 0, 0 },
  2791. {"filesystem", no_argument, 0, 0 },
  2792. {"disk", no_argument, 0, 0 },
  2793. {"mount", no_argument, 0, 0 },
  2794. {"filedescriptor", no_argument, 0, 0 },
  2795. {"hardirq", no_argument, 0, 0 },
  2796. {"softirq", no_argument, 0, 0 },
  2797. {"oomkill", no_argument, 0, 0 },
  2798. {"shm", no_argument, 0, 0 },
  2799. {"mdflush", no_argument, 0, 0 },
  2800. /* INSERT NEW THREADS BEFORE THIS COMMENT TO KEEP COMPATIBILITY WITH enum ebpf_module_indexes */
  2801. {"all", no_argument, 0, 0 },
  2802. {"version", no_argument, 0, 0 },
  2803. {"help", no_argument, 0, 0 },
  2804. {"global", no_argument, 0, 0 },
  2805. {"return", no_argument, 0, 0 },
  2806. {"legacy", no_argument, 0, 0 },
  2807. {"core", no_argument, 0, 0 },
  2808. {"unittest", no_argument, 0, 0 },
  2809. {0, 0, 0, 0}
  2810. };
  2811. memset(&network_viewer_opt, 0, sizeof(network_viewer_opt));
  2812. rw_spinlock_init(&network_viewer_opt.rw_spinlock);
  2813. if (argc > 1) {
  2814. int n = (int)str2l(argv[1]);
  2815. if (n > 0) {
  2816. freq = n;
  2817. }
  2818. }
  2819. if (!freq)
  2820. freq = EBPF_DEFAULT_UPDATE_EVERY;
  2821. //rw_spinlock_write_lock(&network_viewer_opt.rw_spinlock);
  2822. if (ebpf_load_collector_config(ebpf_user_config_dir, &disable_cgroups, freq)) {
  2823. netdata_log_info(
  2824. "Does not have a configuration file inside `%s/ebpf.d.conf. It will try to load stock file.",
  2825. ebpf_user_config_dir);
  2826. if (ebpf_load_collector_config(ebpf_stock_config_dir, &disable_cgroups, freq)) {
  2827. netdata_log_info("Does not have a stock file. It is starting with default options.");
  2828. }
  2829. }
  2830. ebpf_load_thread_config();
  2831. //rw_spinlock_write_unlock(&network_viewer_opt.rw_spinlock);
  2832. while (1) {
  2833. int c = getopt_long_only(argc, argv, "", long_options, &option_index);
  2834. if (c == -1)
  2835. break;
  2836. switch (option_index) {
  2837. case EBPF_MODULE_PROCESS_IDX: {
  2838. select_threads |= 1<<EBPF_MODULE_PROCESS_IDX;
  2839. #ifdef NETDATA_INTERNAL_CHECKS
  2840. netdata_log_info("EBPF enabling \"PROCESS\" charts, because it was started with the option \"[-]-process\".");
  2841. #endif
  2842. break;
  2843. }
  2844. case EBPF_MODULE_SOCKET_IDX: {
  2845. select_threads |= 1<<EBPF_MODULE_SOCKET_IDX;
  2846. #ifdef NETDATA_INTERNAL_CHECKS
  2847. netdata_log_info("EBPF enabling \"NET\" charts, because it was started with the option \"[-]-net\".");
  2848. #endif
  2849. break;
  2850. }
  2851. case EBPF_MODULE_CACHESTAT_IDX: {
  2852. select_threads |= 1<<EBPF_MODULE_CACHESTAT_IDX;
  2853. #ifdef NETDATA_INTERNAL_CHECKS
  2854. netdata_log_info("EBPF enabling \"CACHESTAT\" charts, because it was started with the option \"[-]-cachestat\".");
  2855. #endif
  2856. break;
  2857. }
  2858. case EBPF_MODULE_SYNC_IDX: {
  2859. select_threads |= 1<<EBPF_MODULE_SYNC_IDX;
  2860. #ifdef NETDATA_INTERNAL_CHECKS
  2861. netdata_log_info("EBPF enabling \"SYNC\" chart, because it was started with the option \"[-]-sync\".");
  2862. #endif
  2863. break;
  2864. }
  2865. case EBPF_MODULE_DCSTAT_IDX: {
  2866. select_threads |= 1<<EBPF_MODULE_DCSTAT_IDX;
  2867. #ifdef NETDATA_INTERNAL_CHECKS
  2868. netdata_log_info("EBPF enabling \"DCSTAT\" charts, because it was started with the option \"[-]-dcstat\".");
  2869. #endif
  2870. break;
  2871. }
  2872. case EBPF_MODULE_SWAP_IDX: {
  2873. select_threads |= 1<<EBPF_MODULE_SWAP_IDX;
  2874. #ifdef NETDATA_INTERNAL_CHECKS
  2875. netdata_log_info("EBPF enabling \"SWAP\" chart, because it was started with the option \"[-]-swap\".");
  2876. #endif
  2877. break;
  2878. }
  2879. case EBPF_MODULE_VFS_IDX: {
  2880. select_threads |= 1<<EBPF_MODULE_VFS_IDX;
  2881. #ifdef NETDATA_INTERNAL_CHECKS
  2882. netdata_log_info("EBPF enabling \"VFS\" chart, because it was started with the option \"[-]-vfs\".");
  2883. #endif
  2884. break;
  2885. }
  2886. case EBPF_MODULE_FILESYSTEM_IDX: {
  2887. select_threads |= 1<<EBPF_MODULE_FILESYSTEM_IDX;
  2888. #ifdef NETDATA_INTERNAL_CHECKS
  2889. netdata_log_info("EBPF enabling \"FILESYSTEM\" chart, because it was started with the option \"[-]-filesystem\".");
  2890. #endif
  2891. break;
  2892. }
  2893. case EBPF_MODULE_DISK_IDX: {
  2894. select_threads |= 1<<EBPF_MODULE_DISK_IDX;
  2895. #ifdef NETDATA_INTERNAL_CHECKS
  2896. netdata_log_info("EBPF enabling \"DISK\" chart, because it was started with the option \"[-]-disk\".");
  2897. #endif
  2898. break;
  2899. }
  2900. case EBPF_MODULE_MOUNT_IDX: {
  2901. select_threads |= 1<<EBPF_MODULE_MOUNT_IDX;
  2902. #ifdef NETDATA_INTERNAL_CHECKS
  2903. netdata_log_info("EBPF enabling \"MOUNT\" chart, because it was started with the option \"[-]-mount\".");
  2904. #endif
  2905. break;
  2906. }
  2907. case EBPF_MODULE_FD_IDX: {
  2908. select_threads |= 1<<EBPF_MODULE_FD_IDX;
  2909. #ifdef NETDATA_INTERNAL_CHECKS
  2910. netdata_log_info("EBPF enabling \"FILEDESCRIPTOR\" chart, because it was started with the option \"[-]-filedescriptor\".");
  2911. #endif
  2912. break;
  2913. }
  2914. case EBPF_MODULE_HARDIRQ_IDX: {
  2915. select_threads |= 1<<EBPF_MODULE_HARDIRQ_IDX;
  2916. #ifdef NETDATA_INTERNAL_CHECKS
  2917. netdata_log_info("EBPF enabling \"HARDIRQ\" chart, because it was started with the option \"[-]-hardirq\".");
  2918. #endif
  2919. break;
  2920. }
  2921. case EBPF_MODULE_SOFTIRQ_IDX: {
  2922. select_threads |= 1<<EBPF_MODULE_SOFTIRQ_IDX;
  2923. #ifdef NETDATA_INTERNAL_CHECKS
  2924. netdata_log_info("EBPF enabling \"SOFTIRQ\" chart, because it was started with the option \"[-]-softirq\".");
  2925. #endif
  2926. break;
  2927. }
  2928. case EBPF_MODULE_OOMKILL_IDX: {
  2929. select_threads |= 1<<EBPF_MODULE_OOMKILL_IDX;
  2930. #ifdef NETDATA_INTERNAL_CHECKS
  2931. netdata_log_info("EBPF enabling \"OOMKILL\" chart, because it was started with the option \"[-]-oomkill\".");
  2932. #endif
  2933. break;
  2934. }
  2935. case EBPF_MODULE_SHM_IDX: {
  2936. select_threads |= 1<<EBPF_MODULE_SHM_IDX;
  2937. #ifdef NETDATA_INTERNAL_CHECKS
  2938. netdata_log_info("EBPF enabling \"SHM\" chart, because it was started with the option \"[-]-shm\".");
  2939. #endif
  2940. break;
  2941. }
  2942. case EBPF_MODULE_MDFLUSH_IDX: {
  2943. select_threads |= 1<<EBPF_MODULE_MDFLUSH_IDX;
  2944. #ifdef NETDATA_INTERNAL_CHECKS
  2945. netdata_log_info("EBPF enabling \"MDFLUSH\" chart, because it was started with the option \"[-]-mdflush\".");
  2946. #endif
  2947. break;
  2948. }
  2949. case EBPF_OPTION_ALL_CHARTS: {
  2950. ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_YES);
  2951. disable_cgroups = 0;
  2952. #ifdef NETDATA_INTERNAL_CHECKS
  2953. netdata_log_info("EBPF running with all chart groups, because it was started with the option \"[-]-all\".");
  2954. #endif
  2955. break;
  2956. }
  2957. case EBPF_OPTION_VERSION: {
  2958. printf("ebpf.plugin %s\n", VERSION);
  2959. exit(0);
  2960. }
  2961. case EBPF_OPTION_HELP: {
  2962. ebpf_print_help();
  2963. exit(0);
  2964. }
  2965. case EBPF_OPTION_GLOBAL_CHART: {
  2966. disable_cgroups = 1;
  2967. #ifdef NETDATA_INTERNAL_CHECKS
  2968. netdata_log_info("EBPF running with global chart group, because it was started with the option \"[-]-global\".");
  2969. #endif
  2970. break;
  2971. }
  2972. case EBPF_OPTION_RETURN_MODE: {
  2973. ebpf_set_thread_mode(MODE_RETURN);
  2974. #ifdef NETDATA_INTERNAL_CHECKS
  2975. netdata_log_info("EBPF running in \"RETURN\" mode, because it was started with the option \"[-]-return\".");
  2976. #endif
  2977. break;
  2978. }
  2979. case EBPF_OPTION_LEGACY: {
  2980. ebpf_set_load_mode(EBPF_LOAD_LEGACY, EBPF_LOADED_FROM_USER);
  2981. #ifdef NETDATA_INTERNAL_CHECKS
  2982. netdata_log_info("EBPF running with \"LEGACY\" code, because it was started with the option \"[-]-legacy\".");
  2983. #endif
  2984. break;
  2985. }
  2986. case EBPF_OPTION_CORE: {
  2987. ebpf_set_load_mode(EBPF_LOAD_CORE, EBPF_LOADED_FROM_USER);
  2988. #ifdef NETDATA_INTERNAL_CHECKS
  2989. netdata_log_info("EBPF running with \"CO-RE\" code, because it was started with the option \"[-]-core\".");
  2990. #endif
  2991. break;
  2992. }
  2993. case EBPF_OPTION_UNITTEST: {
  2994. // if we cannot run until the end, we will cancel the unittest
  2995. int exit_code = ECANCELED;
  2996. if (ebpf_check_conditions())
  2997. goto unittest;
  2998. if (ebpf_adjust_memory_limit())
  2999. goto unittest;
  3000. // Load binary in entry mode
  3001. ebpf_ut_initialize_structure(MODE_ENTRY);
  3002. if (ebpf_ut_load_real_binary())
  3003. goto unittest;
  3004. ebpf_ut_cleanup_memory();
  3005. // Do not load a binary in entry mode
  3006. ebpf_ut_initialize_structure(MODE_ENTRY);
  3007. if (ebpf_ut_load_fake_binary())
  3008. goto unittest;
  3009. ebpf_ut_cleanup_memory();
  3010. exit_code = 0;
  3011. unittest:
  3012. exit(exit_code);
  3013. }
  3014. default: {
  3015. break;
  3016. }
  3017. }
  3018. }
  3019. if (disable_cgroups) {
  3020. ebpf_disable_cgroups();
  3021. }
  3022. if (select_threads) {
  3023. disable_all_global_charts();
  3024. uint64_t idx;
  3025. for (idx = 0; idx < EBPF_OPTION_ALL_CHARTS; idx++) {
  3026. if (select_threads & 1<<idx)
  3027. ebpf_enable_specific_chart(&ebpf_modules[idx], disable_cgroups);
  3028. }
  3029. }
  3030. // Load apps_groups.conf
  3031. if (ebpf_read_apps_groups_conf(
  3032. &apps_groups_default_target, &apps_groups_root_target, ebpf_user_config_dir, "groups")) {
  3033. netdata_log_info("Cannot read process groups configuration file '%s/apps_groups.conf'. Will try '%s/apps_groups.conf'",
  3034. ebpf_user_config_dir, ebpf_stock_config_dir);
  3035. if (ebpf_read_apps_groups_conf(
  3036. &apps_groups_default_target, &apps_groups_root_target, ebpf_stock_config_dir, "groups")) {
  3037. netdata_log_error("Cannot read process groups '%s/apps_groups.conf'. There are no internal defaults. Failing.",
  3038. ebpf_stock_config_dir);
  3039. ebpf_exit();
  3040. }
  3041. } else
  3042. netdata_log_info("Loaded config file '%s/apps_groups.conf'", ebpf_user_config_dir);
  3043. }
  3044. /*****************************************************************
  3045. *
  3046. * Collector charts
  3047. *
  3048. *****************************************************************/
  3049. static char *load_event_stat[NETDATA_EBPF_LOAD_STAT_END] = {"legacy", "co-re"};
  3050. static char *memlock_stat = {"memory_locked"};
  3051. static char *hash_table_stat = {"hash_table"};
  3052. static char *hash_table_core[NETDATA_EBPF_LOAD_STAT_END] = {"per_core", "unique"};
  3053. /**
  3054. * Send Hash Table PID data
  3055. *
  3056. * Send all information associated with a specific pid table.
  3057. *
  3058. * @param chart chart id
  3059. * @param idx index position in hash_table_stats
  3060. */
  3061. static inline void ebpf_send_hash_table_pid_data(char *chart, uint32_t idx)
  3062. {
  3063. int i;
  3064. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, chart, "");
  3065. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3066. ebpf_module_t *wem = &ebpf_modules[i];
  3067. if (wem->functions.apps_routine)
  3068. write_chart_dimension((char *)wem->info.thread_name,
  3069. (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
  3070. wem->hash_table_stats[idx]:
  3071. 0);
  3072. }
  3073. ebpf_write_end_chart();
  3074. }
  3075. /**
  3076. * Send Global Hash Table data
  3077. *
  3078. * Send all information associated with a specific pid table.
  3079. *
  3080. */
  3081. static inline void ebpf_send_global_hash_table_data()
  3082. {
  3083. int i;
  3084. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_GLOBAL_ELEMENTS, "");
  3085. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3086. ebpf_module_t *wem = &ebpf_modules[i];
  3087. write_chart_dimension((char *)wem->info.thread_name,
  3088. (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? NETDATA_CONTROLLER_END: 0);
  3089. }
  3090. ebpf_write_end_chart();
  3091. }
  3092. /**
  3093. * Send Statistic Data
  3094. *
  3095. * Send statistic information to netdata.
  3096. */
  3097. void ebpf_send_statistic_data()
  3098. {
  3099. if (!publish_internal_metrics)
  3100. return;
  3101. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_THREADS, "");
  3102. int i;
  3103. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3104. ebpf_module_t *wem = &ebpf_modules[i];
  3105. if (wem->functions.fnct_routine)
  3106. continue;
  3107. write_chart_dimension((char *)wem->info.thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
  3108. }
  3109. ebpf_write_end_chart();
  3110. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LIFE_TIME, "");
  3111. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
  3112. ebpf_module_t *wem = &ebpf_modules[i];
  3113. // Threads like VFS is slow to load and this can create an invalid number, this is the motive
  3114. // we are also testing wem->lifetime value.
  3115. if (wem->functions.fnct_routine)
  3116. continue;
  3117. write_chart_dimension((char *)wem->info.thread_name,
  3118. (wem->lifetime && wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
  3119. (long long) (wem->lifetime - wem->running_time):
  3120. 0) ;
  3121. }
  3122. ebpf_write_end_chart();
  3123. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LOAD_METHOD, "");
  3124. write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY], (long long)plugin_statistics.legacy);
  3125. write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE], (long long)plugin_statistics.core);
  3126. ebpf_write_end_chart();
  3127. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_KERNEL_MEMORY, "");
  3128. write_chart_dimension(memlock_stat, (long long)plugin_statistics.memlock_kern);
  3129. ebpf_write_end_chart();
  3130. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_LOADED, "");
  3131. write_chart_dimension(hash_table_stat, (long long)plugin_statistics.hash_tables);
  3132. ebpf_write_end_chart();
  3133. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_PER_CORE, "");
  3134. write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE], (long long)plugin_statistics.hash_percpu);
  3135. write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE], (long long)plugin_statistics.hash_unique);
  3136. ebpf_write_end_chart();
  3137. ebpf_send_global_hash_table_data();
  3138. ebpf_send_hash_table_pid_data(NETDATA_EBPF_HASH_TABLES_INSERT_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_ADD);
  3139. ebpf_send_hash_table_pid_data(NETDATA_EBPF_HASH_TABLES_REMOVE_PID_ELEMENTS, NETDATA_EBPF_GLOBAL_TABLE_PID_TABLE_DEL);
  3140. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3141. ebpf_module_t *wem = &ebpf_modules[i];
  3142. if (!wem->functions.fnct_routine)
  3143. continue;
  3144. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, (char *)wem->functions.fcnt_thread_chart_name, "");
  3145. write_chart_dimension((char *)wem->info.thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
  3146. ebpf_write_end_chart();
  3147. ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, (char *)wem->functions.fcnt_thread_lifetime_name, "");
  3148. write_chart_dimension((char *)wem->info.thread_name,
  3149. (wem->lifetime && wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
  3150. (long long) (wem->lifetime - wem->running_time):
  3151. 0) ;
  3152. ebpf_write_end_chart();
  3153. }
  3154. }
  3155. /**
  3156. * Update Internal Metric variable
  3157. *
  3158. * By default eBPF.plugin sends internal metrics for netdata, but user can
  3159. * disable this.
  3160. *
  3161. * The function updates the variable used to send charts.
  3162. */
  3163. static void update_internal_metric_variable()
  3164. {
  3165. const char *s = getenv("NETDATA_INTERNALS_MONITORING");
  3166. if (s && *s && strcmp(s, "NO") == 0)
  3167. publish_internal_metrics = false;
  3168. }
  3169. /**
  3170. * Create Thread Chart
  3171. *
  3172. * Write to standard output current values for threads charts.
  3173. *
  3174. * @param name is the chart name
  3175. * @param title chart title.
  3176. * @param units chart units
  3177. * @param order is the chart order
  3178. * @param update_every time used to update charts
  3179. * @param module a module to create a specific chart.
  3180. */
  3181. static void ebpf_create_thread_chart(char *name,
  3182. char *title,
  3183. char *units,
  3184. int order,
  3185. int update_every,
  3186. ebpf_module_t *module)
  3187. {
  3188. // common call for specific and all charts.
  3189. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3190. name,
  3191. "",
  3192. title,
  3193. units,
  3194. NETDATA_EBPF_FAMILY,
  3195. NETDATA_EBPF_CHART_TYPE_LINE,
  3196. NULL,
  3197. order,
  3198. update_every,
  3199. "main");
  3200. if (module) {
  3201. ebpf_write_global_dimension((char *)module->info.thread_name,
  3202. (char *)module->info.thread_name,
  3203. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3204. return;
  3205. }
  3206. int i;
  3207. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3208. ebpf_module_t *em = &ebpf_modules[i];
  3209. if (em->functions.fnct_routine)
  3210. continue;
  3211. ebpf_write_global_dimension((char *)em->info.thread_name,
  3212. (char *)em->info.thread_name,
  3213. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3214. }
  3215. }
  3216. /**
  3217. * Create chart for Load Thread
  3218. *
  3219. * Write to standard output current values for load mode.
  3220. *
  3221. * @param update_every time used to update charts
  3222. */
  3223. static inline void ebpf_create_statistic_load_chart(int update_every)
  3224. {
  3225. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3226. NETDATA_EBPF_LOAD_METHOD,
  3227. "",
  3228. "Load info.",
  3229. "methods",
  3230. NETDATA_EBPF_FAMILY,
  3231. NETDATA_EBPF_CHART_TYPE_LINE,
  3232. NULL,
  3233. NETDATA_EBPF_ORDER_STAT_LOAD_METHOD,
  3234. update_every,
  3235. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3236. ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
  3237. load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
  3238. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3239. ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
  3240. load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
  3241. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3242. }
  3243. /**
  3244. * Create chart for Kernel Memory
  3245. *
  3246. * Write to standard output current values for allocated memory.
  3247. *
  3248. * @param update_every time used to update charts
  3249. */
  3250. static inline void ebpf_create_statistic_kernel_memory(int update_every)
  3251. {
  3252. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3253. NETDATA_EBPF_KERNEL_MEMORY,
  3254. "",
  3255. "Memory allocated for hash tables.",
  3256. "bytes",
  3257. NETDATA_EBPF_FAMILY,
  3258. NETDATA_EBPF_CHART_TYPE_LINE,
  3259. NULL,
  3260. NETDATA_EBPF_ORDER_STAT_KERNEL_MEMORY,
  3261. update_every,
  3262. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3263. ebpf_write_global_dimension(memlock_stat,
  3264. memlock_stat,
  3265. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3266. }
  3267. /**
  3268. * Create chart Hash Table
  3269. *
  3270. * Write to standard output number of hash tables used with this software.
  3271. *
  3272. * @param update_every time used to update charts
  3273. */
  3274. static inline void ebpf_create_statistic_hash_tables(int update_every)
  3275. {
  3276. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3277. NETDATA_EBPF_HASH_TABLES_LOADED,
  3278. "",
  3279. "Number of hash tables loaded.",
  3280. "hash tables",
  3281. NETDATA_EBPF_FAMILY,
  3282. NETDATA_EBPF_CHART_TYPE_LINE,
  3283. NULL,
  3284. NETDATA_EBPF_ORDER_STAT_HASH_TABLES,
  3285. update_every,
  3286. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3287. ebpf_write_global_dimension(hash_table_stat,
  3288. hash_table_stat,
  3289. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3290. }
  3291. /**
  3292. * Create chart for percpu stats
  3293. *
  3294. * Write to standard output current values for threads.
  3295. *
  3296. * @param update_every time used to update charts
  3297. */
  3298. static inline void ebpf_create_statistic_hash_per_core(int update_every)
  3299. {
  3300. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3301. NETDATA_EBPF_HASH_TABLES_PER_CORE,
  3302. "",
  3303. "How threads are loading hash/array tables.",
  3304. "threads",
  3305. NETDATA_EBPF_FAMILY,
  3306. NETDATA_EBPF_CHART_TYPE_LINE,
  3307. NULL,
  3308. NETDATA_EBPF_ORDER_STAT_HASH_CORE,
  3309. update_every,
  3310. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3311. ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
  3312. hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
  3313. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3314. ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
  3315. hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
  3316. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3317. }
  3318. /**
  3319. * Hash table global elements
  3320. *
  3321. * Write to standard output current values inside global tables.
  3322. *
  3323. * @param update_every time used to update charts
  3324. */
  3325. static void ebpf_create_statistic_hash_global_elements(int update_every)
  3326. {
  3327. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3328. NETDATA_EBPF_HASH_TABLES_GLOBAL_ELEMENTS,
  3329. "",
  3330. "Controllers inside global table",
  3331. "rows",
  3332. NETDATA_EBPF_FAMILY,
  3333. NETDATA_EBPF_CHART_TYPE_LINE,
  3334. NULL,
  3335. NETDATA_EBPF_ORDER_STAT_HASH_GLOBAL_TABLE_TOTAL,
  3336. update_every,
  3337. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3338. int i;
  3339. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3340. ebpf_write_global_dimension((char *)ebpf_modules[i].info.thread_name,
  3341. (char *)ebpf_modules[i].info.thread_name,
  3342. ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
  3343. }
  3344. }
  3345. /**
  3346. * Hash table global elements
  3347. *
  3348. * Write to standard output current values inside global tables.
  3349. *
  3350. * @param update_every time used to update charts
  3351. * @param id chart id
  3352. * @param title chart title
  3353. * @param order ordder chart will be shown on dashboard.
  3354. */
  3355. static void ebpf_create_statistic_hash_pid_table(int update_every, char *id, char *title, int order)
  3356. {
  3357. ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
  3358. id,
  3359. "",
  3360. title,
  3361. "rows",
  3362. NETDATA_EBPF_FAMILY,
  3363. NETDATA_EBPF_CHART_TYPE_LINE,
  3364. NULL,
  3365. order,
  3366. update_every,
  3367. NETDATA_EBPF_MODULE_NAME_PROCESS);
  3368. int i;
  3369. for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3370. ebpf_module_t *wem = &ebpf_modules[i];
  3371. if (wem->functions.apps_routine)
  3372. ebpf_write_global_dimension((char *)wem->info.thread_name,
  3373. (char *)wem->info.thread_name,
  3374. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
  3375. }
  3376. }
  3377. /**
  3378. * Create Statistics Charts
  3379. *
  3380. * Create charts that will show statistics related to eBPF plugin.
  3381. *
  3382. * @param update_every time used to update charts
  3383. */
  3384. static void ebpf_create_statistic_charts(int update_every)
  3385. {
  3386. static char create_charts = 1;
  3387. update_internal_metric_variable();
  3388. if (!publish_internal_metrics)
  3389. return;
  3390. if (!create_charts)
  3391. return;
  3392. create_charts = 0;
  3393. ebpf_create_thread_chart(NETDATA_EBPF_THREADS,
  3394. "Threads running.",
  3395. "boolean",
  3396. NETDATA_EBPF_ORDER_STAT_THREADS,
  3397. update_every,
  3398. NULL);
  3399. /*
  3400. #ifdef NETDATA_DEV_MODE
  3401. EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
  3402. #endif
  3403. */
  3404. ebpf_create_thread_chart(NETDATA_EBPF_LIFE_TIME,
  3405. "Time remaining for thread.",
  3406. "seconds",
  3407. NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
  3408. update_every,
  3409. NULL);
  3410. /*
  3411. #ifdef NETDATA_DEV_MODE
  3412. EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
  3413. #endif
  3414. */
  3415. int i,j;
  3416. char name[256];
  3417. for (i = 0, j = NETDATA_EBPF_ORDER_FUNCTION_PER_THREAD; i < EBPF_MODULE_FUNCTION_IDX; i++) {
  3418. ebpf_module_t *em = &ebpf_modules[i];
  3419. if (!em->functions.fnct_routine)
  3420. continue;
  3421. em->functions.order_thread_chart = j;
  3422. snprintfz(name, sizeof(name) - 1, "%s_%s", NETDATA_EBPF_THREADS, em->info.thread_name);
  3423. em->functions.fcnt_thread_chart_name = strdupz(name);
  3424. ebpf_create_thread_chart(name,
  3425. "Threads running.",
  3426. "boolean",
  3427. j++,
  3428. update_every,
  3429. em);
  3430. #ifdef NETDATA_DEV_MODE
  3431. EBPF_PLUGIN_FUNCTIONS(em->functions.fcnt_name, em->functions.fcnt_desc);
  3432. #endif
  3433. em->functions.order_thread_lifetime = j;
  3434. snprintfz(name, sizeof(name) - 1, "%s_%s", NETDATA_EBPF_LIFE_TIME, em->info.thread_name);
  3435. em->functions.fcnt_thread_lifetime_name = strdupz(name);
  3436. ebpf_create_thread_chart(name,
  3437. "Time remaining for thread.",
  3438. "seconds",
  3439. j++,
  3440. update_every,
  3441. em);
  3442. #ifdef NETDATA_DEV_MODE
  3443. EBPF_PLUGIN_FUNCTIONS(em->functions.fcnt_name, em->functions.fcnt_desc);
  3444. #endif
  3445. }
  3446. ebpf_create_statistic_load_chart(update_every);
  3447. ebpf_create_statistic_kernel_memory(update_every);
  3448. ebpf_create_statistic_hash_tables(update_every);
  3449. ebpf_create_statistic_hash_per_core(update_every);
  3450. ebpf_create_statistic_hash_global_elements(update_every);
  3451. ebpf_create_statistic_hash_pid_table(update_every,
  3452. NETDATA_EBPF_HASH_TABLES_INSERT_PID_ELEMENTS,
  3453. "Elements inserted into PID table",
  3454. NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_ADDED);
  3455. ebpf_create_statistic_hash_pid_table(update_every,
  3456. NETDATA_EBPF_HASH_TABLES_REMOVE_PID_ELEMENTS,
  3457. "Elements removed from PID table",
  3458. NETDATA_EBPF_ORDER_STAT_HASH_PID_TABLE_REMOVED);
  3459. fflush(stdout);
  3460. }
  3461. /*****************************************************************
  3462. *
  3463. * COLLECTOR ENTRY POINT
  3464. *
  3465. *****************************************************************/
  3466. /**
  3467. * Update PID file
  3468. *
  3469. * Update the content of PID file
  3470. *
  3471. * @param filename is the full name of the file.
  3472. * @param pid that identifies the process
  3473. */
  3474. static void ebpf_update_pid_file(char *filename, pid_t pid)
  3475. {
  3476. FILE *fp = fopen(filename, "w");
  3477. if (!fp)
  3478. return;
  3479. fprintf(fp, "%d", pid);
  3480. fclose(fp);
  3481. }
  3482. /**
  3483. * Get Process Name
  3484. *
  3485. * Get process name from /proc/PID/status
  3486. *
  3487. * @param pid that identifies the process
  3488. */
  3489. static char *ebpf_get_process_name(pid_t pid)
  3490. {
  3491. char *name = NULL;
  3492. char filename[FILENAME_MAX + 1];
  3493. snprintfz(filename, FILENAME_MAX, "/proc/%d/status", pid);
  3494. procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
  3495. if(unlikely(!ff)) {
  3496. netdata_log_error("Cannot open %s", filename);
  3497. return name;
  3498. }
  3499. ff = procfile_readall(ff);
  3500. if(unlikely(!ff))
  3501. return name;
  3502. unsigned long i, lines = procfile_lines(ff);
  3503. for(i = 0; i < lines ; i++) {
  3504. char *cmp = procfile_lineword(ff, i, 0);
  3505. if (!strcmp(cmp, "Name:")) {
  3506. name = strdupz(procfile_lineword(ff, i, 1));
  3507. break;
  3508. }
  3509. }
  3510. procfile_close(ff);
  3511. return name;
  3512. }
  3513. /**
  3514. * Read Previous PID
  3515. *
  3516. * @param filename is the full name of the file.
  3517. *
  3518. * @return It returns the PID used during previous execution on success or 0 otherwise
  3519. */
  3520. static pid_t ebpf_read_previous_pid(char *filename)
  3521. {
  3522. FILE *fp = fopen(filename, "r");
  3523. if (!fp)
  3524. return 0;
  3525. char buffer[64];
  3526. size_t length = fread(buffer, sizeof(*buffer), 63, fp);
  3527. pid_t old_pid = 0;
  3528. if (length) {
  3529. if (length > 63)
  3530. length = 63;
  3531. buffer[length] = '\0';
  3532. old_pid = (pid_t) str2uint32_t(buffer, NULL);
  3533. }
  3534. fclose(fp);
  3535. return old_pid;
  3536. }
  3537. /**
  3538. * Kill previous process
  3539. *
  3540. * Kill previous process whether it was not closed.
  3541. *
  3542. * @param filename is the full name of the file.
  3543. * @param pid that identifies the process
  3544. */
  3545. static void ebpf_kill_previous_process(char *filename, pid_t pid)
  3546. {
  3547. pid_t old_pid = ebpf_read_previous_pid(filename);
  3548. if (!old_pid)
  3549. return;
  3550. // Process is not running
  3551. char *prev_name = ebpf_get_process_name(old_pid);
  3552. if (!prev_name)
  3553. return;
  3554. char *current_name = ebpf_get_process_name(pid);
  3555. if (!strcmp(prev_name, current_name))
  3556. kill(old_pid, SIGKILL);
  3557. freez(prev_name);
  3558. freez(current_name);
  3559. // wait few microseconds before start new plugin
  3560. sleep_usec(USEC_PER_MS * 300);
  3561. }
  3562. /**
  3563. * PID file
  3564. *
  3565. * Write the filename for PID inside the given vector.
  3566. *
  3567. * @param filename vector where we will store the name.
  3568. * @param length number of bytes available in filename vector
  3569. */
  3570. void ebpf_pid_file(char *filename, size_t length)
  3571. {
  3572. snprintfz(filename, length, "%s/var/run/ebpf.pid", netdata_configured_host_prefix);
  3573. }
  3574. /**
  3575. * Manage PID
  3576. *
  3577. * This function kills another instance of eBPF whether it is necessary and update the file content.
  3578. *
  3579. * @param pid that identifies the process
  3580. */
  3581. static void ebpf_manage_pid(pid_t pid)
  3582. {
  3583. char filename[FILENAME_MAX + 1];
  3584. ebpf_pid_file(filename, FILENAME_MAX);
  3585. ebpf_kill_previous_process(filename, pid);
  3586. ebpf_update_pid_file(filename, pid);
  3587. }
  3588. /**
  3589. * Set start routine
  3590. *
  3591. * Set static routine before threads to be created.
  3592. */
  3593. static void ebpf_set_static_routine()
  3594. {
  3595. int i;
  3596. for (i = 0; ebpf_modules[i].info.thread_name; i++) {
  3597. ebpf_threads[i].start_routine = ebpf_modules[i].functions.start_routine;
  3598. }
  3599. }
  3600. /**
  3601. * Entry point
  3602. *
  3603. * @param argc the number of arguments
  3604. * @param argv the pointer to the arguments
  3605. *
  3606. * @return it returns 0 on success and another integer otherwise
  3607. */
  3608. int main(int argc, char **argv)
  3609. {
  3610. clocks_init();
  3611. nd_log_initialize_for_external_plugins("ebpf.plugin");
  3612. main_thread_id = gettid();
  3613. set_global_variables();
  3614. ebpf_parse_args(argc, argv);
  3615. ebpf_manage_pid(getpid());
  3616. if (ebpf_check_conditions())
  3617. return 2;
  3618. if (ebpf_adjust_memory_limit())
  3619. return 3;
  3620. signal(SIGINT, ebpf_stop_threads);
  3621. signal(SIGQUIT, ebpf_stop_threads);
  3622. signal(SIGTERM, ebpf_stop_threads);
  3623. signal(SIGPIPE, ebpf_stop_threads);
  3624. ebpf_start_pthread_variables();
  3625. netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
  3626. if(verify_netdata_host_prefix(true) == -1) ebpf_exit(6);
  3627. ebpf_allocate_common_vectors();
  3628. #ifdef LIBBPF_MAJOR_VERSION
  3629. libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
  3630. #endif
  3631. ebpf_read_local_addresses_unsafe();
  3632. read_local_ports("/proc/net/tcp", IPPROTO_TCP);
  3633. read_local_ports("/proc/net/tcp6", IPPROTO_TCP);
  3634. read_local_ports("/proc/net/udp", IPPROTO_UDP);
  3635. read_local_ports("/proc/net/udp6", IPPROTO_UDP);
  3636. ebpf_set_static_routine();
  3637. cgroup_integration_thread.thread = mallocz(sizeof(netdata_thread_t));
  3638. cgroup_integration_thread.start_routine = ebpf_cgroup_integration;
  3639. netdata_thread_create(cgroup_integration_thread.thread, cgroup_integration_thread.name,
  3640. NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
  3641. int i;
  3642. for (i = 0; ebpf_threads[i].name != NULL; i++) {
  3643. struct netdata_static_thread *st = &ebpf_threads[i];
  3644. ebpf_module_t *em = &ebpf_modules[i];
  3645. em->thread = st;
  3646. em->thread_id = i;
  3647. if (em->enabled != NETDATA_THREAD_EBPF_NOT_RUNNING) {
  3648. st->thread = mallocz(sizeof(netdata_thread_t));
  3649. em->enabled = NETDATA_THREAD_EBPF_RUNNING;
  3650. em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
  3651. netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
  3652. } else {
  3653. em->lifetime = EBPF_DEFAULT_LIFETIME;
  3654. }
  3655. }
  3656. usec_t step = USEC_PER_SEC;
  3657. heartbeat_t hb;
  3658. heartbeat_init(&hb);
  3659. int update_apps_every = (int) EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
  3660. int update_apps_list = update_apps_every - 1;
  3661. int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
  3662. //Plugin will be killed when it receives a signal
  3663. for ( ; !ebpf_plugin_exit; global_iterations_counter++) {
  3664. (void)heartbeat_next(&hb, step);
  3665. if (global_iterations_counter % EBPF_DEFAULT_UPDATE_EVERY == 0) {
  3666. pthread_mutex_lock(&lock);
  3667. ebpf_create_statistic_charts(EBPF_DEFAULT_UPDATE_EVERY);
  3668. ebpf_send_statistic_data();
  3669. pthread_mutex_unlock(&lock);
  3670. fflush(stdout);
  3671. }
  3672. pthread_mutex_lock(&ebpf_exit_cleanup);
  3673. pthread_mutex_lock(&collect_data_mutex);
  3674. if (++update_apps_list == update_apps_every) {
  3675. update_apps_list = 0;
  3676. cleanup_exited_pids();
  3677. collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
  3678. pthread_mutex_lock(&lock);
  3679. ebpf_create_apps_charts(apps_groups_root_target);
  3680. pthread_mutex_unlock(&lock);
  3681. }
  3682. pthread_mutex_unlock(&collect_data_mutex);
  3683. pthread_mutex_unlock(&ebpf_exit_cleanup);
  3684. }
  3685. ebpf_stop_threads(0);
  3686. return 0;
  3687. }