ebpf_socket.c 146 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include <sys/resource.h>
  3. #include "ebpf.h"
  4. #include "ebpf_socket.h"
  5. /*****************************************************************
  6. *
  7. * GLOBAL VARIABLES
  8. *
  9. *****************************************************************/
  10. static char *socket_dimension_names[NETDATA_MAX_SOCKET_VECTOR] = { "received", "sent", "close",
  11. "received", "sent", "retransmitted",
  12. "connected_V4", "connected_V6", "connected_tcp",
  13. "connected_udp"};
  14. static char *socket_id_names[NETDATA_MAX_SOCKET_VECTOR] = { "tcp_cleanup_rbuf", "tcp_sendmsg", "tcp_close",
  15. "udp_recvmsg", "udp_sendmsg", "tcp_retransmit_skb",
  16. "tcp_connect_v4", "tcp_connect_v6", "inet_csk_accept_tcp",
  17. "inet_csk_accept_udp" };
  18. static ebpf_local_maps_t socket_maps[] = {{.name = "tbl_bandwidth",
  19. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  20. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
  21. .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
  22. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  23. {.name = "tbl_global_sock",
  24. .internal_input = NETDATA_SOCKET_COUNTER,
  25. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  26. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  27. {.name = "tbl_lports",
  28. .internal_input = NETDATA_SOCKET_COUNTER,
  29. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  30. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  31. {.name = "tbl_conn_ipv4",
  32. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  33. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
  34. .type = NETDATA_EBPF_MAP_STATIC,
  35. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  36. {.name = "tbl_conn_ipv6",
  37. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  38. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED,
  39. .type = NETDATA_EBPF_MAP_STATIC,
  40. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  41. {.name = "tbl_nv_udp",
  42. .internal_input = NETDATA_COMPILED_UDP_CONNECTIONS_ALLOWED,
  43. .user_input = NETDATA_MAXIMUM_UDP_CONNECTIONS_ALLOWED,
  44. .type = NETDATA_EBPF_MAP_STATIC,
  45. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  46. {.name = "socket_ctrl", .internal_input = NETDATA_CONTROLLER_END,
  47. .user_input = 0,
  48. .type = NETDATA_EBPF_MAP_CONTROLLER,
  49. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  50. {.name = NULL, .internal_input = 0, .user_input = 0}};
  51. static netdata_idx_t *socket_hash_values = NULL;
  52. static netdata_syscall_stat_t socket_aggregated_data[NETDATA_MAX_SOCKET_VECTOR];
  53. static netdata_publish_syscall_t socket_publish_aggregated[NETDATA_MAX_SOCKET_VECTOR];
  54. ebpf_socket_publish_apps_t **socket_bandwidth_curr = NULL;
  55. static ebpf_bandwidth_t *bandwidth_vector = NULL;
  56. pthread_mutex_t nv_mutex;
  57. int wait_to_plot = 0;
  58. netdata_vector_plot_t inbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
  59. netdata_vector_plot_t outbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
  60. netdata_socket_t *socket_values;
  61. ebpf_network_viewer_port_list_t *listen_ports = NULL;
  62. struct config socket_config = { .first_section = NULL,
  63. .last_section = NULL,
  64. .mutex = NETDATA_MUTEX_INITIALIZER,
  65. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  66. .rwlock = AVL_LOCK_INITIALIZER } };
  67. netdata_ebpf_targets_t socket_targets[] = { {.name = "inet_csk_accept", .mode = EBPF_LOAD_TRAMPOLINE},
  68. {.name = "tcp_retransmit_skb", .mode = EBPF_LOAD_TRAMPOLINE},
  69. {.name = "tcp_cleanup_rbuf", .mode = EBPF_LOAD_TRAMPOLINE},
  70. {.name = "tcp_close", .mode = EBPF_LOAD_TRAMPOLINE},
  71. {.name = "udp_recvmsg", .mode = EBPF_LOAD_TRAMPOLINE},
  72. {.name = "tcp_sendmsg", .mode = EBPF_LOAD_TRAMPOLINE},
  73. {.name = "udp_sendmsg", .mode = EBPF_LOAD_TRAMPOLINE},
  74. {.name = "tcp_v4_connect", .mode = EBPF_LOAD_TRAMPOLINE},
  75. {.name = "tcp_v6_connect", .mode = EBPF_LOAD_TRAMPOLINE},
  76. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  77. struct netdata_static_thread socket_threads = {
  78. .name = "EBPF SOCKET READ",
  79. .config_section = NULL,
  80. .config_name = NULL,
  81. .env_name = NULL,
  82. .enabled = 1,
  83. .thread = NULL,
  84. .init_routine = NULL,
  85. .start_routine = NULL
  86. };
  87. static enum ebpf_threads_status ebpf_socket_exited = NETDATA_THREAD_EBPF_RUNNING;
  88. #ifdef LIBBPF_MAJOR_VERSION
  89. #include "includes/socket.skel.h" // BTF code
  90. static struct socket_bpf *bpf_obj = NULL;
  91. /**
  92. * Disable Probe
  93. *
  94. * Disable probes to use trampoline.
  95. *
  96. * @param obj is the main structure for bpf objects.
  97. */
  98. static void ebpf_socket_disable_probes(struct socket_bpf *obj)
  99. {
  100. bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_kretprobe, false);
  101. bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kretprobe, false);
  102. bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kretprobe, false);
  103. bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_kprobe, false);
  104. bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_kprobe, false);
  105. bpf_program__set_autoload(obj->progs.netdata_tcp_close_kprobe, false);
  106. bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_kprobe, false);
  107. bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_kretprobe, false);
  108. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kretprobe, false);
  109. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kprobe, false);
  110. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kretprobe, false);
  111. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kprobe, false);
  112. bpf_program__set_autoload(obj->progs.netdata_socket_release_task_kprobe, false);
  113. }
  114. /**
  115. * Disable Trampoline
  116. *
  117. * Disable trampoline to use probes.
  118. *
  119. * @param obj is the main structure for bpf objects.
  120. */
  121. static void ebpf_socket_disable_trampoline(struct socket_bpf *obj)
  122. {
  123. bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_fentry, false);
  124. bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fexit, false);
  125. bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fexit, false);
  126. bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_fentry, false);
  127. bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_fentry, false);
  128. bpf_program__set_autoload(obj->progs.netdata_tcp_close_fentry, false);
  129. bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_fentry, false);
  130. bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_fexit, false);
  131. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fentry, false);
  132. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fexit, false);
  133. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fentry, false);
  134. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fexit, false);
  135. bpf_program__set_autoload(obj->progs.netdata_socket_release_task_fentry, false);
  136. }
  137. /**
  138. * Set trampoline target.
  139. *
  140. * @param obj is the main structure for bpf objects.
  141. */
  142. static void ebpf_set_trampoline_target(struct socket_bpf *obj)
  143. {
  144. bpf_program__set_attach_target(obj->progs.netdata_inet_csk_accept_fentry, 0,
  145. socket_targets[NETDATA_FCNT_INET_CSK_ACCEPT].name);
  146. bpf_program__set_attach_target(obj->progs.netdata_tcp_v4_connect_fexit, 0,
  147. socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
  148. bpf_program__set_attach_target(obj->progs.netdata_tcp_v6_connect_fexit, 0,
  149. socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
  150. bpf_program__set_attach_target(obj->progs.netdata_tcp_retransmit_skb_fentry, 0,
  151. socket_targets[NETDATA_FCNT_TCP_RETRANSMIT].name);
  152. bpf_program__set_attach_target(obj->progs.netdata_tcp_cleanup_rbuf_fentry, 0,
  153. socket_targets[NETDATA_FCNT_CLEANUP_RBUF].name);
  154. bpf_program__set_attach_target(obj->progs.netdata_tcp_close_fentry, 0, socket_targets[NETDATA_FCNT_TCP_CLOSE].name);
  155. bpf_program__set_attach_target(obj->progs.netdata_udp_recvmsg_fentry, 0,
  156. socket_targets[NETDATA_FCNT_UDP_RECEVMSG].name);
  157. bpf_program__set_attach_target(obj->progs.netdata_udp_recvmsg_fexit, 0,
  158. socket_targets[NETDATA_FCNT_UDP_RECEVMSG].name);
  159. bpf_program__set_attach_target(obj->progs.netdata_tcp_sendmsg_fentry, 0,
  160. socket_targets[NETDATA_FCNT_TCP_SENDMSG].name);
  161. bpf_program__set_attach_target(obj->progs.netdata_tcp_sendmsg_fexit, 0,
  162. socket_targets[NETDATA_FCNT_TCP_SENDMSG].name);
  163. bpf_program__set_attach_target(obj->progs.netdata_udp_sendmsg_fentry, 0,
  164. socket_targets[NETDATA_FCNT_UDP_SENDMSG].name);
  165. bpf_program__set_attach_target(obj->progs.netdata_udp_sendmsg_fexit, 0,
  166. socket_targets[NETDATA_FCNT_UDP_SENDMSG].name);
  167. bpf_program__set_attach_target(obj->progs.netdata_socket_release_task_fentry, 0, EBPF_COMMON_FNCT_CLEAN_UP);
  168. }
  169. /**
  170. * Disable specific trampoline
  171. *
  172. * Disable specific trampoline to match user selection.
  173. *
  174. * @param obj is the main structure for bpf objects.
  175. * @param sel option selected by user.
  176. */
  177. static inline void ebpf_socket_disable_specific_trampoline(struct socket_bpf *obj, netdata_run_mode_t sel)
  178. {
  179. if (sel == MODE_RETURN) {
  180. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fentry, false);
  181. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fentry, false);
  182. } else {
  183. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fexit, false);
  184. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_fexit, false);
  185. }
  186. }
  187. /**
  188. * Disable specific probe
  189. *
  190. * Disable specific probe to match user selection.
  191. *
  192. * @param obj is the main structure for bpf objects.
  193. * @param sel option selected by user.
  194. */
  195. static inline void ebpf_socket_disable_specific_probe(struct socket_bpf *obj, netdata_run_mode_t sel)
  196. {
  197. if (sel == MODE_RETURN) {
  198. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kprobe, false);
  199. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kprobe, false);
  200. } else {
  201. bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kretprobe, false);
  202. bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kretprobe, false);
  203. }
  204. }
  205. /**
  206. * Attach probes
  207. *
  208. * Attach probes to targets.
  209. *
  210. * @param obj is the main structure for bpf objects.
  211. * @param sel option selected by user.
  212. */
  213. static int ebpf_socket_attach_probes(struct socket_bpf *obj, netdata_run_mode_t sel)
  214. {
  215. obj->links.netdata_inet_csk_accept_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_inet_csk_accept_kretprobe,
  216. true,
  217. socket_targets[NETDATA_FCNT_INET_CSK_ACCEPT].name);
  218. int ret = libbpf_get_error(obj->links.netdata_inet_csk_accept_kretprobe);
  219. if (ret)
  220. return -1;
  221. obj->links.netdata_tcp_v4_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v4_connect_kretprobe,
  222. true,
  223. socket_targets[NETDATA_FCNT_TCP_V4_CONNECT].name);
  224. ret = libbpf_get_error(obj->links.netdata_tcp_v4_connect_kretprobe);
  225. if (ret)
  226. return -1;
  227. obj->links.netdata_tcp_v6_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v6_connect_kretprobe,
  228. true,
  229. socket_targets[NETDATA_FCNT_TCP_V6_CONNECT].name);
  230. ret = libbpf_get_error(obj->links.netdata_tcp_v6_connect_kretprobe);
  231. if (ret)
  232. return -1;
  233. obj->links.netdata_tcp_retransmit_skb_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_retransmit_skb_kprobe,
  234. false,
  235. socket_targets[NETDATA_FCNT_TCP_RETRANSMIT].name);
  236. ret = libbpf_get_error(obj->links.netdata_tcp_retransmit_skb_kprobe);
  237. if (ret)
  238. return -1;
  239. obj->links.netdata_tcp_cleanup_rbuf_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_cleanup_rbuf_kprobe,
  240. false,
  241. socket_targets[NETDATA_FCNT_CLEANUP_RBUF].name);
  242. ret = libbpf_get_error(obj->links.netdata_tcp_cleanup_rbuf_kprobe);
  243. if (ret)
  244. return -1;
  245. obj->links.netdata_tcp_close_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_close_kprobe,
  246. false,
  247. socket_targets[NETDATA_FCNT_TCP_CLOSE].name);
  248. ret = libbpf_get_error(obj->links.netdata_tcp_close_kprobe);
  249. if (ret)
  250. return -1;
  251. obj->links.netdata_udp_recvmsg_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_udp_recvmsg_kprobe,
  252. false,
  253. socket_targets[NETDATA_FCNT_UDP_RECEVMSG].name);
  254. ret = libbpf_get_error(obj->links.netdata_udp_recvmsg_kprobe);
  255. if (ret)
  256. return -1;
  257. obj->links.netdata_udp_recvmsg_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_udp_recvmsg_kretprobe,
  258. true,
  259. socket_targets[NETDATA_FCNT_UDP_RECEVMSG].name);
  260. ret = libbpf_get_error(obj->links.netdata_udp_recvmsg_kretprobe);
  261. if (ret)
  262. return -1;
  263. if (sel == MODE_RETURN) {
  264. obj->links.netdata_tcp_sendmsg_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_sendmsg_kretprobe,
  265. true,
  266. socket_targets[NETDATA_FCNT_TCP_SENDMSG].name);
  267. ret = libbpf_get_error(obj->links.netdata_tcp_sendmsg_kretprobe);
  268. if (ret)
  269. return -1;
  270. obj->links.netdata_udp_sendmsg_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_udp_sendmsg_kretprobe,
  271. true,
  272. socket_targets[NETDATA_FCNT_UDP_SENDMSG].name);
  273. ret = libbpf_get_error(obj->links.netdata_udp_sendmsg_kretprobe);
  274. if (ret)
  275. return -1;
  276. } else {
  277. obj->links.netdata_tcp_sendmsg_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_sendmsg_kprobe,
  278. false,
  279. socket_targets[NETDATA_FCNT_TCP_SENDMSG].name);
  280. ret = libbpf_get_error(obj->links.netdata_tcp_sendmsg_kprobe);
  281. if (ret)
  282. return -1;
  283. obj->links.netdata_udp_sendmsg_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_udp_sendmsg_kprobe,
  284. false,
  285. socket_targets[NETDATA_FCNT_UDP_SENDMSG].name);
  286. ret = libbpf_get_error(obj->links.netdata_udp_sendmsg_kprobe);
  287. if (ret)
  288. return -1;
  289. }
  290. obj->links.netdata_socket_release_task_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_socket_release_task_kprobe,
  291. false, EBPF_COMMON_FNCT_CLEAN_UP);
  292. ret = libbpf_get_error(obj->links.netdata_socket_release_task_kprobe);
  293. if (ret)
  294. return -1;
  295. return 0;
  296. }
  297. /**
  298. * Set hash tables
  299. *
  300. * Set the values for maps according the value given by kernel.
  301. *
  302. * @param obj is the main structure for bpf objects.
  303. */
  304. static void ebpf_socket_set_hash_tables(struct socket_bpf *obj)
  305. {
  306. socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd = bpf_map__fd(obj->maps.tbl_bandwidth);
  307. socket_maps[NETDATA_SOCKET_GLOBAL].map_fd = bpf_map__fd(obj->maps.tbl_global_sock);
  308. socket_maps[NETDATA_SOCKET_LPORTS].map_fd = bpf_map__fd(obj->maps.tbl_lports);
  309. socket_maps[NETDATA_SOCKET_TABLE_IPV4].map_fd = bpf_map__fd(obj->maps.tbl_conn_ipv4);
  310. socket_maps[NETDATA_SOCKET_TABLE_IPV6].map_fd = bpf_map__fd(obj->maps.tbl_conn_ipv6);
  311. socket_maps[NETDATA_SOCKET_TABLE_UDP].map_fd = bpf_map__fd(obj->maps.tbl_nv_udp);
  312. socket_maps[NETDATA_SOCKET_TABLE_CTRL].map_fd = bpf_map__fd(obj->maps.socket_ctrl);
  313. }
  314. /**
  315. * Adjust Map Size
  316. *
  317. * Resize maps according input from users.
  318. *
  319. * @param obj is the main structure for bpf objects.
  320. * @param em structure with configuration
  321. */
  322. static void ebpf_socket_adjust_map_size(struct socket_bpf *obj, ebpf_module_t *em)
  323. {
  324. ebpf_update_map_size(obj->maps.tbl_bandwidth, &socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH],
  325. em, bpf_map__name(obj->maps.tbl_bandwidth));
  326. ebpf_update_map_size(obj->maps.tbl_conn_ipv4, &socket_maps[NETDATA_SOCKET_TABLE_IPV4],
  327. em, bpf_map__name(obj->maps.tbl_conn_ipv4));
  328. ebpf_update_map_size(obj->maps.tbl_conn_ipv6, &socket_maps[NETDATA_SOCKET_TABLE_IPV6],
  329. em, bpf_map__name(obj->maps.tbl_conn_ipv6));
  330. ebpf_update_map_size(obj->maps.tbl_nv_udp, &socket_maps[NETDATA_SOCKET_TABLE_UDP],
  331. em, bpf_map__name(obj->maps.tbl_nv_udp));
  332. }
  333. /**
  334. * Load and attach
  335. *
  336. * Load and attach the eBPF code in kernel.
  337. *
  338. * @param obj is the main structure for bpf objects.
  339. * @param em structure with configuration
  340. *
  341. * @return it returns 0 on succes and -1 otherwise
  342. */
  343. static inline int ebpf_socket_load_and_attach(struct socket_bpf *obj, ebpf_module_t *em)
  344. {
  345. netdata_ebpf_targets_t *mt = em->targets;
  346. netdata_ebpf_program_loaded_t test = mt[NETDATA_FCNT_INET_CSK_ACCEPT].mode;
  347. if (test == EBPF_LOAD_TRAMPOLINE) {
  348. ebpf_socket_disable_probes(obj);
  349. ebpf_set_trampoline_target(obj);
  350. ebpf_socket_disable_specific_trampoline(obj, em->mode);
  351. } else { // We are not using tracepoints for this thread.
  352. ebpf_socket_disable_trampoline(obj);
  353. ebpf_socket_disable_specific_probe(obj, em->mode);
  354. }
  355. int ret = socket_bpf__load(obj);
  356. if (ret) {
  357. fprintf(stderr, "failed to load BPF object: %d\n", ret);
  358. return ret;
  359. }
  360. ebpf_socket_adjust_map_size(obj, em);
  361. if (test == EBPF_LOAD_TRAMPOLINE) {
  362. ret = socket_bpf__attach(obj);
  363. } else {
  364. ret = ebpf_socket_attach_probes(obj, em->mode);
  365. }
  366. if (!ret) {
  367. ebpf_socket_set_hash_tables(obj);
  368. ebpf_update_controller(socket_maps[NETDATA_SOCKET_TABLE_CTRL].map_fd, em);
  369. }
  370. return ret;
  371. }
  372. #endif
  373. /*****************************************************************
  374. *
  375. * FUNCTIONS TO CLOSE THE THREAD
  376. *
  377. *****************************************************************/
  378. /**
  379. * Clean internal socket plot
  380. *
  381. * Clean all structures allocated with strdupz.
  382. *
  383. * @param ptr the pointer with addresses to clean.
  384. */
  385. static inline void clean_internal_socket_plot(netdata_socket_plot_t *ptr)
  386. {
  387. freez(ptr->dimension_recv);
  388. freez(ptr->dimension_sent);
  389. freez(ptr->resolved_name);
  390. freez(ptr->dimension_retransmit);
  391. }
  392. /**
  393. * Clean socket plot
  394. *
  395. * Clean the allocated data for inbound and outbound vectors.
  396. */
  397. static void clean_allocated_socket_plot()
  398. {
  399. uint32_t i;
  400. uint32_t end = inbound_vectors.last;
  401. netdata_socket_plot_t *plot = inbound_vectors.plot;
  402. for (i = 0; i < end; i++) {
  403. clean_internal_socket_plot(&plot[i]);
  404. }
  405. clean_internal_socket_plot(&plot[inbound_vectors.last]);
  406. end = outbound_vectors.last;
  407. plot = outbound_vectors.plot;
  408. for (i = 0; i < end; i++) {
  409. clean_internal_socket_plot(&plot[i]);
  410. }
  411. clean_internal_socket_plot(&plot[outbound_vectors.last]);
  412. }
  413. /**
  414. * Clean network ports allocated during initialization.
  415. *
  416. * @param ptr a pointer to the link list.
  417. */
  418. static void clean_network_ports(ebpf_network_viewer_port_list_t *ptr)
  419. {
  420. if (unlikely(!ptr))
  421. return;
  422. while (ptr) {
  423. ebpf_network_viewer_port_list_t *next = ptr->next;
  424. freez(ptr->value);
  425. freez(ptr);
  426. ptr = next;
  427. }
  428. }
  429. /**
  430. * Clean service names
  431. *
  432. * Clean the allocated link list that stores names.
  433. *
  434. * @param names the link list.
  435. */
  436. static void clean_service_names(ebpf_network_viewer_dim_name_t *names)
  437. {
  438. if (unlikely(!names))
  439. return;
  440. while (names) {
  441. ebpf_network_viewer_dim_name_t *next = names->next;
  442. freez(names->name);
  443. freez(names);
  444. names = next;
  445. }
  446. }
  447. /**
  448. * Clean hostnames
  449. *
  450. * @param hostnames the hostnames to clean
  451. */
  452. static void clean_hostnames(ebpf_network_viewer_hostname_list_t *hostnames)
  453. {
  454. if (unlikely(!hostnames))
  455. return;
  456. while (hostnames) {
  457. ebpf_network_viewer_hostname_list_t *next = hostnames->next;
  458. freez(hostnames->value);
  459. simple_pattern_free(hostnames->value_pattern);
  460. freez(hostnames);
  461. hostnames = next;
  462. }
  463. }
  464. /**
  465. * Cleanup publish syscall
  466. *
  467. * @param nps list of structures to clean
  468. */
  469. void ebpf_cleanup_publish_syscall(netdata_publish_syscall_t *nps)
  470. {
  471. while (nps) {
  472. freez(nps->algorithm);
  473. nps = nps->next;
  474. }
  475. }
  476. /**
  477. * Clean port Structure
  478. *
  479. * Clean the allocated list.
  480. *
  481. * @param clean the list that will be cleaned
  482. */
  483. void clean_port_structure(ebpf_network_viewer_port_list_t **clean)
  484. {
  485. ebpf_network_viewer_port_list_t *move = *clean;
  486. while (move) {
  487. ebpf_network_viewer_port_list_t *next = move->next;
  488. freez(move->value);
  489. freez(move);
  490. move = next;
  491. }
  492. *clean = NULL;
  493. }
  494. /**
  495. * Clean IP structure
  496. *
  497. * Clean the allocated list.
  498. *
  499. * @param clean the list that will be cleaned
  500. */
  501. static void clean_ip_structure(ebpf_network_viewer_ip_list_t **clean)
  502. {
  503. ebpf_network_viewer_ip_list_t *move = *clean;
  504. while (move) {
  505. ebpf_network_viewer_ip_list_t *next = move->next;
  506. freez(move->value);
  507. freez(move);
  508. move = next;
  509. }
  510. *clean = NULL;
  511. }
  512. /**
  513. * Socket exit
  514. *
  515. * Clean up the main thread.
  516. *
  517. * @param ptr thread data.
  518. */
  519. static void ebpf_socket_exit(void *ptr)
  520. {
  521. ebpf_module_t *em = (ebpf_module_t *)ptr;
  522. if (!em->enabled) {
  523. em->enabled = NETDATA_MAIN_THREAD_EXITED;
  524. return;
  525. }
  526. ebpf_socket_exited = NETDATA_THREAD_EBPF_STOPPING;
  527. }
  528. /**
  529. * Socket cleanup
  530. *
  531. * Clean up allocated addresses.
  532. *
  533. * @param ptr thread data.
  534. */
  535. void ebpf_socket_cleanup(void *ptr)
  536. {
  537. ebpf_module_t *em = (ebpf_module_t *)ptr;
  538. if (ebpf_socket_exited != NETDATA_THREAD_EBPF_STOPPED)
  539. return;
  540. ebpf_cleanup_publish_syscall(socket_publish_aggregated);
  541. freez(socket_hash_values);
  542. freez(bandwidth_vector);
  543. freez(socket_values);
  544. clean_allocated_socket_plot();
  545. freez(inbound_vectors.plot);
  546. freez(outbound_vectors.plot);
  547. clean_port_structure(&listen_ports);
  548. ebpf_modules[EBPF_MODULE_SOCKET_IDX].enabled = 0;
  549. clean_network_ports(network_viewer_opt.included_port);
  550. clean_network_ports(network_viewer_opt.excluded_port);
  551. clean_service_names(network_viewer_opt.names);
  552. clean_hostnames(network_viewer_opt.included_hostnames);
  553. clean_hostnames(network_viewer_opt.excluded_hostnames);
  554. pthread_mutex_destroy(&nv_mutex);
  555. freez(socket_threads.thread);
  556. #ifdef LIBBPF_MAJOR_VERSION
  557. if (bpf_obj)
  558. socket_bpf__destroy(bpf_obj);
  559. #endif
  560. socket_threads.enabled = NETDATA_MAIN_THREAD_EXITED;
  561. em->enabled = NETDATA_MAIN_THREAD_EXITED;
  562. }
  563. /*****************************************************************
  564. *
  565. * PROCESS DATA AND SEND TO NETDATA
  566. *
  567. *****************************************************************/
  568. /**
  569. * Update publish structure before to send data to Netdata.
  570. *
  571. * @param publish the first output structure with independent dimensions
  572. * @param tcp structure to store IO from tcp sockets
  573. * @param udp structure to store IO from udp sockets
  574. * @param input the structure with the input data.
  575. */
  576. static void ebpf_update_global_publish(
  577. netdata_publish_syscall_t *publish, netdata_publish_vfs_common_t *tcp, netdata_publish_vfs_common_t *udp,
  578. netdata_syscall_stat_t *input)
  579. {
  580. netdata_publish_syscall_t *move = publish;
  581. while (move) {
  582. if (input->call != move->pcall) {
  583. // This condition happens to avoid initial values with dimensions higher than normal values.
  584. if (move->pcall) {
  585. move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
  586. move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
  587. move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
  588. } else {
  589. move->ncall = 0;
  590. move->nbyte = 0;
  591. move->nerr = 0;
  592. }
  593. move->pcall = input->call;
  594. move->pbyte = input->bytes;
  595. move->perr = input->ecall;
  596. } else {
  597. move->ncall = 0;
  598. move->nbyte = 0;
  599. move->nerr = 0;
  600. }
  601. input = input->next;
  602. move = move->next;
  603. }
  604. tcp->write = -(long)publish[0].nbyte;
  605. tcp->read = (long)publish[1].nbyte;
  606. udp->write = -(long)publish[3].nbyte;
  607. udp->read = (long)publish[4].nbyte;
  608. }
  609. /**
  610. * Update Network Viewer plot data
  611. *
  612. * @param plot the structure where the data will be stored
  613. * @param sock the last update from the socket
  614. */
  615. static inline void update_nv_plot_data(netdata_plot_values_t *plot, netdata_socket_t *sock)
  616. {
  617. if (sock->ct > plot->last_time) {
  618. plot->last_time = sock->ct;
  619. plot->plot_recv_packets = sock->recv_packets;
  620. plot->plot_sent_packets = sock->sent_packets;
  621. plot->plot_recv_bytes = sock->recv_bytes;
  622. plot->plot_sent_bytes = sock->sent_bytes;
  623. plot->plot_retransmit = sock->retransmit;
  624. }
  625. sock->recv_packets = 0;
  626. sock->sent_packets = 0;
  627. sock->recv_bytes = 0;
  628. sock->sent_bytes = 0;
  629. sock->retransmit = 0;
  630. }
  631. /**
  632. * Calculate Network Viewer Plot
  633. *
  634. * Do math with collected values before to plot data.
  635. */
  636. static inline void calculate_nv_plot()
  637. {
  638. uint32_t i;
  639. uint32_t end = inbound_vectors.next;
  640. for (i = 0; i < end; i++) {
  641. update_nv_plot_data(&inbound_vectors.plot[i].plot, &inbound_vectors.plot[i].sock);
  642. }
  643. inbound_vectors.max_plot = end;
  644. // The 'Other' dimension is always calculated for the chart to have at least one dimension
  645. update_nv_plot_data(&inbound_vectors.plot[inbound_vectors.last].plot,
  646. &inbound_vectors.plot[inbound_vectors.last].sock);
  647. end = outbound_vectors.next;
  648. for (i = 0; i < end; i++) {
  649. update_nv_plot_data(&outbound_vectors.plot[i].plot, &outbound_vectors.plot[i].sock);
  650. }
  651. outbound_vectors.max_plot = end;
  652. // The 'Other' dimension is always calculated for the chart to have at least one dimension
  653. update_nv_plot_data(&outbound_vectors.plot[outbound_vectors.last].plot,
  654. &outbound_vectors.plot[outbound_vectors.last].sock);
  655. }
  656. /**
  657. * Network viewer send bytes
  658. *
  659. * @param ptr the structure with values to plot
  660. * @param chart the chart name.
  661. */
  662. static inline void ebpf_socket_nv_send_bytes(netdata_vector_plot_t *ptr, char *chart)
  663. {
  664. uint32_t i;
  665. uint32_t end = ptr->last_plot;
  666. netdata_socket_plot_t *w = ptr->plot;
  667. collected_number value;
  668. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  669. for (i = 0; i < end; i++) {
  670. value = ((collected_number) w[i].plot.plot_sent_bytes);
  671. write_chart_dimension(w[i].dimension_sent, value);
  672. value = (collected_number) w[i].plot.plot_recv_bytes;
  673. write_chart_dimension(w[i].dimension_recv, value);
  674. }
  675. i = ptr->last;
  676. value = ((collected_number) w[i].plot.plot_sent_bytes);
  677. write_chart_dimension(w[i].dimension_sent, value);
  678. value = (collected_number) w[i].plot.plot_recv_bytes;
  679. write_chart_dimension(w[i].dimension_recv, value);
  680. write_end_chart();
  681. }
  682. /**
  683. * Network Viewer Send packets
  684. *
  685. * @param ptr the structure with values to plot
  686. * @param chart the chart name.
  687. */
  688. static inline void ebpf_socket_nv_send_packets(netdata_vector_plot_t *ptr, char *chart)
  689. {
  690. uint32_t i;
  691. uint32_t end = ptr->last_plot;
  692. netdata_socket_plot_t *w = ptr->plot;
  693. collected_number value;
  694. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  695. for (i = 0; i < end; i++) {
  696. value = ((collected_number)w[i].plot.plot_sent_packets);
  697. write_chart_dimension(w[i].dimension_sent, value);
  698. value = (collected_number) w[i].plot.plot_recv_packets;
  699. write_chart_dimension(w[i].dimension_recv, value);
  700. }
  701. i = ptr->last;
  702. value = ((collected_number)w[i].plot.plot_sent_packets);
  703. write_chart_dimension(w[i].dimension_sent, value);
  704. value = (collected_number)w[i].plot.plot_recv_packets;
  705. write_chart_dimension(w[i].dimension_recv, value);
  706. write_end_chart();
  707. }
  708. /**
  709. * Network Viewer Send Retransmit
  710. *
  711. * @param ptr the structure with values to plot
  712. * @param chart the chart name.
  713. */
  714. static inline void ebpf_socket_nv_send_retransmit(netdata_vector_plot_t *ptr, char *chart)
  715. {
  716. uint32_t i;
  717. uint32_t end = ptr->last_plot;
  718. netdata_socket_plot_t *w = ptr->plot;
  719. collected_number value;
  720. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  721. for (i = 0; i < end; i++) {
  722. value = (collected_number) w[i].plot.plot_retransmit;
  723. write_chart_dimension(w[i].dimension_retransmit, value);
  724. }
  725. i = ptr->last;
  726. value = (collected_number)w[i].plot.plot_retransmit;
  727. write_chart_dimension(w[i].dimension_retransmit, value);
  728. write_end_chart();
  729. }
  730. /**
  731. * Send network viewer data
  732. *
  733. * @param ptr the pointer to plot data
  734. */
  735. static void ebpf_socket_send_nv_data(netdata_vector_plot_t *ptr)
  736. {
  737. if (!ptr->flags)
  738. return;
  739. if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
  740. ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_OUTBOUND_BYTES);
  741. fflush(stdout);
  742. ebpf_socket_nv_send_packets(ptr, NETDATA_NV_OUTBOUND_PACKETS);
  743. fflush(stdout);
  744. ebpf_socket_nv_send_retransmit(ptr, NETDATA_NV_OUTBOUND_RETRANSMIT);
  745. fflush(stdout);
  746. } else {
  747. ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_INBOUND_BYTES);
  748. fflush(stdout);
  749. ebpf_socket_nv_send_packets(ptr, NETDATA_NV_INBOUND_PACKETS);
  750. fflush(stdout);
  751. }
  752. }
  753. /**
  754. * Send Global Inbound connection
  755. *
  756. * Send number of connections read per protocol.
  757. */
  758. static void ebpf_socket_send_global_inbound_conn()
  759. {
  760. uint64_t udp_conn = 0;
  761. uint64_t tcp_conn = 0;
  762. ebpf_network_viewer_port_list_t *move = listen_ports;
  763. while (move) {
  764. if (move->protocol == IPPROTO_TCP)
  765. tcp_conn += move->connections;
  766. else
  767. udp_conn += move->connections;
  768. move = move->next;
  769. }
  770. write_begin_chart(NETDATA_EBPF_IP_FAMILY, NETDATA_INBOUND_CONNECTIONS);
  771. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_INCOMING_CONNECTION_TCP].name, (long long) tcp_conn);
  772. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_INCOMING_CONNECTION_UDP].name, (long long) udp_conn);
  773. write_end_chart();
  774. }
  775. /**
  776. * Send data to Netdata calling auxiliary functions.
  777. *
  778. * @param em the structure with thread information
  779. */
  780. static void ebpf_socket_send_data(ebpf_module_t *em)
  781. {
  782. netdata_publish_vfs_common_t common_tcp;
  783. netdata_publish_vfs_common_t common_udp;
  784. ebpf_update_global_publish(socket_publish_aggregated, &common_tcp, &common_udp, socket_aggregated_data);
  785. ebpf_socket_send_global_inbound_conn();
  786. write_count_chart(NETDATA_TCP_OUTBOUND_CONNECTIONS, NETDATA_EBPF_IP_FAMILY,
  787. &socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V4], 2);
  788. // We read bytes from function arguments, but bandwidth is given in bits,
  789. // so we need to multiply by 8 to convert for the final value.
  790. write_count_chart(NETDATA_TCP_FUNCTION_COUNT, NETDATA_EBPF_IP_FAMILY, socket_publish_aggregated, 3);
  791. write_io_chart(NETDATA_TCP_FUNCTION_BITS, NETDATA_EBPF_IP_FAMILY, socket_id_names[0],
  792. common_tcp.read * 8/BITS_IN_A_KILOBIT, socket_id_names[1],
  793. common_tcp.write * 8/BITS_IN_A_KILOBIT);
  794. if (em->mode < MODE_ENTRY) {
  795. write_err_chart(NETDATA_TCP_FUNCTION_ERROR, NETDATA_EBPF_IP_FAMILY, socket_publish_aggregated, 2);
  796. }
  797. write_count_chart(NETDATA_TCP_RETRANSMIT, NETDATA_EBPF_IP_FAMILY,
  798. &socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT],1);
  799. write_count_chart(NETDATA_UDP_FUNCTION_COUNT, NETDATA_EBPF_IP_FAMILY,
  800. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],2);
  801. write_io_chart(NETDATA_UDP_FUNCTION_BITS, NETDATA_EBPF_IP_FAMILY,
  802. socket_id_names[3], (long long)common_udp.read * 8/BITS_IN_A_KILOBIT,
  803. socket_id_names[4], (long long)common_udp.write * 8/BITS_IN_A_KILOBIT);
  804. if (em->mode < MODE_ENTRY) {
  805. write_err_chart(NETDATA_UDP_FUNCTION_ERROR, NETDATA_EBPF_IP_FAMILY,
  806. &socket_publish_aggregated[NETDATA_UDP_START], 2);
  807. }
  808. }
  809. /**
  810. * Sum values for pid
  811. *
  812. * @param root the structure with all available PIDs
  813. *
  814. * @param offset the address that we are reading
  815. *
  816. * @return it returns the sum of all PIDs
  817. */
  818. long long ebpf_socket_sum_values_for_pids(struct pid_on_target *root, size_t offset)
  819. {
  820. long long ret = 0;
  821. while (root) {
  822. int32_t pid = root->pid;
  823. ebpf_socket_publish_apps_t *w = socket_bandwidth_curr[pid];
  824. if (w) {
  825. ret += get_value_from_structure((char *)w, offset);
  826. }
  827. root = root->next;
  828. }
  829. return ret;
  830. }
  831. /**
  832. * Send data to Netdata calling auxiliary functions.
  833. *
  834. * @param em the structure with thread information
  835. * @param root the target list.
  836. */
  837. void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
  838. {
  839. UNUSED(em);
  840. struct target *w;
  841. collected_number value;
  842. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_CONNECTION_TCP_V4);
  843. for (w = root; w; w = w->next) {
  844. if (unlikely(w->exposed && w->processes)) {
  845. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  846. call_tcp_v4_connection));
  847. write_chart_dimension(w->name, value);
  848. }
  849. }
  850. write_end_chart();
  851. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_CONNECTION_TCP_V6);
  852. for (w = root; w; w = w->next) {
  853. if (unlikely(w->exposed && w->processes)) {
  854. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  855. call_tcp_v6_connection));
  856. write_chart_dimension(w->name, value);
  857. }
  858. }
  859. write_end_chart();
  860. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_SENT);
  861. for (w = root; w; w = w->next) {
  862. if (unlikely(w->exposed && w->processes)) {
  863. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  864. bytes_sent));
  865. // We multiply by 0.008, because we read bytes, but we display bits
  866. write_chart_dimension(w->name, ((value)*8)/1000);
  867. }
  868. }
  869. write_end_chart();
  870. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_RECV);
  871. for (w = root; w; w = w->next) {
  872. if (unlikely(w->exposed && w->processes)) {
  873. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  874. bytes_received));
  875. // We multiply by 0.008, because we read bytes, but we display bits
  876. write_chart_dimension(w->name, ((value)*8)/1000);
  877. }
  878. }
  879. write_end_chart();
  880. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS);
  881. for (w = root; w; w = w->next) {
  882. if (unlikely(w->exposed && w->processes)) {
  883. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  884. call_tcp_sent));
  885. write_chart_dimension(w->name, value);
  886. }
  887. }
  888. write_end_chart();
  889. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS);
  890. for (w = root; w; w = w->next) {
  891. if (unlikely(w->exposed && w->processes)) {
  892. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  893. call_tcp_received));
  894. write_chart_dimension(w->name, value);
  895. }
  896. }
  897. write_end_chart();
  898. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT);
  899. for (w = root; w; w = w->next) {
  900. if (unlikely(w->exposed && w->processes)) {
  901. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  902. retransmit));
  903. write_chart_dimension(w->name, value);
  904. }
  905. }
  906. write_end_chart();
  907. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS);
  908. for (w = root; w; w = w->next) {
  909. if (unlikely(w->exposed && w->processes)) {
  910. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  911. call_udp_sent));
  912. write_chart_dimension(w->name, value);
  913. }
  914. }
  915. write_end_chart();
  916. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS);
  917. for (w = root; w; w = w->next) {
  918. if (unlikely(w->exposed && w->processes)) {
  919. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  920. call_udp_received));
  921. write_chart_dimension(w->name, value);
  922. }
  923. }
  924. write_end_chart();
  925. }
  926. /*****************************************************************
  927. *
  928. * FUNCTIONS TO CREATE CHARTS
  929. *
  930. *****************************************************************/
  931. /**
  932. * Create global charts
  933. *
  934. * Call ebpf_create_chart to create the charts for the collector.
  935. *
  936. * @param em a pointer to the structure with the default values.
  937. */
  938. static void ebpf_create_global_charts(ebpf_module_t *em)
  939. {
  940. int order = 21070;
  941. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  942. NETDATA_INBOUND_CONNECTIONS,
  943. "Inbound connections.",
  944. EBPF_COMMON_DIMENSION_CONNECTIONS,
  945. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  946. NULL,
  947. NETDATA_EBPF_CHART_TYPE_LINE,
  948. order++,
  949. ebpf_create_global_dimension,
  950. &socket_publish_aggregated[NETDATA_IDX_INCOMING_CONNECTION_TCP],
  951. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  952. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  953. NETDATA_TCP_OUTBOUND_CONNECTIONS,
  954. "TCP outbound connections.",
  955. EBPF_COMMON_DIMENSION_CONNECTIONS,
  956. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  957. NULL,
  958. NETDATA_EBPF_CHART_TYPE_LINE,
  959. order++,
  960. ebpf_create_global_dimension,
  961. &socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V4],
  962. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  963. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  964. NETDATA_TCP_FUNCTION_COUNT,
  965. "Calls to internal functions",
  966. EBPF_COMMON_DIMENSION_CALL,
  967. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  968. NULL,
  969. NETDATA_EBPF_CHART_TYPE_LINE,
  970. order++,
  971. ebpf_create_global_dimension,
  972. socket_publish_aggregated,
  973. 3, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  974. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY, NETDATA_TCP_FUNCTION_BITS,
  975. "TCP bandwidth", EBPF_COMMON_DIMENSION_BITS,
  976. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  977. NULL,
  978. NETDATA_EBPF_CHART_TYPE_LINE,
  979. order++,
  980. ebpf_create_global_dimension,
  981. socket_publish_aggregated,
  982. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  983. if (em->mode < MODE_ENTRY) {
  984. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  985. NETDATA_TCP_FUNCTION_ERROR,
  986. "TCP errors",
  987. EBPF_COMMON_DIMENSION_CALL,
  988. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  989. NULL,
  990. NETDATA_EBPF_CHART_TYPE_LINE,
  991. order++,
  992. ebpf_create_global_dimension,
  993. socket_publish_aggregated,
  994. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  995. }
  996. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  997. NETDATA_TCP_RETRANSMIT,
  998. "Packages retransmitted",
  999. EBPF_COMMON_DIMENSION_CALL,
  1000. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  1001. NULL,
  1002. NETDATA_EBPF_CHART_TYPE_LINE,
  1003. order++,
  1004. ebpf_create_global_dimension,
  1005. &socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT],
  1006. 1, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1007. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  1008. NETDATA_UDP_FUNCTION_COUNT,
  1009. "UDP calls",
  1010. EBPF_COMMON_DIMENSION_CALL,
  1011. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  1012. NULL,
  1013. NETDATA_EBPF_CHART_TYPE_LINE,
  1014. order++,
  1015. ebpf_create_global_dimension,
  1016. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  1017. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1018. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY, NETDATA_UDP_FUNCTION_BITS,
  1019. "UDP bandwidth", EBPF_COMMON_DIMENSION_BITS,
  1020. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  1021. NULL,
  1022. NETDATA_EBPF_CHART_TYPE_LINE,
  1023. order++,
  1024. ebpf_create_global_dimension,
  1025. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  1026. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1027. if (em->mode < MODE_ENTRY) {
  1028. ebpf_create_chart(NETDATA_EBPF_IP_FAMILY,
  1029. NETDATA_UDP_FUNCTION_ERROR,
  1030. "UDP errors",
  1031. EBPF_COMMON_DIMENSION_CALL,
  1032. NETDATA_SOCKET_KERNEL_FUNCTIONS,
  1033. NULL,
  1034. NETDATA_EBPF_CHART_TYPE_LINE,
  1035. order++,
  1036. ebpf_create_global_dimension,
  1037. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  1038. 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1039. }
  1040. }
  1041. /**
  1042. * Create apps charts
  1043. *
  1044. * Call ebpf_create_chart to create the charts on apps submenu.
  1045. *
  1046. * @param em a pointer to the structure with the default values.
  1047. * @param ptr a pointer for targets
  1048. */
  1049. void ebpf_socket_create_apps_charts(struct ebpf_module *em, void *ptr)
  1050. {
  1051. struct target *root = ptr;
  1052. int order = 20080;
  1053. ebpf_create_charts_on_apps(NETDATA_NET_APPS_CONNECTION_TCP_V4,
  1054. "Calls to tcp_v4_connection", EBPF_COMMON_DIMENSION_CONNECTIONS,
  1055. NETDATA_APPS_NET_GROUP,
  1056. NETDATA_EBPF_CHART_TYPE_STACKED,
  1057. order++,
  1058. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1059. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1060. ebpf_create_charts_on_apps(NETDATA_NET_APPS_CONNECTION_TCP_V6,
  1061. "Calls to tcp_v6_connection", EBPF_COMMON_DIMENSION_CONNECTIONS,
  1062. NETDATA_APPS_NET_GROUP,
  1063. NETDATA_EBPF_CHART_TYPE_STACKED,
  1064. order++,
  1065. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1066. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1067. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_SENT,
  1068. "Bytes sent", EBPF_COMMON_DIMENSION_BITS,
  1069. NETDATA_APPS_NET_GROUP,
  1070. NETDATA_EBPF_CHART_TYPE_STACKED,
  1071. order++,
  1072. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1073. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1074. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_RECV,
  1075. "bytes received", EBPF_COMMON_DIMENSION_BITS,
  1076. NETDATA_APPS_NET_GROUP,
  1077. NETDATA_EBPF_CHART_TYPE_STACKED,
  1078. order++,
  1079. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1080. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1081. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
  1082. "Calls for tcp_sendmsg",
  1083. EBPF_COMMON_DIMENSION_CALL,
  1084. NETDATA_APPS_NET_GROUP,
  1085. NETDATA_EBPF_CHART_TYPE_STACKED,
  1086. order++,
  1087. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1088. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1089. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
  1090. "Calls for tcp_cleanup_rbuf",
  1091. EBPF_COMMON_DIMENSION_CALL,
  1092. NETDATA_APPS_NET_GROUP,
  1093. NETDATA_EBPF_CHART_TYPE_STACKED,
  1094. order++,
  1095. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1096. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1097. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
  1098. "Calls for tcp_retransmit",
  1099. EBPF_COMMON_DIMENSION_CALL,
  1100. NETDATA_APPS_NET_GROUP,
  1101. NETDATA_EBPF_CHART_TYPE_STACKED,
  1102. order++,
  1103. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1104. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1105. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
  1106. "Calls for udp_sendmsg",
  1107. EBPF_COMMON_DIMENSION_CALL,
  1108. NETDATA_APPS_NET_GROUP,
  1109. NETDATA_EBPF_CHART_TYPE_STACKED,
  1110. order++,
  1111. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1112. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1113. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
  1114. "Calls for udp_recvmsg",
  1115. EBPF_COMMON_DIMENSION_CALL,
  1116. NETDATA_APPS_NET_GROUP,
  1117. NETDATA_EBPF_CHART_TYPE_STACKED,
  1118. order++,
  1119. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  1120. root, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  1121. em->apps_charts |= NETDATA_EBPF_APPS_FLAG_CHART_CREATED;
  1122. }
  1123. /**
  1124. * Create network viewer chart
  1125. *
  1126. * Create common charts.
  1127. *
  1128. * @param id chart id
  1129. * @param title chart title
  1130. * @param units units label
  1131. * @param family group name used to attach the chart on dashboard
  1132. * @param order chart order
  1133. * @param update_every value to overwrite the update frequency set by the server.
  1134. * @param ptr plot structure with values.
  1135. */
  1136. static void ebpf_socket_create_nv_chart(char *id, char *title, char *units,
  1137. char *family, int order, int update_every, netdata_vector_plot_t *ptr)
  1138. {
  1139. ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
  1140. id,
  1141. title,
  1142. units,
  1143. family,
  1144. NETDATA_EBPF_CHART_TYPE_STACKED,
  1145. NULL,
  1146. order,
  1147. update_every,
  1148. NETDATA_EBPF_MODULE_NAME_SOCKET);
  1149. uint32_t i;
  1150. uint32_t end = ptr->last_plot;
  1151. netdata_socket_plot_t *w = ptr->plot;
  1152. for (i = 0; i < end; i++) {
  1153. fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[i].dimension_sent);
  1154. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_recv);
  1155. }
  1156. end = ptr->last;
  1157. fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[end].dimension_sent);
  1158. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_recv);
  1159. }
  1160. /**
  1161. * Create network viewer retransmit
  1162. *
  1163. * Create a specific chart.
  1164. *
  1165. * @param id the chart id
  1166. * @param title the chart title
  1167. * @param units the units label
  1168. * @param family the group name used to attach the chart on dashboard
  1169. * @param order the chart order
  1170. * @param update_every value to overwrite the update frequency set by the server.
  1171. * @param ptr the plot structure with values.
  1172. */
  1173. static void ebpf_socket_create_nv_retransmit(char *id, char *title, char *units,
  1174. char *family, int order, int update_every, netdata_vector_plot_t *ptr)
  1175. {
  1176. ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
  1177. id,
  1178. title,
  1179. units,
  1180. family,
  1181. NETDATA_EBPF_CHART_TYPE_STACKED,
  1182. NULL,
  1183. order,
  1184. update_every,
  1185. NETDATA_EBPF_MODULE_NAME_SOCKET);
  1186. uint32_t i;
  1187. uint32_t end = ptr->last_plot;
  1188. netdata_socket_plot_t *w = ptr->plot;
  1189. for (i = 0; i < end; i++) {
  1190. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_retransmit);
  1191. }
  1192. end = ptr->last;
  1193. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_retransmit);
  1194. }
  1195. /**
  1196. * Create Network Viewer charts
  1197. *
  1198. * Recreate the charts when new sockets are created.
  1199. *
  1200. * @param ptr a pointer for inbound or outbound vectors.
  1201. * @param update_every value to overwrite the update frequency set by the server.
  1202. */
  1203. static void ebpf_socket_create_nv_charts(netdata_vector_plot_t *ptr, int update_every)
  1204. {
  1205. // We do not have new sockets, so we do not need move forward
  1206. if (ptr->max_plot == ptr->last_plot)
  1207. return;
  1208. ptr->last_plot = ptr->max_plot;
  1209. if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
  1210. ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_BYTES,
  1211. "Outbound connections (bytes).", EBPF_COMMON_DIMENSION_BYTES,
  1212. NETDATA_NETWORK_CONNECTIONS_GROUP,
  1213. 21080,
  1214. update_every, ptr);
  1215. ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_PACKETS,
  1216. "Outbound connections (packets)",
  1217. EBPF_COMMON_DIMENSION_PACKETS,
  1218. NETDATA_NETWORK_CONNECTIONS_GROUP,
  1219. 21082,
  1220. update_every, ptr);
  1221. ebpf_socket_create_nv_retransmit(NETDATA_NV_OUTBOUND_RETRANSMIT,
  1222. "Retransmitted packets",
  1223. EBPF_COMMON_DIMENSION_CALL,
  1224. NETDATA_NETWORK_CONNECTIONS_GROUP,
  1225. 21083,
  1226. update_every, ptr);
  1227. } else {
  1228. ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_BYTES,
  1229. "Inbound connections (bytes)", EBPF_COMMON_DIMENSION_BYTES,
  1230. NETDATA_NETWORK_CONNECTIONS_GROUP,
  1231. 21084,
  1232. update_every, ptr);
  1233. ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_PACKETS,
  1234. "Inbound connections (packets)",
  1235. EBPF_COMMON_DIMENSION_PACKETS,
  1236. NETDATA_NETWORK_CONNECTIONS_GROUP,
  1237. 21085,
  1238. update_every, ptr);
  1239. }
  1240. ptr->flags |= NETWORK_VIEWER_CHARTS_CREATED;
  1241. }
  1242. /*****************************************************************
  1243. *
  1244. * READ INFORMATION FROM KERNEL RING
  1245. *
  1246. *****************************************************************/
  1247. /**
  1248. * Is specific ip inside the range
  1249. *
  1250. * Check if the ip is inside a IP range previously defined
  1251. *
  1252. * @param cmp the IP to compare
  1253. * @param family the IP family
  1254. *
  1255. * @return It returns 1 if the IP is inside the range and 0 otherwise
  1256. */
  1257. static int is_specific_ip_inside_range(union netdata_ip_t *cmp, int family)
  1258. {
  1259. if (!network_viewer_opt.excluded_ips && !network_viewer_opt.included_ips)
  1260. return 1;
  1261. uint32_t ipv4_test = ntohl(cmp->addr32[0]);
  1262. ebpf_network_viewer_ip_list_t *move = network_viewer_opt.excluded_ips;
  1263. while (move) {
  1264. if (family == AF_INET) {
  1265. if (ntohl(move->first.addr32[0]) <= ipv4_test &&
  1266. ipv4_test <= ntohl(move->last.addr32[0]) )
  1267. return 0;
  1268. } else {
  1269. if (memcmp(move->first.addr8, cmp->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  1270. memcmp(move->last.addr8, cmp->addr8, sizeof(union netdata_ip_t)) >= 0) {
  1271. return 0;
  1272. }
  1273. }
  1274. move = move->next;
  1275. }
  1276. move = network_viewer_opt.included_ips;
  1277. while (move) {
  1278. if (family == AF_INET) {
  1279. if (ntohl(move->first.addr32[0]) <= ipv4_test &&
  1280. ntohl(move->last.addr32[0]) >= ipv4_test)
  1281. return 1;
  1282. } else {
  1283. if (memcmp(move->first.addr8, cmp->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  1284. memcmp(move->last.addr8, cmp->addr8, sizeof(union netdata_ip_t)) >= 0) {
  1285. return 1;
  1286. }
  1287. }
  1288. move = move->next;
  1289. }
  1290. return 0;
  1291. }
  1292. /**
  1293. * Is port inside range
  1294. *
  1295. * Verify if the cmp port is inside the range [first, last].
  1296. * This function expects only the last parameter as big endian.
  1297. *
  1298. * @param cmp the value to compare
  1299. *
  1300. * @return It returns 1 when cmp is inside and 0 otherwise.
  1301. */
  1302. static int is_port_inside_range(uint16_t cmp)
  1303. {
  1304. // We do not have restrictions for ports.
  1305. if (!network_viewer_opt.excluded_port && !network_viewer_opt.included_port)
  1306. return 1;
  1307. // Test if port is excluded
  1308. ebpf_network_viewer_port_list_t *move = network_viewer_opt.excluded_port;
  1309. cmp = htons(cmp);
  1310. while (move) {
  1311. if (move->cmp_first <= cmp && cmp <= move->cmp_last)
  1312. return 0;
  1313. move = move->next;
  1314. }
  1315. // Test if the port is inside allowed range
  1316. move = network_viewer_opt.included_port;
  1317. while (move) {
  1318. if (move->cmp_first <= cmp && cmp <= move->cmp_last)
  1319. return 1;
  1320. move = move->next;
  1321. }
  1322. return 0;
  1323. }
  1324. /**
  1325. * Hostname matches pattern
  1326. *
  1327. * @param cmp the value to compare
  1328. *
  1329. * @return It returns 1 when the value matches and zero otherwise.
  1330. */
  1331. int hostname_matches_pattern(char *cmp)
  1332. {
  1333. if (!network_viewer_opt.included_hostnames && !network_viewer_opt.excluded_hostnames)
  1334. return 1;
  1335. ebpf_network_viewer_hostname_list_t *move = network_viewer_opt.excluded_hostnames;
  1336. while (move) {
  1337. if (simple_pattern_matches(move->value_pattern, cmp))
  1338. return 0;
  1339. move = move->next;
  1340. }
  1341. move = network_viewer_opt.included_hostnames;
  1342. while (move) {
  1343. if (simple_pattern_matches(move->value_pattern, cmp))
  1344. return 1;
  1345. move = move->next;
  1346. }
  1347. return 0;
  1348. }
  1349. /**
  1350. * Is socket allowed?
  1351. *
  1352. * Compare destination addresses and destination ports to define next steps
  1353. *
  1354. * @param key the socket read from kernel ring
  1355. * @param family the family used to compare IPs (AF_INET and AF_INET6)
  1356. *
  1357. * @return It returns 1 if this socket is inside the ranges and 0 otherwise.
  1358. */
  1359. int is_socket_allowed(netdata_socket_idx_t *key, int family)
  1360. {
  1361. if (!is_port_inside_range(key->dport))
  1362. return 0;
  1363. return is_specific_ip_inside_range(&key->daddr, family);
  1364. }
  1365. /**
  1366. * Compare sockets
  1367. *
  1368. * Compare destination address and destination port.
  1369. * We do not compare source port, because it is random.
  1370. * We also do not compare source address, because inbound and outbound connections are stored in separated AVL trees.
  1371. *
  1372. * @param a pointer to netdata_socket_plot
  1373. * @param b pointer to netdata_socket_plot
  1374. *
  1375. * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
  1376. */
  1377. static int compare_sockets(void *a, void *b)
  1378. {
  1379. struct netdata_socket_plot *val1 = a;
  1380. struct netdata_socket_plot *val2 = b;
  1381. int cmp;
  1382. // We do not need to compare val2 family, because data inside hash table is always from the same family
  1383. if (val1->family == AF_INET) { //IPV4
  1384. if (val1->flags & NETDATA_INBOUND_DIRECTION) {
  1385. if (val1->index.sport == val2->index.sport)
  1386. cmp = 0;
  1387. else {
  1388. cmp = (val1->index.sport > val2->index.sport)?1:-1;
  1389. }
  1390. } else {
  1391. cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
  1392. if (!cmp) {
  1393. cmp = memcmp(&val1->index.daddr.addr32[0], &val2->index.daddr.addr32[0], sizeof(uint32_t));
  1394. }
  1395. }
  1396. } else {
  1397. if (val1->flags & NETDATA_INBOUND_DIRECTION) {
  1398. if (val1->index.sport == val2->index.sport)
  1399. cmp = 0;
  1400. else {
  1401. cmp = (val1->index.sport > val2->index.sport)?1:-1;
  1402. }
  1403. } else {
  1404. cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
  1405. if (!cmp) {
  1406. cmp = memcmp(&val1->index.daddr.addr32, &val2->index.daddr.addr32, 4*sizeof(uint32_t));
  1407. }
  1408. }
  1409. }
  1410. return cmp;
  1411. }
  1412. /**
  1413. * Build dimension name
  1414. *
  1415. * Fill dimension name vector with values given
  1416. *
  1417. * @param dimname the output vector
  1418. * @param hostname the hostname for the socket.
  1419. * @param service_name the service used to connect.
  1420. * @param proto the protocol used in this connection
  1421. * @param family is this IPV4(AF_INET) or IPV6(AF_INET6)
  1422. *
  1423. * @return it returns the size of the data copied on success and -1 otherwise.
  1424. */
  1425. static inline int build_outbound_dimension_name(char *dimname, char *hostname, char *service_name,
  1426. char *proto, int family)
  1427. {
  1428. return snprintf(dimname, CONFIG_MAX_NAME - 7, (family == AF_INET)?"%s:%s:%s_":"%s:%s:[%s]_",
  1429. service_name, proto,
  1430. hostname);
  1431. }
  1432. /**
  1433. * Fill inbound dimension name
  1434. *
  1435. * Mount the dimension name with the input given
  1436. *
  1437. * @param dimname the output vector
  1438. * @param service_name the service used to connect.
  1439. * @param proto the protocol used in this connection
  1440. *
  1441. * @return it returns the size of the data copied on success and -1 otherwise.
  1442. */
  1443. static inline int build_inbound_dimension_name(char *dimname, char *service_name, char *proto)
  1444. {
  1445. return snprintf(dimname, CONFIG_MAX_NAME - 7, "%s:%s_", service_name,
  1446. proto);
  1447. }
  1448. /**
  1449. * Fill Resolved Name
  1450. *
  1451. * Fill the resolved name structure with the value given.
  1452. * The hostname is the largest value possible, if it is necessary to cut some value, it must be cut.
  1453. *
  1454. * @param ptr the output vector
  1455. * @param hostname the hostname resolved or IP.
  1456. * @param length the length for the hostname.
  1457. * @param service_name the service name associated to the connection
  1458. * @param is_outbound the is this an outbound connection
  1459. */
  1460. static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname, size_t length,
  1461. char *service_name, int is_outbound)
  1462. {
  1463. if (length < NETDATA_MAX_NETWORK_COMBINED_LENGTH)
  1464. ptr->resolved_name = strdupz(hostname);
  1465. else {
  1466. length = NETDATA_MAX_NETWORK_COMBINED_LENGTH;
  1467. ptr->resolved_name = mallocz( NETDATA_MAX_NETWORK_COMBINED_LENGTH + 1);
  1468. memcpy(ptr->resolved_name, hostname, length);
  1469. ptr->resolved_name[length] = '\0';
  1470. }
  1471. char dimname[CONFIG_MAX_NAME];
  1472. int size;
  1473. char *protocol;
  1474. if (ptr->sock.protocol == IPPROTO_UDP) {
  1475. protocol = "UDP";
  1476. } else if (ptr->sock.protocol == IPPROTO_TCP) {
  1477. protocol = "TCP";
  1478. } else {
  1479. protocol = "ALL";
  1480. }
  1481. if (is_outbound)
  1482. size = build_outbound_dimension_name(dimname, hostname, service_name, protocol, ptr->family);
  1483. else
  1484. size = build_inbound_dimension_name(dimname,service_name, protocol);
  1485. if (size > 0) {
  1486. strcpy(&dimname[size], "sent");
  1487. dimname[size + 4] = '\0';
  1488. ptr->dimension_sent = strdupz(dimname);
  1489. strcpy(&dimname[size], "recv");
  1490. ptr->dimension_recv = strdupz(dimname);
  1491. dimname[size - 1] = '\0';
  1492. ptr->dimension_retransmit = strdupz(dimname);
  1493. }
  1494. }
  1495. /**
  1496. * Mount dimension names
  1497. *
  1498. * Fill the vector names after to resolve the addresses
  1499. *
  1500. * @param ptr a pointer to the structure where the values are stored.
  1501. * @param is_outbound is a outbound ptr value?
  1502. *
  1503. * @return It returns 1 if the name is valid and 0 otherwise.
  1504. */
  1505. int fill_names(netdata_socket_plot_t *ptr, int is_outbound)
  1506. {
  1507. char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
  1508. if (ptr->resolved)
  1509. return 1;
  1510. int ret;
  1511. static int resolve_name = -1;
  1512. static int resolve_service = -1;
  1513. if (resolve_name == -1)
  1514. resolve_name = network_viewer_opt.hostname_resolution_enabled;
  1515. if (resolve_service == -1)
  1516. resolve_service = network_viewer_opt.service_resolution_enabled;
  1517. netdata_socket_idx_t *idx = &ptr->index;
  1518. char *errname = { "Not resolved" };
  1519. // Resolve Name
  1520. if (ptr->family == AF_INET) { //IPV4
  1521. struct sockaddr_in myaddr;
  1522. memset(&myaddr, 0 , sizeof(myaddr));
  1523. myaddr.sin_family = ptr->family;
  1524. if (is_outbound) {
  1525. myaddr.sin_port = idx->dport;
  1526. myaddr.sin_addr.s_addr = idx->daddr.addr32[0];
  1527. } else {
  1528. myaddr.sin_port = idx->sport;
  1529. myaddr.sin_addr.s_addr = idx->saddr.addr32[0];
  1530. }
  1531. ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr, sizeof(myaddr), hostname,
  1532. sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
  1533. if (!ret && !resolve_service) {
  1534. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
  1535. }
  1536. if (ret) {
  1537. // I cannot resolve the name, I will use the IP
  1538. if (!inet_ntop(AF_INET, &myaddr.sin_addr.s_addr, hostname, NI_MAXHOST)) {
  1539. strncpy(hostname, errname, 13);
  1540. }
  1541. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
  1542. ret = 1;
  1543. }
  1544. } else { // IPV6
  1545. struct sockaddr_in6 myaddr6;
  1546. memset(&myaddr6, 0 , sizeof(myaddr6));
  1547. myaddr6.sin6_family = AF_INET6;
  1548. if (is_outbound) {
  1549. myaddr6.sin6_port = idx->dport;
  1550. memcpy(myaddr6.sin6_addr.s6_addr, idx->daddr.addr8, sizeof(union netdata_ip_t));
  1551. } else {
  1552. myaddr6.sin6_port = idx->sport;
  1553. memcpy(myaddr6.sin6_addr.s6_addr, idx->saddr.addr8, sizeof(union netdata_ip_t));
  1554. }
  1555. ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr6, sizeof(myaddr6), hostname,
  1556. sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
  1557. if (!ret && !resolve_service) {
  1558. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
  1559. }
  1560. if (ret) {
  1561. // I cannot resolve the name, I will use the IP
  1562. if (!inet_ntop(AF_INET6, myaddr6.sin6_addr.s6_addr, hostname, NI_MAXHOST)) {
  1563. strncpy(hostname, errname, 13);
  1564. }
  1565. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
  1566. ret = 1;
  1567. }
  1568. }
  1569. fill_resolved_name(ptr, hostname,
  1570. strlen(hostname) + strlen(service_name)+ NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH,
  1571. service_name, is_outbound);
  1572. if (resolve_name && !ret)
  1573. ret = hostname_matches_pattern(hostname);
  1574. ptr->resolved++;
  1575. return ret;
  1576. }
  1577. /**
  1578. * Fill last Network Viewer Dimension
  1579. *
  1580. * Fill the unique dimension that is always plotted.
  1581. *
  1582. * @param ptr the pointer for the last dimension
  1583. * @param is_outbound is this an inbound structure?
  1584. */
  1585. static void fill_last_nv_dimension(netdata_socket_plot_t *ptr, int is_outbound)
  1586. {
  1587. char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
  1588. char *other = { "other" };
  1589. // We are also copying the NULL bytes to avoid warnings in new compilers
  1590. strncpy(hostname, other, 6);
  1591. strncpy(service_name, other, 6);
  1592. ptr->family = AF_INET;
  1593. ptr->sock.protocol = 255;
  1594. ptr->flags = (!is_outbound)?NETDATA_INBOUND_DIRECTION:NETDATA_OUTBOUND_DIRECTION;
  1595. fill_resolved_name(ptr, hostname, 10 + NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH, service_name, is_outbound);
  1596. #ifdef NETDATA_INTERNAL_CHECKS
  1597. info("Last %s dimension added: ID = %u, IP = OTHER, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
  1598. (is_outbound)?"outbound":"inbound", network_viewer_opt.max_dim - 1, ptr->resolved_name,
  1599. ptr->dimension_recv, ptr->dimension_sent, ptr->dimension_retransmit);
  1600. #endif
  1601. }
  1602. /**
  1603. * Update Socket Data
  1604. *
  1605. * Update the socket information with last collected data
  1606. *
  1607. * @param sock
  1608. * @param lvalues
  1609. */
  1610. static inline void update_socket_data(netdata_socket_t *sock, netdata_socket_t *lvalues)
  1611. {
  1612. sock->recv_packets += lvalues->recv_packets;
  1613. sock->sent_packets += lvalues->sent_packets;
  1614. sock->recv_bytes += lvalues->recv_bytes;
  1615. sock->sent_bytes += lvalues->sent_bytes;
  1616. sock->retransmit += lvalues->retransmit;
  1617. if (lvalues->ct > sock->ct)
  1618. sock->ct = lvalues->ct;
  1619. }
  1620. /**
  1621. * Store socket inside avl
  1622. *
  1623. * Store the socket values inside the avl tree.
  1624. *
  1625. * @param out the structure with information used to plot charts.
  1626. * @param lvalues Values read from socket ring.
  1627. * @param lindex the index information, the real socket.
  1628. * @param family the family associated to the socket
  1629. * @param flags the connection flags
  1630. */
  1631. static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t *lvalues,
  1632. netdata_socket_idx_t *lindex, int family, uint32_t flags)
  1633. {
  1634. netdata_socket_plot_t test, *ret ;
  1635. memcpy(&test.index, lindex, sizeof(netdata_socket_idx_t));
  1636. test.flags = flags;
  1637. ret = (netdata_socket_plot_t *) avl_search_lock(&out->tree, (avl_t *)&test);
  1638. if (ret) {
  1639. if (lvalues->ct > ret->plot.last_time) {
  1640. update_socket_data(&ret->sock, lvalues);
  1641. }
  1642. } else {
  1643. uint32_t curr = out->next;
  1644. uint32_t last = out->last;
  1645. netdata_socket_plot_t *w = &out->plot[curr];
  1646. int resolved;
  1647. if (curr == last) {
  1648. if (lvalues->ct > w->plot.last_time) {
  1649. update_socket_data(&w->sock, lvalues);
  1650. }
  1651. return;
  1652. } else {
  1653. memcpy(&w->sock, lvalues, sizeof(netdata_socket_t));
  1654. memcpy(&w->index, lindex, sizeof(netdata_socket_idx_t));
  1655. w->family = family;
  1656. resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors);
  1657. }
  1658. if (!resolved) {
  1659. freez(w->resolved_name);
  1660. freez(w->dimension_sent);
  1661. freez(w->dimension_recv);
  1662. freez(w->dimension_retransmit);
  1663. memset(w, 0, sizeof(netdata_socket_plot_t));
  1664. return;
  1665. }
  1666. w->flags = flags;
  1667. netdata_socket_plot_t *check ;
  1668. check = (netdata_socket_plot_t *) avl_insert_lock(&out->tree, (avl_t *)w);
  1669. if (check != w)
  1670. error("Internal error, cannot insert the AVL tree.");
  1671. #ifdef NETDATA_INTERNAL_CHECKS
  1672. char iptext[INET6_ADDRSTRLEN];
  1673. if (inet_ntop(family, &w->index.daddr.addr8, iptext, sizeof(iptext)))
  1674. info("New %s dimension added: ID = %u, IP = %s, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
  1675. (out == &inbound_vectors)?"inbound":"outbound", curr, iptext, w->resolved_name,
  1676. w->dimension_recv, w->dimension_sent, w->dimension_retransmit);
  1677. #endif
  1678. curr++;
  1679. if (curr > last)
  1680. curr = last;
  1681. out->next = curr;
  1682. }
  1683. }
  1684. /**
  1685. * Compare Vector to store
  1686. *
  1687. * Compare input values with local address to select table to store.
  1688. *
  1689. * @param direction store inbound and outbound direction.
  1690. * @param cmp index read from hash table.
  1691. * @param proto the protocol read.
  1692. *
  1693. * @return It returns the structure with address to compare.
  1694. */
  1695. netdata_vector_plot_t * select_vector_to_store(uint32_t *direction, netdata_socket_idx_t *cmp, uint8_t proto)
  1696. {
  1697. if (!listen_ports) {
  1698. *direction = NETDATA_OUTBOUND_DIRECTION;
  1699. return &outbound_vectors;
  1700. }
  1701. ebpf_network_viewer_port_list_t *move_ports = listen_ports;
  1702. while (move_ports) {
  1703. if (move_ports->protocol == proto && move_ports->first == cmp->sport) {
  1704. *direction = NETDATA_INBOUND_DIRECTION;
  1705. return &inbound_vectors;
  1706. }
  1707. move_ports = move_ports->next;
  1708. }
  1709. *direction = NETDATA_OUTBOUND_DIRECTION;
  1710. return &outbound_vectors;
  1711. }
  1712. /**
  1713. * Hash accumulator
  1714. *
  1715. * @param values the values used to calculate the data.
  1716. * @param key the key to store data.
  1717. * @param family the connection family
  1718. * @param end the values size.
  1719. */
  1720. static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key, int family, int end)
  1721. {
  1722. uint64_t bsent = 0, brecv = 0, psent = 0, precv = 0;
  1723. uint16_t retransmit = 0;
  1724. int i;
  1725. uint8_t protocol = values[0].protocol;
  1726. uint64_t ct = values[0].ct;
  1727. for (i = 1; i < end; i++) {
  1728. netdata_socket_t *w = &values[i];
  1729. precv += w->recv_packets;
  1730. psent += w->sent_packets;
  1731. brecv += w->recv_bytes;
  1732. bsent += w->sent_bytes;
  1733. retransmit += w->retransmit;
  1734. if (!protocol)
  1735. protocol = w->protocol;
  1736. if (w->ct > ct)
  1737. ct = w->ct;
  1738. }
  1739. values[0].recv_packets += precv;
  1740. values[0].sent_packets += psent;
  1741. values[0].recv_bytes += brecv;
  1742. values[0].sent_bytes += bsent;
  1743. values[0].retransmit += retransmit;
  1744. values[0].protocol = (!protocol)?IPPROTO_TCP:protocol;
  1745. values[0].ct = ct;
  1746. if (is_socket_allowed(key, family)) {
  1747. uint32_t dir;
  1748. netdata_vector_plot_t *table = select_vector_to_store(&dir, key, protocol);
  1749. store_socket_inside_avl(table, &values[0], key, family, dir);
  1750. }
  1751. }
  1752. /**
  1753. * Read socket hash table
  1754. *
  1755. * Read data from hash tables created on kernel ring.
  1756. *
  1757. * @param fd the hash table with data.
  1758. * @param family the family associated to the hash table
  1759. *
  1760. * @return it returns 0 on success and -1 otherwise.
  1761. */
  1762. static void read_socket_hash_table(int fd, int family, int network_connection)
  1763. {
  1764. if (wait_to_plot)
  1765. return;
  1766. netdata_socket_idx_t key = {};
  1767. netdata_socket_idx_t next_key = {};
  1768. netdata_socket_t *values = socket_values;
  1769. size_t length = ebpf_nprocs*sizeof(netdata_socket_t);
  1770. int test, end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
  1771. while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  1772. // We need to reset the values when we are working on kernel 4.15 or newer, because kernel does not create
  1773. // values for specific processor unless it is used to store data. As result of this behavior one the next socket
  1774. // can have values from the previous one.
  1775. memset(values, 0, length);
  1776. test = bpf_map_lookup_elem(fd, &key, values);
  1777. if (test < 0) {
  1778. key = next_key;
  1779. continue;
  1780. }
  1781. if (network_connection) {
  1782. hash_accumulator(values, &key, family, end);
  1783. }
  1784. key = next_key;
  1785. }
  1786. }
  1787. /**
  1788. * Fill Network Viewer Port list
  1789. *
  1790. * Fill the strcture with values read from /proc or hash table.
  1791. *
  1792. * @param out the structure where we will store data.
  1793. * @param value the ports we are listen to.
  1794. * @param proto the protocol used for this connection.
  1795. * @param in the strcuture with values read form different sources.
  1796. */
  1797. static inline void fill_nv_port_list(ebpf_network_viewer_port_list_t *out, uint16_t value, uint16_t proto,
  1798. netdata_passive_connection_t *in)
  1799. {
  1800. out->first = value;
  1801. out->protocol = proto;
  1802. out->pid = in->pid;
  1803. out->tgid = in->tgid;
  1804. out->connections = in->counter;
  1805. }
  1806. /**
  1807. * Update listen table
  1808. *
  1809. * Update link list when it is necessary.
  1810. *
  1811. * @param value the ports we are listen to.
  1812. * @param proto the protocol used with port connection.
  1813. * @param in the strcuture with values read form different sources.
  1814. */
  1815. void update_listen_table(uint16_t value, uint16_t proto, netdata_passive_connection_t *in)
  1816. {
  1817. ebpf_network_viewer_port_list_t *w;
  1818. if (likely(listen_ports)) {
  1819. ebpf_network_viewer_port_list_t *move = listen_ports, *store = listen_ports;
  1820. while (move) {
  1821. if (move->protocol == proto && move->first == value) {
  1822. move->pid = in->pid;
  1823. move->tgid = in->tgid;
  1824. move->connections = in->counter;
  1825. return;
  1826. }
  1827. store = move;
  1828. move = move->next;
  1829. }
  1830. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1831. store->next = w;
  1832. } else {
  1833. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1834. listen_ports = w;
  1835. }
  1836. fill_nv_port_list(w, value, proto, in);
  1837. #ifdef NETDATA_INTERNAL_CHECKS
  1838. info("The network viewer is monitoring inbound connections for port %u", ntohs(value));
  1839. #endif
  1840. }
  1841. /**
  1842. * Read listen table
  1843. *
  1844. * Read the table with all ports that we are listen on host.
  1845. */
  1846. static void read_listen_table()
  1847. {
  1848. netdata_passive_connection_idx_t key = {};
  1849. netdata_passive_connection_idx_t next_key = {};
  1850. int fd = socket_maps[NETDATA_SOCKET_LPORTS].map_fd;
  1851. netdata_passive_connection_t value = {};
  1852. while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  1853. int test = bpf_map_lookup_elem(fd, &key, &value);
  1854. if (test < 0) {
  1855. key = next_key;
  1856. continue;
  1857. }
  1858. // The correct protocol must come from kernel
  1859. update_listen_table(key.port, key.protocol, &value);
  1860. key = next_key;
  1861. memset(&value, 0, sizeof(value));
  1862. }
  1863. if (next_key.port && value.pid) {
  1864. // The correct protocol must come from kernel
  1865. update_listen_table(next_key.port, next_key.protocol, &value);
  1866. }
  1867. }
  1868. /**
  1869. * Socket read hash
  1870. *
  1871. * This is the thread callback.
  1872. * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
  1873. *
  1874. * @param ptr It is a NULL value for this thread.
  1875. *
  1876. * @return It always returns NULL.
  1877. */
  1878. void *ebpf_socket_read_hash(void *ptr)
  1879. {
  1880. netdata_thread_cleanup_push(ebpf_socket_cleanup, ptr);
  1881. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1882. heartbeat_t hb;
  1883. heartbeat_init(&hb);
  1884. usec_t step = NETDATA_SOCKET_READ_SLEEP_MS * em->update_every;
  1885. int fd_ipv4 = socket_maps[NETDATA_SOCKET_TABLE_IPV4].map_fd;
  1886. int fd_ipv6 = socket_maps[NETDATA_SOCKET_TABLE_IPV6].map_fd;
  1887. int network_connection = em->optional;
  1888. while (ebpf_socket_exited == NETDATA_THREAD_EBPF_RUNNING) {
  1889. usec_t dt = heartbeat_next(&hb, step);
  1890. (void)dt;
  1891. if (ebpf_socket_exited == NETDATA_THREAD_EBPF_STOPPING)
  1892. break;
  1893. pthread_mutex_lock(&nv_mutex);
  1894. read_listen_table();
  1895. read_socket_hash_table(fd_ipv4, AF_INET, network_connection);
  1896. read_socket_hash_table(fd_ipv6, AF_INET6, network_connection);
  1897. wait_to_plot = 1;
  1898. pthread_mutex_unlock(&nv_mutex);
  1899. }
  1900. ebpf_socket_exited = NETDATA_THREAD_EBPF_STOPPED;
  1901. netdata_thread_cleanup_pop(1);
  1902. return NULL;
  1903. }
  1904. /**
  1905. * Read the hash table and store data to allocated vectors.
  1906. */
  1907. static void read_hash_global_tables()
  1908. {
  1909. uint64_t idx;
  1910. netdata_idx_t res[NETDATA_SOCKET_COUNTER];
  1911. netdata_idx_t *val = socket_hash_values;
  1912. int fd = socket_maps[NETDATA_SOCKET_GLOBAL].map_fd;
  1913. for (idx = 0; idx < NETDATA_SOCKET_COUNTER; idx++) {
  1914. if (!bpf_map_lookup_elem(fd, &idx, val)) {
  1915. uint64_t total = 0;
  1916. int i;
  1917. int end = ebpf_nprocs;
  1918. for (i = 0; i < end; i++)
  1919. total += val[i];
  1920. res[idx] = total;
  1921. } else {
  1922. res[idx] = 0;
  1923. }
  1924. }
  1925. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].call = res[NETDATA_KEY_CALLS_TCP_SENDMSG];
  1926. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].call = res[NETDATA_KEY_CALLS_TCP_CLEANUP_RBUF];
  1927. socket_aggregated_data[NETDATA_IDX_TCP_CLOSE].call = res[NETDATA_KEY_CALLS_TCP_CLOSE];
  1928. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].call = res[NETDATA_KEY_CALLS_UDP_RECVMSG];
  1929. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].call = res[NETDATA_KEY_CALLS_UDP_SENDMSG];
  1930. socket_aggregated_data[NETDATA_IDX_TCP_RETRANSMIT].call = res[NETDATA_KEY_TCP_RETRANSMIT];
  1931. socket_aggregated_data[NETDATA_IDX_TCP_CONNECTION_V4].call = res[NETDATA_KEY_CALLS_TCP_CONNECT_IPV4];
  1932. socket_aggregated_data[NETDATA_IDX_TCP_CONNECTION_V6].call = res[NETDATA_KEY_CALLS_TCP_CONNECT_IPV6];
  1933. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].ecall = res[NETDATA_KEY_ERROR_TCP_SENDMSG];
  1934. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].ecall = res[NETDATA_KEY_ERROR_TCP_CLEANUP_RBUF];
  1935. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].ecall = res[NETDATA_KEY_ERROR_UDP_RECVMSG];
  1936. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].ecall = res[NETDATA_KEY_ERROR_UDP_SENDMSG];
  1937. socket_aggregated_data[NETDATA_IDX_TCP_CONNECTION_V4].ecall = res[NETDATA_KEY_ERROR_TCP_CONNECT_IPV4];
  1938. socket_aggregated_data[NETDATA_IDX_TCP_CONNECTION_V6].ecall = res[NETDATA_KEY_ERROR_TCP_CONNECT_IPV6];
  1939. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].bytes = res[NETDATA_KEY_BYTES_TCP_SENDMSG];
  1940. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].bytes = res[NETDATA_KEY_BYTES_TCP_CLEANUP_RBUF];
  1941. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].bytes = res[NETDATA_KEY_BYTES_UDP_RECVMSG];
  1942. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].bytes = res[NETDATA_KEY_BYTES_UDP_SENDMSG];
  1943. }
  1944. /**
  1945. * Fill publish apps when necessary.
  1946. *
  1947. * @param current_pid the PID that I am updating
  1948. * @param eb the structure with data read from memory.
  1949. */
  1950. void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
  1951. {
  1952. ebpf_socket_publish_apps_t *curr = socket_bandwidth_curr[current_pid];
  1953. if (!curr) {
  1954. curr = callocz(1, sizeof(ebpf_socket_publish_apps_t));
  1955. socket_bandwidth_curr[current_pid] = curr;
  1956. }
  1957. curr->bytes_sent = eb->bytes_sent;
  1958. curr->bytes_received = eb->bytes_received;
  1959. curr->call_tcp_sent = eb->call_tcp_sent;
  1960. curr->call_tcp_received = eb->call_tcp_received;
  1961. curr->retransmit = eb->retransmit;
  1962. curr->call_udp_sent = eb->call_udp_sent;
  1963. curr->call_udp_received = eb->call_udp_received;
  1964. curr->call_close = eb->close;
  1965. curr->call_tcp_v4_connection = eb->tcp_v4_connection;
  1966. curr->call_tcp_v6_connection = eb->tcp_v6_connection;
  1967. }
  1968. /**
  1969. * Bandwidth accumulator.
  1970. *
  1971. * @param out the vector with the values to sum
  1972. */
  1973. void ebpf_socket_bandwidth_accumulator(ebpf_bandwidth_t *out)
  1974. {
  1975. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  1976. ebpf_bandwidth_t *total = &out[0];
  1977. for (i = 1; i < end; i++) {
  1978. ebpf_bandwidth_t *move = &out[i];
  1979. total->bytes_sent += move->bytes_sent;
  1980. total->bytes_received += move->bytes_received;
  1981. total->call_tcp_sent += move->call_tcp_sent;
  1982. total->call_tcp_received += move->call_tcp_received;
  1983. total->retransmit += move->retransmit;
  1984. total->call_udp_sent += move->call_udp_sent;
  1985. total->call_udp_received += move->call_udp_received;
  1986. total->close += move->close;
  1987. total->tcp_v4_connection += move->tcp_v4_connection;
  1988. total->tcp_v6_connection += move->tcp_v6_connection;
  1989. }
  1990. }
  1991. /**
  1992. * Update the apps data reading information from the hash table
  1993. */
  1994. static void ebpf_socket_update_apps_data()
  1995. {
  1996. int fd = socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd;
  1997. ebpf_bandwidth_t *eb = bandwidth_vector;
  1998. uint32_t key;
  1999. struct pid_stat *pids = root_of_pids;
  2000. while (pids) {
  2001. key = pids->pid;
  2002. if (bpf_map_lookup_elem(fd, &key, eb)) {
  2003. pids = pids->next;
  2004. continue;
  2005. }
  2006. ebpf_socket_bandwidth_accumulator(eb);
  2007. ebpf_socket_fill_publish_apps(key, eb);
  2008. pids = pids->next;
  2009. }
  2010. }
  2011. /**
  2012. * Update cgroup
  2013. *
  2014. * Update cgroup data based in
  2015. */
  2016. static void ebpf_update_socket_cgroup()
  2017. {
  2018. ebpf_cgroup_target_t *ect ;
  2019. ebpf_bandwidth_t *eb = bandwidth_vector;
  2020. int fd = socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].map_fd;
  2021. pthread_mutex_lock(&mutex_cgroup_shm);
  2022. for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
  2023. struct pid_on_target2 *pids;
  2024. for (pids = ect->pids; pids; pids = pids->next) {
  2025. int pid = pids->pid;
  2026. ebpf_bandwidth_t *out = &pids->socket;
  2027. ebpf_socket_publish_apps_t *publish = &ect->publish_socket;
  2028. if (likely(socket_bandwidth_curr) && socket_bandwidth_curr[pid]) {
  2029. ebpf_socket_publish_apps_t *in = socket_bandwidth_curr[pid];
  2030. publish->bytes_sent = in->bytes_sent;
  2031. publish->bytes_received = in->bytes_received;
  2032. publish->call_tcp_sent = in->call_tcp_sent;
  2033. publish->call_tcp_received = in->call_tcp_received;
  2034. publish->retransmit = in->retransmit;
  2035. publish->call_udp_sent = in->call_udp_sent;
  2036. publish->call_udp_received = in->call_udp_received;
  2037. publish->call_close = in->call_close;
  2038. publish->call_tcp_v4_connection = in->call_tcp_v4_connection;
  2039. publish->call_tcp_v6_connection = in->call_tcp_v6_connection;
  2040. } else {
  2041. if (!bpf_map_lookup_elem(fd, &pid, eb)) {
  2042. ebpf_socket_bandwidth_accumulator(eb);
  2043. memcpy(out, eb, sizeof(ebpf_bandwidth_t));
  2044. publish->bytes_sent = out->bytes_sent;
  2045. publish->bytes_received = out->bytes_received;
  2046. publish->call_tcp_sent = out->call_tcp_sent;
  2047. publish->call_tcp_received = out->call_tcp_received;
  2048. publish->retransmit = out->retransmit;
  2049. publish->call_udp_sent = out->call_udp_sent;
  2050. publish->call_udp_received = out->call_udp_received;
  2051. publish->call_close = out->close;
  2052. publish->call_tcp_v4_connection = out->tcp_v4_connection;
  2053. publish->call_tcp_v6_connection = out->tcp_v6_connection;
  2054. }
  2055. }
  2056. }
  2057. }
  2058. pthread_mutex_unlock(&mutex_cgroup_shm);
  2059. }
  2060. /**
  2061. * Sum PIDs
  2062. *
  2063. * Sum values for all targets.
  2064. *
  2065. * @param fd structure used to store data
  2066. * @param pids input data
  2067. */
  2068. static void ebpf_socket_sum_cgroup_pids(ebpf_socket_publish_apps_t *socket, struct pid_on_target2 *pids)
  2069. {
  2070. ebpf_socket_publish_apps_t accumulator;
  2071. memset(&accumulator, 0, sizeof(accumulator));
  2072. while (pids) {
  2073. ebpf_bandwidth_t *w = &pids->socket;
  2074. accumulator.bytes_received += w->bytes_received;
  2075. accumulator.bytes_sent += w->bytes_sent;
  2076. accumulator.call_tcp_received += w->call_tcp_received;
  2077. accumulator.call_tcp_sent += w->call_tcp_sent;
  2078. accumulator.retransmit += w->retransmit;
  2079. accumulator.call_udp_received += w->call_udp_received;
  2080. accumulator.call_udp_sent += w->call_udp_sent;
  2081. accumulator.call_close += w->close;
  2082. accumulator.call_tcp_v4_connection += w->tcp_v4_connection;
  2083. accumulator.call_tcp_v6_connection += w->tcp_v6_connection;
  2084. pids = pids->next;
  2085. }
  2086. socket->bytes_sent = (accumulator.bytes_sent >= socket->bytes_sent) ? accumulator.bytes_sent : socket->bytes_sent;
  2087. socket->bytes_received = (accumulator.bytes_received >= socket->bytes_received) ? accumulator.bytes_received : socket->bytes_received;
  2088. socket->call_tcp_sent = (accumulator.call_tcp_sent >= socket->call_tcp_sent) ? accumulator.call_tcp_sent : socket->call_tcp_sent;
  2089. socket->call_tcp_received = (accumulator.call_tcp_received >= socket->call_tcp_received) ? accumulator.call_tcp_received : socket->call_tcp_received;
  2090. socket->retransmit = (accumulator.retransmit >= socket->retransmit) ? accumulator.retransmit : socket->retransmit;
  2091. socket->call_udp_sent = (accumulator.call_udp_sent >= socket->call_udp_sent) ? accumulator.call_udp_sent : socket->call_udp_sent;
  2092. socket->call_udp_received = (accumulator.call_udp_received >= socket->call_udp_received) ? accumulator.call_udp_received : socket->call_udp_received;
  2093. socket->call_close = (accumulator.call_close >= socket->call_close) ? accumulator.call_close : socket->call_close;
  2094. socket->call_tcp_v4_connection = (accumulator.call_tcp_v4_connection >= socket->call_tcp_v4_connection) ?
  2095. accumulator.call_tcp_v4_connection : socket->call_tcp_v4_connection;
  2096. socket->call_tcp_v6_connection = (accumulator.call_tcp_v6_connection >= socket->call_tcp_v6_connection) ?
  2097. accumulator.call_tcp_v6_connection : socket->call_tcp_v6_connection;
  2098. }
  2099. /**
  2100. * Create specific socket charts
  2101. *
  2102. * Create charts for cgroup/application.
  2103. *
  2104. * @param type the chart type.
  2105. * @param update_every value to overwrite the update frequency set by the server.
  2106. */
  2107. static void ebpf_create_specific_socket_charts(char *type, int update_every)
  2108. {
  2109. int order_basis = 5300;
  2110. ebpf_create_chart(type, NETDATA_NET_APPS_CONNECTION_TCP_V4,
  2111. "Calls to tcp_v4_connection",
  2112. EBPF_COMMON_DIMENSION_CONNECTIONS, NETDATA_CGROUP_NET_GROUP,
  2113. NETDATA_CGROUP_TCP_V4_CONN_CONTEXT,
  2114. NETDATA_EBPF_CHART_TYPE_LINE,
  2115. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2116. ebpf_create_global_dimension,
  2117. &socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V4], 1,
  2118. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2119. ebpf_create_chart(type, NETDATA_NET_APPS_CONNECTION_TCP_V6,
  2120. "Calls to tcp_v6_connection",
  2121. EBPF_COMMON_DIMENSION_CONNECTIONS, NETDATA_CGROUP_NET_GROUP,
  2122. NETDATA_CGROUP_TCP_V6_CONN_CONTEXT,
  2123. NETDATA_EBPF_CHART_TYPE_LINE,
  2124. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2125. ebpf_create_global_dimension,
  2126. &socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V6], 1,
  2127. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2128. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_RECV,
  2129. "Bytes received",
  2130. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2131. NETDATA_CGROUP_SOCKET_BYTES_RECV_CONTEXT,
  2132. NETDATA_EBPF_CHART_TYPE_LINE,
  2133. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2134. ebpf_create_global_dimension,
  2135. &socket_publish_aggregated[NETDATA_IDX_TCP_CLEANUP_RBUF], 1,
  2136. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2137. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_SENT,
  2138. "Bytes sent",
  2139. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2140. NETDATA_CGROUP_SOCKET_BYTES_SEND_CONTEXT,
  2141. NETDATA_EBPF_CHART_TYPE_LINE,
  2142. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2143. ebpf_create_global_dimension,
  2144. socket_publish_aggregated, 1,
  2145. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2146. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
  2147. "Calls to tcp_cleanup_rbuf.",
  2148. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2149. NETDATA_CGROUP_SOCKET_TCP_RECV_CONTEXT,
  2150. NETDATA_EBPF_CHART_TYPE_LINE,
  2151. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2152. ebpf_create_global_dimension,
  2153. &socket_publish_aggregated[NETDATA_IDX_TCP_CLEANUP_RBUF], 1,
  2154. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2155. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
  2156. "Calls to tcp_sendmsg.",
  2157. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2158. NETDATA_CGROUP_SOCKET_TCP_SEND_CONTEXT,
  2159. NETDATA_EBPF_CHART_TYPE_LINE,
  2160. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2161. ebpf_create_global_dimension,
  2162. socket_publish_aggregated, 1,
  2163. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2164. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
  2165. "Calls to tcp_retransmit.",
  2166. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2167. NETDATA_CGROUP_SOCKET_TCP_RETRANSMIT_CONTEXT,
  2168. NETDATA_EBPF_CHART_TYPE_LINE,
  2169. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2170. ebpf_create_global_dimension,
  2171. &socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT], 1,
  2172. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2173. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
  2174. "Calls to udp_sendmsg",
  2175. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2176. NETDATA_CGROUP_SOCKET_UDP_SEND_CONTEXT,
  2177. NETDATA_EBPF_CHART_TYPE_LINE,
  2178. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2179. ebpf_create_global_dimension,
  2180. &socket_publish_aggregated[NETDATA_IDX_UDP_SENDMSG], 1,
  2181. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2182. ebpf_create_chart(type, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
  2183. "Calls to udp_recvmsg",
  2184. EBPF_COMMON_DIMENSION_CALL, NETDATA_CGROUP_NET_GROUP,
  2185. NETDATA_CGROUP_SOCKET_UDP_RECV_CONTEXT,
  2186. NETDATA_EBPF_CHART_TYPE_LINE,
  2187. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++,
  2188. ebpf_create_global_dimension,
  2189. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF], 1,
  2190. update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
  2191. }
  2192. /**
  2193. * Obsolete specific socket charts
  2194. *
  2195. * Obsolete charts for cgroup/application.
  2196. *
  2197. * @param type the chart type.
  2198. * @param update_every value to overwrite the update frequency set by the server.
  2199. */
  2200. static void ebpf_obsolete_specific_socket_charts(char *type, int update_every)
  2201. {
  2202. int order_basis = 5300;
  2203. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_CONNECTION_TCP_V4, "Calls to tcp_v4_connection",
  2204. EBPF_COMMON_DIMENSION_CONNECTIONS, NETDATA_APPS_NET_GROUP,
  2205. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_TCP_V4_CONN_CONTEXT,
  2206. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2207. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_CONNECTION_TCP_V6,"Calls to tcp_v6_connection",
  2208. EBPF_COMMON_DIMENSION_CONNECTIONS, NETDATA_APPS_NET_GROUP,
  2209. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_TCP_V6_CONN_CONTEXT,
  2210. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2211. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_RECV, "Bytes received",
  2212. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2213. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_BYTES_RECV_CONTEXT,
  2214. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2215. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_SENT,"Bytes sent",
  2216. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2217. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_BYTES_SEND_CONTEXT,
  2218. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2219. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS, "Calls to tcp_cleanup_rbuf.",
  2220. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2221. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_TCP_RECV_CONTEXT,
  2222. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2223. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS, "Calls to tcp_sendmsg.",
  2224. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2225. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_TCP_SEND_CONTEXT,
  2226. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2227. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT, "Calls to tcp_retransmit.",
  2228. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2229. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_TCP_RETRANSMIT_CONTEXT,
  2230. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2231. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS, "Calls to udp_sendmsg",
  2232. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP,
  2233. NETDATA_EBPF_CHART_TYPE_LINE, NETDATA_SERVICES_SOCKET_UDP_SEND_CONTEXT,
  2234. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2235. ebpf_write_chart_obsolete(type, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS, "Calls to udp_recvmsg",
  2236. EBPF_COMMON_DIMENSION_CALL, NETDATA_APPS_NET_GROUP, NETDATA_EBPF_CHART_TYPE_LINE,
  2237. NETDATA_SERVICES_SOCKET_UDP_RECV_CONTEXT,
  2238. NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + order_basis++, update_every);
  2239. }
  2240. /*
  2241. * Send Specific Swap data
  2242. *
  2243. * Send data for specific cgroup/apps.
  2244. *
  2245. * @param type chart type
  2246. * @param values structure with values that will be sent to netdata
  2247. */
  2248. static void ebpf_send_specific_socket_data(char *type, ebpf_socket_publish_apps_t *values)
  2249. {
  2250. write_begin_chart(type, NETDATA_NET_APPS_CONNECTION_TCP_V4);
  2251. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V4].name,
  2252. (long long) values->call_tcp_v4_connection);
  2253. write_end_chart();
  2254. write_begin_chart(type, NETDATA_NET_APPS_CONNECTION_TCP_V6);
  2255. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_CONNECTION_V6].name,
  2256. (long long) values->call_tcp_v6_connection);
  2257. write_end_chart();
  2258. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_SENT);
  2259. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_SENDMSG].name,
  2260. (long long) values->bytes_sent);
  2261. write_end_chart();
  2262. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_RECV);
  2263. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_CLEANUP_RBUF].name,
  2264. (long long) values->bytes_received);
  2265. write_end_chart();
  2266. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS);
  2267. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_SENDMSG].name,
  2268. (long long) values->call_tcp_sent);
  2269. write_end_chart();
  2270. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS);
  2271. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_CLEANUP_RBUF].name,
  2272. (long long) values->call_tcp_received);
  2273. write_end_chart();
  2274. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT);
  2275. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT].name,
  2276. (long long) values->retransmit);
  2277. write_end_chart();
  2278. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS);
  2279. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_UDP_SENDMSG].name,
  2280. (long long) values->call_udp_sent);
  2281. write_end_chart();
  2282. write_begin_chart(type, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS);
  2283. write_chart_dimension(socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF].name,
  2284. (long long) values->call_udp_received);
  2285. write_end_chart();
  2286. }
  2287. /**
  2288. * Create Systemd Socket Charts
  2289. *
  2290. * Create charts when systemd is enabled
  2291. *
  2292. * @param update_every value to overwrite the update frequency set by the server.
  2293. **/
  2294. static void ebpf_create_systemd_socket_charts(int update_every)
  2295. {
  2296. int order = 20080;
  2297. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_CONNECTION_TCP_V4,
  2298. "Calls to tcp_v4_connection", EBPF_COMMON_DIMENSION_CONNECTIONS,
  2299. NETDATA_APPS_NET_GROUP,
  2300. NETDATA_EBPF_CHART_TYPE_STACKED,
  2301. order++,
  2302. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2303. NETDATA_SERVICES_SOCKET_TCP_V4_CONN_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2304. update_every);
  2305. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_CONNECTION_TCP_V6,
  2306. "Calls to tcp_v6_connection", EBPF_COMMON_DIMENSION_CONNECTIONS,
  2307. NETDATA_APPS_NET_GROUP,
  2308. NETDATA_EBPF_CHART_TYPE_STACKED,
  2309. order++,
  2310. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2311. NETDATA_SERVICES_SOCKET_TCP_V6_CONN_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2312. update_every);
  2313. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_RECV,
  2314. "Bytes received", EBPF_COMMON_DIMENSION_BITS,
  2315. NETDATA_APPS_NET_GROUP,
  2316. NETDATA_EBPF_CHART_TYPE_STACKED,
  2317. order++,
  2318. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2319. NETDATA_SERVICES_SOCKET_BYTES_RECV_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2320. update_every);
  2321. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_SENT,
  2322. "Bytes sent", EBPF_COMMON_DIMENSION_BITS,
  2323. NETDATA_APPS_NET_GROUP,
  2324. NETDATA_EBPF_CHART_TYPE_STACKED,
  2325. order++,
  2326. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2327. NETDATA_SERVICES_SOCKET_BYTES_SEND_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2328. update_every);
  2329. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
  2330. "Calls to tcp_cleanup_rbuf.",
  2331. EBPF_COMMON_DIMENSION_CALL,
  2332. NETDATA_APPS_NET_GROUP,
  2333. NETDATA_EBPF_CHART_TYPE_STACKED,
  2334. order++,
  2335. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2336. NETDATA_SERVICES_SOCKET_TCP_RECV_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2337. update_every);
  2338. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
  2339. "Calls to tcp_sendmsg.",
  2340. EBPF_COMMON_DIMENSION_CALL,
  2341. NETDATA_APPS_NET_GROUP,
  2342. NETDATA_EBPF_CHART_TYPE_STACKED,
  2343. order++,
  2344. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2345. NETDATA_SERVICES_SOCKET_TCP_SEND_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2346. update_every);
  2347. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
  2348. "Calls to tcp_retransmit",
  2349. EBPF_COMMON_DIMENSION_CALL,
  2350. NETDATA_APPS_NET_GROUP,
  2351. NETDATA_EBPF_CHART_TYPE_STACKED,
  2352. order++,
  2353. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2354. NETDATA_SERVICES_SOCKET_TCP_RETRANSMIT_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2355. update_every);
  2356. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
  2357. "Calls to udp_sendmsg",
  2358. EBPF_COMMON_DIMENSION_CALL,
  2359. NETDATA_APPS_NET_GROUP,
  2360. NETDATA_EBPF_CHART_TYPE_STACKED,
  2361. order++,
  2362. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2363. NETDATA_SERVICES_SOCKET_UDP_SEND_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2364. update_every);
  2365. ebpf_create_charts_on_systemd(NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
  2366. "Calls to udp_recvmsg",
  2367. EBPF_COMMON_DIMENSION_CALL,
  2368. NETDATA_APPS_NET_GROUP,
  2369. NETDATA_EBPF_CHART_TYPE_STACKED,
  2370. order++,
  2371. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  2372. NETDATA_SERVICES_SOCKET_UDP_RECV_CONTEXT, NETDATA_EBPF_MODULE_NAME_SOCKET,
  2373. update_every);
  2374. }
  2375. /**
  2376. * Send Systemd charts
  2377. *
  2378. * Send collected data to Netdata.
  2379. *
  2380. * @return It returns the status for chart creation, if it is necessary to remove a specific dimension, zero is returned
  2381. * otherwise function returns 1 to avoid chart recreation
  2382. */
  2383. static int ebpf_send_systemd_socket_charts()
  2384. {
  2385. int ret = 1;
  2386. ebpf_cgroup_target_t *ect;
  2387. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_CONNECTION_TCP_V4);
  2388. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2389. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2390. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_tcp_v4_connection);
  2391. } else if (unlikely(ect->systemd))
  2392. ret = 0;
  2393. }
  2394. write_end_chart();
  2395. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_CONNECTION_TCP_V6);
  2396. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2397. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2398. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_tcp_v6_connection);
  2399. } else
  2400. ret = 0;
  2401. }
  2402. write_end_chart();
  2403. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_SENT);
  2404. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2405. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2406. write_chart_dimension(ect->name, (long long)ect->publish_socket.bytes_sent);
  2407. } else
  2408. ret = 0;
  2409. }
  2410. write_end_chart();
  2411. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_RECV);
  2412. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2413. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2414. write_chart_dimension(ect->name, (long long)ect->publish_socket.bytes_received);
  2415. }
  2416. }
  2417. write_end_chart();
  2418. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS);
  2419. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2420. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2421. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_tcp_sent);
  2422. }
  2423. }
  2424. write_end_chart();
  2425. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS);
  2426. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2427. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2428. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_tcp_received);
  2429. }
  2430. }
  2431. write_end_chart();
  2432. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT);
  2433. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2434. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2435. write_chart_dimension(ect->name, (long long)ect->publish_socket.retransmit);
  2436. }
  2437. }
  2438. write_end_chart();
  2439. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS);
  2440. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2441. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2442. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_udp_sent);
  2443. }
  2444. }
  2445. write_end_chart();
  2446. write_begin_chart(NETDATA_SERVICE_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS);
  2447. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2448. if (unlikely(ect->systemd) && unlikely(ect->updated)) {
  2449. write_chart_dimension(ect->name, (long long)ect->publish_socket.call_udp_received);
  2450. }
  2451. }
  2452. write_end_chart();
  2453. return ret;
  2454. }
  2455. /**
  2456. * Update Cgroup algorithm
  2457. *
  2458. * Change algorithm from absolute to incremental
  2459. */
  2460. void ebpf_socket_update_cgroup_algorithm()
  2461. {
  2462. int i;
  2463. for (i = 0; i < NETDATA_MAX_SOCKET_VECTOR; i++) {
  2464. netdata_publish_syscall_t *ptr = &socket_publish_aggregated[i];
  2465. freez(ptr->algorithm);
  2466. ptr->algorithm = strdupz(ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
  2467. }
  2468. }
  2469. /**
  2470. * Send data to Netdata calling auxiliary functions.
  2471. *
  2472. * @param update_every value to overwrite the update frequency set by the server.
  2473. */
  2474. static void ebpf_socket_send_cgroup_data(int update_every)
  2475. {
  2476. if (!ebpf_cgroup_pids)
  2477. return;
  2478. pthread_mutex_lock(&mutex_cgroup_shm);
  2479. ebpf_cgroup_target_t *ect;
  2480. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2481. ebpf_socket_sum_cgroup_pids(&ect->publish_socket, ect->pids);
  2482. }
  2483. int has_systemd = shm_ebpf_cgroup.header->systemd_enabled;
  2484. if (has_systemd) {
  2485. static int systemd_charts = 0;
  2486. if (!systemd_charts) {
  2487. ebpf_create_systemd_socket_charts(update_every);
  2488. systemd_charts = 1;
  2489. }
  2490. systemd_charts = ebpf_send_systemd_socket_charts();
  2491. }
  2492. for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
  2493. if (ect->systemd)
  2494. continue;
  2495. if (!(ect->flags & NETDATA_EBPF_CGROUP_HAS_SOCKET_CHART)) {
  2496. ebpf_create_specific_socket_charts(ect->name, update_every);
  2497. ect->flags |= NETDATA_EBPF_CGROUP_HAS_SOCKET_CHART;
  2498. }
  2499. if (ect->flags & NETDATA_EBPF_CGROUP_HAS_SOCKET_CHART && ect->updated) {
  2500. ebpf_send_specific_socket_data(ect->name, &ect->publish_socket);
  2501. } else {
  2502. ebpf_obsolete_specific_socket_charts(ect->name, update_every);
  2503. ect->flags &= ~NETDATA_EBPF_CGROUP_HAS_SOCKET_CHART;
  2504. }
  2505. }
  2506. pthread_mutex_unlock(&mutex_cgroup_shm);
  2507. }
  2508. /*****************************************************************
  2509. *
  2510. * FUNCTIONS WITH THE MAIN LOOP
  2511. *
  2512. *****************************************************************/
  2513. /**
  2514. * Main loop for this collector.
  2515. *
  2516. * @param step the number of microseconds used with heart beat
  2517. * @param em the structure with thread information
  2518. */
  2519. static void socket_collector(usec_t step, ebpf_module_t *em)
  2520. {
  2521. heartbeat_t hb;
  2522. heartbeat_init(&hb);
  2523. socket_threads.thread = mallocz(sizeof(netdata_thread_t));
  2524. socket_threads.start_routine = ebpf_socket_read_hash;
  2525. netdata_thread_create(socket_threads.thread, socket_threads.name,
  2526. NETDATA_THREAD_OPTION_DEFAULT, ebpf_socket_read_hash, em);
  2527. int cgroups = em->cgroup_charts;
  2528. if (cgroups)
  2529. ebpf_socket_update_cgroup_algorithm();
  2530. int socket_global_enabled = em->global_charts;
  2531. int network_connection = em->optional;
  2532. int update_every = em->update_every;
  2533. while (!ebpf_exit_plugin) {
  2534. (void)heartbeat_next(&hb, step);
  2535. if (ebpf_exit_plugin)
  2536. break;
  2537. netdata_apps_integration_flags_t socket_apps_enabled = em->apps_charts;
  2538. pthread_mutex_lock(&collect_data_mutex);
  2539. if (socket_global_enabled)
  2540. read_hash_global_tables();
  2541. if (socket_apps_enabled)
  2542. ebpf_socket_update_apps_data();
  2543. if (cgroups)
  2544. ebpf_update_socket_cgroup();
  2545. calculate_nv_plot();
  2546. pthread_mutex_lock(&lock);
  2547. if (socket_global_enabled)
  2548. ebpf_socket_send_data(em);
  2549. if (socket_apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
  2550. ebpf_socket_send_apps_data(em, apps_groups_root_target);
  2551. if (cgroups)
  2552. ebpf_socket_send_cgroup_data(update_every);
  2553. fflush(stdout);
  2554. if (network_connection) {
  2555. // We are calling fflush many times, because when we have a lot of dimensions
  2556. // we began to have not expected outputs and Netdata closed the plugin.
  2557. pthread_mutex_lock(&nv_mutex);
  2558. ebpf_socket_create_nv_charts(&inbound_vectors, update_every);
  2559. fflush(stdout);
  2560. ebpf_socket_send_nv_data(&inbound_vectors);
  2561. ebpf_socket_create_nv_charts(&outbound_vectors, update_every);
  2562. fflush(stdout);
  2563. ebpf_socket_send_nv_data(&outbound_vectors);
  2564. wait_to_plot = 0;
  2565. pthread_mutex_unlock(&nv_mutex);
  2566. }
  2567. pthread_mutex_unlock(&lock);
  2568. pthread_mutex_unlock(&collect_data_mutex);
  2569. }
  2570. }
  2571. /*****************************************************************
  2572. *
  2573. * FUNCTIONS TO START THREAD
  2574. *
  2575. *****************************************************************/
  2576. /**
  2577. * Allocate vectors used with this thread.
  2578. * We are not testing the return, because callocz does this and shutdown the software
  2579. * case it was not possible to allocate.
  2580. *
  2581. * @param apps is apps enabled?
  2582. */
  2583. static void ebpf_socket_allocate_global_vectors(int apps)
  2584. {
  2585. memset(socket_aggregated_data, 0 ,NETDATA_MAX_SOCKET_VECTOR * sizeof(netdata_syscall_stat_t));
  2586. memset(socket_publish_aggregated, 0 ,NETDATA_MAX_SOCKET_VECTOR * sizeof(netdata_publish_syscall_t));
  2587. socket_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
  2588. if (apps)
  2589. socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
  2590. bandwidth_vector = callocz((size_t)ebpf_nprocs, sizeof(ebpf_bandwidth_t));
  2591. socket_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_socket_t));
  2592. inbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
  2593. outbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
  2594. }
  2595. /**
  2596. * Initialize Inbound and Outbound
  2597. *
  2598. * Initialize the common outbound and inbound sockets.
  2599. */
  2600. static void initialize_inbound_outbound()
  2601. {
  2602. inbound_vectors.last = network_viewer_opt.max_dim - 1;
  2603. outbound_vectors.last = inbound_vectors.last;
  2604. fill_last_nv_dimension(&inbound_vectors.plot[inbound_vectors.last], 0);
  2605. fill_last_nv_dimension(&outbound_vectors.plot[outbound_vectors.last], 1);
  2606. }
  2607. /*****************************************************************
  2608. *
  2609. * EBPF SOCKET THREAD
  2610. *
  2611. *****************************************************************/
  2612. /**
  2613. * Fill Port list
  2614. *
  2615. * @param out a pointer to the link list.
  2616. * @param in the structure that will be linked.
  2617. */
  2618. static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in)
  2619. {
  2620. if (likely(*out)) {
  2621. ebpf_network_viewer_port_list_t *move = *out, *store = *out;
  2622. uint16_t first = ntohs(in->first);
  2623. uint16_t last = ntohs(in->last);
  2624. while (move) {
  2625. uint16_t cmp_first = ntohs(move->first);
  2626. uint16_t cmp_last = ntohs(move->last);
  2627. if (cmp_first <= first && first <= cmp_last &&
  2628. cmp_first <= last && last <= cmp_last ) {
  2629. info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.",
  2630. first, last, cmp_first, cmp_last);
  2631. freez(in->value);
  2632. freez(in);
  2633. return;
  2634. } else if (first <= cmp_first && cmp_first <= last &&
  2635. first <= cmp_last && cmp_last <= last) {
  2636. info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.",
  2637. first, last, cmp_first, cmp_last);
  2638. freez(move->value);
  2639. move->value = in->value;
  2640. move->first = in->first;
  2641. move->last = in->last;
  2642. freez(in);
  2643. return;
  2644. }
  2645. store = move;
  2646. move = move->next;
  2647. }
  2648. store->next = in;
  2649. } else {
  2650. *out = in;
  2651. }
  2652. #ifdef NETDATA_INTERNAL_CHECKS
  2653. info("Adding values %s( %u, %u) to %s port list used on network viewer",
  2654. in->value, ntohs(in->first), ntohs(in->last),
  2655. (*out == network_viewer_opt.included_port)?"included":"excluded");
  2656. #endif
  2657. }
  2658. /**
  2659. * Parse Service List
  2660. *
  2661. * @param out a pointer to store the link list
  2662. * @param service the service used to create the structure that will be linked.
  2663. */
  2664. static void parse_service_list(void **out, char *service)
  2665. {
  2666. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  2667. struct servent *serv = getservbyname((const char *)service, "tcp");
  2668. if (!serv)
  2669. serv = getservbyname((const char *)service, "udp");
  2670. if (!serv) {
  2671. info("Cannot resolv the service '%s' with protocols TCP and UDP, it will be ignored", service);
  2672. return;
  2673. }
  2674. ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  2675. w->value = strdupz(service);
  2676. w->hash = simple_hash(service);
  2677. w->first = w->last = (uint16_t)serv->s_port;
  2678. fill_port_list(list, w);
  2679. }
  2680. /**
  2681. * Netmask
  2682. *
  2683. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  2684. *
  2685. * @param prefix create the netmask based in the CIDR value.
  2686. *
  2687. * @return
  2688. */
  2689. static inline in_addr_t netmask(int prefix) {
  2690. if (prefix == 0)
  2691. return (~((in_addr_t) - 1));
  2692. else
  2693. return (in_addr_t)(~((1 << (32 - prefix)) - 1));
  2694. }
  2695. /**
  2696. * Broadcast
  2697. *
  2698. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  2699. *
  2700. * @param addr is the ip address
  2701. * @param prefix is the CIDR value.
  2702. *
  2703. * @return It returns the last address of the range
  2704. */
  2705. static inline in_addr_t broadcast(in_addr_t addr, int prefix)
  2706. {
  2707. return (addr | ~netmask(prefix));
  2708. }
  2709. /**
  2710. * Network
  2711. *
  2712. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  2713. *
  2714. * @param addr is the ip address
  2715. * @param prefix is the CIDR value.
  2716. *
  2717. * @return It returns the first address of the range.
  2718. */
  2719. static inline in_addr_t ipv4_network(in_addr_t addr, int prefix)
  2720. {
  2721. return (addr & netmask(prefix));
  2722. }
  2723. /**
  2724. * IP to network long
  2725. *
  2726. * @param dst the vector to store the result
  2727. * @param ip the source ip given by our users.
  2728. * @param domain the ip domain (IPV4 or IPV6)
  2729. * @param source the original string
  2730. *
  2731. * @return it returns 0 on success and -1 otherwise.
  2732. */
  2733. static inline int ip2nl(uint8_t *dst, char *ip, int domain, char *source)
  2734. {
  2735. if (inet_pton(domain, ip, dst) <= 0) {
  2736. error("The address specified (%s) is invalid ", source);
  2737. return -1;
  2738. }
  2739. return 0;
  2740. }
  2741. /**
  2742. * Get IPV6 Last Address
  2743. *
  2744. * @param out the address to store the last address.
  2745. * @param in the address used to do the math.
  2746. * @param prefix number of bits used to calculate the address
  2747. */
  2748. static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  2749. {
  2750. uint64_t mask,tmp;
  2751. uint64_t ret[2];
  2752. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  2753. if (prefix == 128) {
  2754. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  2755. return;
  2756. } else if (!prefix) {
  2757. ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF;
  2758. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  2759. return;
  2760. } else if (prefix <= 64) {
  2761. ret[1] = 0xFFFFFFFFFFFFFFFFULL;
  2762. tmp = be64toh(ret[0]);
  2763. if (prefix > 0) {
  2764. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  2765. tmp |= ~mask;
  2766. }
  2767. ret[0] = htobe64(tmp);
  2768. } else {
  2769. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  2770. tmp = be64toh(ret[1]);
  2771. tmp |= ~mask;
  2772. ret[1] = htobe64(tmp);
  2773. }
  2774. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  2775. }
  2776. /**
  2777. * Calculate ipv6 first address
  2778. *
  2779. * @param out the address to store the first address.
  2780. * @param in the address used to do the math.
  2781. * @param prefix number of bits used to calculate the address
  2782. */
  2783. static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  2784. {
  2785. uint64_t mask,tmp;
  2786. uint64_t ret[2];
  2787. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  2788. if (prefix == 128) {
  2789. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  2790. return;
  2791. } else if (!prefix) {
  2792. ret[0] = ret[1] = 0;
  2793. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  2794. return;
  2795. } else if (prefix <= 64) {
  2796. ret[1] = 0ULL;
  2797. tmp = be64toh(ret[0]);
  2798. if (prefix > 0) {
  2799. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  2800. tmp &= mask;
  2801. }
  2802. ret[0] = htobe64(tmp);
  2803. } else {
  2804. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  2805. tmp = be64toh(ret[1]);
  2806. tmp &= mask;
  2807. ret[1] = htobe64(tmp);
  2808. }
  2809. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  2810. }
  2811. /**
  2812. * Is ip inside the range
  2813. *
  2814. * Check if the ip is inside a IP range
  2815. *
  2816. * @param rfirst the first ip address of the range
  2817. * @param rlast the last ip address of the range
  2818. * @param cmpfirst the first ip to compare
  2819. * @param cmplast the last ip to compare
  2820. * @param family the IP family
  2821. *
  2822. * @return It returns 1 if the IP is inside the range and 0 otherwise
  2823. */
  2824. static int is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast,
  2825. union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family)
  2826. {
  2827. if (family == AF_INET) {
  2828. if (ntohl(rfirst->addr32[0]) <= ntohl(cmpfirst->addr32[0]) &&
  2829. ntohl(rlast->addr32[0]) >= ntohl(cmplast->addr32[0]))
  2830. return 1;
  2831. } else {
  2832. if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  2833. memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) {
  2834. return 1;
  2835. }
  2836. }
  2837. return 0;
  2838. }
  2839. /**
  2840. * Fill IP list
  2841. *
  2842. * @param out a pointer to the link list.
  2843. * @param in the structure that will be linked.
  2844. */
  2845. void fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table)
  2846. {
  2847. #ifndef NETDATA_INTERNAL_CHECKS
  2848. UNUSED(table);
  2849. #endif
  2850. if (likely(*out)) {
  2851. ebpf_network_viewer_ip_list_t *move = *out, *store = *out;
  2852. while (move) {
  2853. if (in->ver == move->ver && is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) {
  2854. info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.",
  2855. in->value, move->value);
  2856. freez(in->value);
  2857. freez(in);
  2858. return;
  2859. }
  2860. store = move;
  2861. move = move->next;
  2862. }
  2863. store->next = in;
  2864. } else {
  2865. *out = in;
  2866. }
  2867. #ifdef NETDATA_INTERNAL_CHECKS
  2868. char first[512], last[512];
  2869. if (in->ver == AF_INET) {
  2870. if (inet_ntop(AF_INET, in->first.addr8, first, INET_ADDRSTRLEN) &&
  2871. inet_ntop(AF_INET, in->last.addr8, last, INET_ADDRSTRLEN))
  2872. info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
  2873. first, last,
  2874. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  2875. table);
  2876. } else {
  2877. if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) &&
  2878. inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN))
  2879. info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
  2880. first, last,
  2881. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  2882. table);
  2883. }
  2884. #endif
  2885. }
  2886. /**
  2887. * Parse IP List
  2888. *
  2889. * Parse IP list and link it.
  2890. *
  2891. * @param out a pointer to store the link list
  2892. * @param ip the value given as parameter
  2893. */
  2894. static void parse_ip_list(void **out, char *ip)
  2895. {
  2896. ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out;
  2897. char *ipdup = strdupz(ip);
  2898. union netdata_ip_t first = { };
  2899. union netdata_ip_t last = { };
  2900. char *is_ipv6;
  2901. if (*ip == '*' && *(ip+1) == '\0') {
  2902. memset(first.addr8, 0, sizeof(first.addr8));
  2903. memset(last.addr8, 0xFF, sizeof(last.addr8));
  2904. is_ipv6 = ip;
  2905. clean_ip_structure(list);
  2906. goto storethisip;
  2907. }
  2908. char *end = ip;
  2909. // Move while I cannot find a separator
  2910. while (*end && *end != '/' && *end != '-') end++;
  2911. // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future
  2912. // https://tools.ietf.org/html/rfc1924
  2913. is_ipv6 = strchr(ip, ':');
  2914. int select;
  2915. if (*end && !is_ipv6) { // IPV4 range
  2916. select = (*end == '/') ? 0 : 1;
  2917. *end++ = '\0';
  2918. if (*end == '!') {
  2919. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2920. goto cleanipdup;
  2921. }
  2922. if (!select) { // CIDR
  2923. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  2924. if (select)
  2925. goto cleanipdup;
  2926. select = (int) str2i(end);
  2927. if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) {
  2928. info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip);
  2929. goto cleanipdup;
  2930. }
  2931. last.addr32[0] = htonl(broadcast(ntohl(first.addr32[0]), select));
  2932. // This was added to remove
  2933. // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977
  2934. UNUSED(last.addr32[0]);
  2935. uint32_t ipv4_test = htonl(ipv4_network(ntohl(first.addr32[0]), select));
  2936. if (first.addr32[0] != ipv4_test) {
  2937. first.addr32[0] = ipv4_test;
  2938. struct in_addr ipv4_convert;
  2939. ipv4_convert.s_addr = ipv4_test;
  2940. char ipv4_msg[INET_ADDRSTRLEN];
  2941. if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN))
  2942. info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg);
  2943. }
  2944. } else { // Range
  2945. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  2946. if (select)
  2947. goto cleanipdup;
  2948. select = ip2nl(last.addr8, end, AF_INET, ipdup);
  2949. if (select)
  2950. goto cleanipdup;
  2951. }
  2952. if (htonl(first.addr32[0]) > htonl(last.addr32[0])) {
  2953. info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  2954. ipdup);
  2955. goto cleanipdup;
  2956. }
  2957. } else if (is_ipv6) { // IPV6
  2958. if (!*end) { // Unique
  2959. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2960. if (select)
  2961. goto cleanipdup;
  2962. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  2963. } else if (*end == '-') {
  2964. *end++ = 0x00;
  2965. if (*end == '!') {
  2966. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2967. goto cleanipdup;
  2968. }
  2969. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2970. if (select)
  2971. goto cleanipdup;
  2972. select = ip2nl(last.addr8, end, AF_INET6, ipdup);
  2973. if (select)
  2974. goto cleanipdup;
  2975. } else { // CIDR
  2976. *end++ = 0x00;
  2977. if (*end == '!') {
  2978. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2979. goto cleanipdup;
  2980. }
  2981. select = str2i(end);
  2982. if (select < 0 || select > 128) {
  2983. info("The CIDR %s is not valid, the address %s will be ignored.", end, ip);
  2984. goto cleanipdup;
  2985. }
  2986. uint64_t prefix = (uint64_t)select;
  2987. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2988. if (select)
  2989. goto cleanipdup;
  2990. get_ipv6_last_addr(&last, &first, prefix);
  2991. union netdata_ip_t ipv6_test;
  2992. get_ipv6_first_addr(&ipv6_test, &first, prefix);
  2993. if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) {
  2994. memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t));
  2995. struct in6_addr ipv6_convert;
  2996. memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t));
  2997. char ipv6_msg[INET6_ADDRSTRLEN];
  2998. if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN))
  2999. info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg);
  3000. }
  3001. }
  3002. if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) &&
  3003. !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) ||
  3004. (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) {
  3005. info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  3006. ipdup);
  3007. goto cleanipdup;
  3008. }
  3009. } else { // Unique ip
  3010. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  3011. if (select)
  3012. goto cleanipdup;
  3013. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  3014. }
  3015. ebpf_network_viewer_ip_list_t *store;
  3016. storethisip:
  3017. store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
  3018. store->value = ipdup;
  3019. store->hash = simple_hash(ipdup);
  3020. store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6;
  3021. memcpy(store->first.addr8, first.addr8, sizeof(first.addr8));
  3022. memcpy(store->last.addr8, last.addr8, sizeof(last.addr8));
  3023. fill_ip_list(list, store, "socket");
  3024. return;
  3025. cleanipdup:
  3026. freez(ipdup);
  3027. }
  3028. /**
  3029. * Parse IP Range
  3030. *
  3031. * Parse the IP ranges given and create Network Viewer IP Structure
  3032. *
  3033. * @param ptr is a pointer with the text to parse.
  3034. */
  3035. static void parse_ips(char *ptr)
  3036. {
  3037. // No value
  3038. if (unlikely(!ptr))
  3039. return;
  3040. while (likely(ptr)) {
  3041. // Move forward until next valid character
  3042. while (isspace(*ptr)) ptr++;
  3043. // No valid value found
  3044. if (unlikely(!*ptr))
  3045. return;
  3046. // Find space that ends the list
  3047. char *end = strchr(ptr, ' ');
  3048. if (end) {
  3049. *end++ = '\0';
  3050. }
  3051. int neg = 0;
  3052. if (*ptr == '!') {
  3053. neg++;
  3054. ptr++;
  3055. }
  3056. if (isascii(*ptr)) { // Parse port
  3057. parse_ip_list((!neg)?(void **)&network_viewer_opt.included_ips:(void **)&network_viewer_opt.excluded_ips,
  3058. ptr);
  3059. }
  3060. ptr = end;
  3061. }
  3062. }
  3063. /**
  3064. * Parse port list
  3065. *
  3066. * Parse an allocated port list with the range given
  3067. *
  3068. * @param out a pointer to store the link list
  3069. * @param range the informed range for the user.
  3070. */
  3071. static void parse_port_list(void **out, char *range)
  3072. {
  3073. int first, last;
  3074. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  3075. char *copied = strdupz(range);
  3076. if (*range == '*' && *(range+1) == '\0') {
  3077. first = 1;
  3078. last = 65535;
  3079. clean_port_structure(list);
  3080. goto fillenvpl;
  3081. }
  3082. char *end = range;
  3083. //Move while I cannot find a separator
  3084. while (*end && *end != ':' && *end != '-') end++;
  3085. //It has a range
  3086. if (likely(*end)) {
  3087. *end++ = '\0';
  3088. if (*end == '!') {
  3089. info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
  3090. freez(copied);
  3091. return;
  3092. }
  3093. last = str2i((const char *)end);
  3094. } else {
  3095. last = 0;
  3096. }
  3097. first = str2i((const char *)range);
  3098. if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
  3099. info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
  3100. freez(copied);
  3101. return;
  3102. }
  3103. if (!last)
  3104. last = first;
  3105. if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) {
  3106. info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
  3107. freez(copied);
  3108. return;
  3109. }
  3110. if (first > last) {
  3111. info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
  3112. freez(copied);
  3113. return;
  3114. }
  3115. ebpf_network_viewer_port_list_t *w;
  3116. fillenvpl:
  3117. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  3118. w->value = copied;
  3119. w->hash = simple_hash(copied);
  3120. w->first = (uint16_t)htons((uint16_t)first);
  3121. w->last = (uint16_t)htons((uint16_t)last);
  3122. w->cmp_first = (uint16_t)first;
  3123. w->cmp_last = (uint16_t)last;
  3124. fill_port_list(list, w);
  3125. }
  3126. /**
  3127. * Read max dimension.
  3128. *
  3129. * Netdata plot two dimensions per connection, so it is necessary to adjust the values.
  3130. *
  3131. * @param cfg the configuration structure
  3132. */
  3133. static void read_max_dimension(struct config *cfg)
  3134. {
  3135. int maxdim ;
  3136. maxdim = (int) appconfig_get_number(cfg,
  3137. EBPF_NETWORK_VIEWER_SECTION,
  3138. EBPF_MAXIMUM_DIMENSIONS,
  3139. NETDATA_NV_CAP_VALUE);
  3140. if (maxdim < 0) {
  3141. error("'maximum dimensions = %d' must be a positive number, Netdata will change for default value %ld.",
  3142. maxdim, NETDATA_NV_CAP_VALUE);
  3143. maxdim = NETDATA_NV_CAP_VALUE;
  3144. }
  3145. maxdim /= 2;
  3146. if (!maxdim) {
  3147. info("The number of dimensions is too small (%u), we are setting it to minimum 2", network_viewer_opt.max_dim);
  3148. network_viewer_opt.max_dim = 1;
  3149. return;
  3150. }
  3151. network_viewer_opt.max_dim = (uint32_t)maxdim;
  3152. }
  3153. /**
  3154. * Parse Port Range
  3155. *
  3156. * Parse the port ranges given and create Network Viewer Port Structure
  3157. *
  3158. * @param ptr is a pointer with the text to parse.
  3159. */
  3160. static void parse_ports(char *ptr)
  3161. {
  3162. // No value
  3163. if (unlikely(!ptr))
  3164. return;
  3165. while (likely(ptr)) {
  3166. // Move forward until next valid character
  3167. while (isspace(*ptr)) ptr++;
  3168. // No valid value found
  3169. if (unlikely(!*ptr))
  3170. return;
  3171. // Find space that ends the list
  3172. char *end = strchr(ptr, ' ');
  3173. if (end) {
  3174. *end++ = '\0';
  3175. }
  3176. int neg = 0;
  3177. if (*ptr == '!') {
  3178. neg++;
  3179. ptr++;
  3180. }
  3181. if (isdigit(*ptr)) { // Parse port
  3182. parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  3183. ptr);
  3184. } else if (isalpha(*ptr)) { // Parse service
  3185. parse_service_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  3186. ptr);
  3187. } else if (*ptr == '*') { // All
  3188. parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  3189. ptr);
  3190. }
  3191. ptr = end;
  3192. }
  3193. }
  3194. /**
  3195. * Link hostname
  3196. *
  3197. * @param out is the output link list
  3198. * @param in the hostname to add to list.
  3199. */
  3200. static void link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in)
  3201. {
  3202. if (likely(*out)) {
  3203. ebpf_network_viewer_hostname_list_t *move = *out;
  3204. for (; move->next ; move = move->next ) {
  3205. if (move->hash == in->hash && !strcmp(move->value, in->value)) {
  3206. info("The hostname %s was already inserted, it will be ignored.", in->value);
  3207. freez(in->value);
  3208. simple_pattern_free(in->value_pattern);
  3209. freez(in);
  3210. return;
  3211. }
  3212. }
  3213. move->next = in;
  3214. } else {
  3215. *out = in;
  3216. }
  3217. #ifdef NETDATA_INTERNAL_CHECKS
  3218. info("Adding value %s to %s hostname list used on network viewer",
  3219. in->value,
  3220. (*out == network_viewer_opt.included_hostnames)?"included":"excluded");
  3221. #endif
  3222. }
  3223. /**
  3224. * Link Hostnames
  3225. *
  3226. * Parse the list of hostnames to create the link list.
  3227. * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP.
  3228. *
  3229. * @param out is the output link list
  3230. * @param parse is a pointer with the text to parser.
  3231. */
  3232. static void link_hostnames(char *parse)
  3233. {
  3234. // No value
  3235. if (unlikely(!parse))
  3236. return;
  3237. while (likely(parse)) {
  3238. // Find the first valid value
  3239. while (isspace(*parse)) parse++;
  3240. // No valid value found
  3241. if (unlikely(!*parse))
  3242. return;
  3243. // Find space that ends the list
  3244. char *end = strchr(parse, ' ');
  3245. if (end) {
  3246. *end++ = '\0';
  3247. }
  3248. int neg = 0;
  3249. if (*parse == '!') {
  3250. neg++;
  3251. parse++;
  3252. }
  3253. ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t));
  3254. hostname->value = strdupz(parse);
  3255. hostname->hash = simple_hash(parse);
  3256. hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT);
  3257. link_hostname((!neg)?&network_viewer_opt.included_hostnames:&network_viewer_opt.excluded_hostnames,
  3258. hostname);
  3259. parse = end;
  3260. }
  3261. }
  3262. /**
  3263. * Parse network viewer section
  3264. *
  3265. * @param cfg the configuration structure
  3266. */
  3267. void parse_network_viewer_section(struct config *cfg)
  3268. {
  3269. read_max_dimension(cfg);
  3270. network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(cfg,
  3271. EBPF_NETWORK_VIEWER_SECTION,
  3272. EBPF_CONFIG_RESOLVE_HOSTNAME,
  3273. CONFIG_BOOLEAN_NO);
  3274. network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(cfg,
  3275. EBPF_NETWORK_VIEWER_SECTION,
  3276. EBPF_CONFIG_RESOLVE_SERVICE,
  3277. CONFIG_BOOLEAN_NO);
  3278. char *value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_PORTS, NULL);
  3279. parse_ports(value);
  3280. if (network_viewer_opt.hostname_resolution_enabled) {
  3281. value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_HOSTNAMES, NULL);
  3282. link_hostnames(value);
  3283. } else {
  3284. info("Name resolution is disabled, collector will not parser \"hostnames\" list.");
  3285. }
  3286. value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION,
  3287. "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");
  3288. parse_ips(value);
  3289. }
  3290. /**
  3291. * Link dimension name
  3292. *
  3293. * Link user specified names inside a link list.
  3294. *
  3295. * @param port the port number associated to the dimension name.
  3296. * @param hash the calculated hash for the dimension name.
  3297. * @param name the dimension name.
  3298. */
  3299. static void link_dimension_name(char *port, uint32_t hash, char *value)
  3300. {
  3301. int test = str2i(port);
  3302. if (test < NETDATA_MINIMUM_PORT_VALUE || test > NETDATA_MAXIMUM_PORT_VALUE){
  3303. error("The dimension given (%s = %s) has an invalid value and it will be ignored.", port, value);
  3304. return;
  3305. }
  3306. ebpf_network_viewer_dim_name_t *w;
  3307. w = callocz(1, sizeof(ebpf_network_viewer_dim_name_t));
  3308. w->name = strdupz(value);
  3309. w->hash = hash;
  3310. w->port = (uint16_t) htons(test);
  3311. ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names;
  3312. if (unlikely(!names)) {
  3313. network_viewer_opt.names = w;
  3314. } else {
  3315. for (; names->next; names = names->next) {
  3316. if (names->port == w->port) {
  3317. info("Duplicated definition for a service, the name %s will be ignored. ", names->name);
  3318. freez(names->name);
  3319. names->name = w->name;
  3320. names->hash = w->hash;
  3321. freez(w);
  3322. return;
  3323. }
  3324. }
  3325. names->next = w;
  3326. }
  3327. #ifdef NETDATA_INTERNAL_CHECKS
  3328. info("Adding values %s( %u) to dimension name list used on network viewer", w->name, htons(w->port));
  3329. #endif
  3330. }
  3331. /**
  3332. * Parse service Name section.
  3333. *
  3334. * This function gets the values that will be used to overwrite dimensions.
  3335. *
  3336. * @param cfg the configuration structure
  3337. */
  3338. void parse_service_name_section(struct config *cfg)
  3339. {
  3340. struct section *co = appconfig_get_section(cfg, EBPF_SERVICE_NAME_SECTION);
  3341. if (co) {
  3342. struct config_option *cv;
  3343. for (cv = co->values; cv ; cv = cv->next) {
  3344. link_dimension_name(cv->name, cv->hash, cv->value);
  3345. }
  3346. }
  3347. // Always associated the default port to Netdata
  3348. ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names;
  3349. if (names) {
  3350. uint16_t default_port = htons(19999);
  3351. while (names) {
  3352. if (names->port == default_port)
  3353. return;
  3354. names = names->next;
  3355. }
  3356. }
  3357. char *port_string = getenv("NETDATA_LISTEN_PORT");
  3358. if (port_string) {
  3359. // if variable has an invalid value, we assume netdata is using 19999
  3360. int default_port = str2i(port_string);
  3361. if (default_port > 0 && default_port < 65536)
  3362. link_dimension_name(port_string, simple_hash(port_string), "Netdata");
  3363. }
  3364. }
  3365. void parse_table_size_options(struct config *cfg)
  3366. {
  3367. socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].user_input = (uint32_t) appconfig_get_number(cfg,
  3368. EBPF_GLOBAL_SECTION,
  3369. EBPF_CONFIG_BANDWIDTH_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  3370. socket_maps[NETDATA_SOCKET_TABLE_IPV4].user_input = (uint32_t) appconfig_get_number(cfg,
  3371. EBPF_GLOBAL_SECTION,
  3372. EBPF_CONFIG_IPV4_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  3373. socket_maps[NETDATA_SOCKET_TABLE_IPV6].user_input = (uint32_t) appconfig_get_number(cfg,
  3374. EBPF_GLOBAL_SECTION,
  3375. EBPF_CONFIG_IPV6_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  3376. socket_maps[NETDATA_SOCKET_TABLE_UDP].user_input = (uint32_t) appconfig_get_number(cfg,
  3377. EBPF_GLOBAL_SECTION,
  3378. EBPF_CONFIG_UDP_SIZE, NETDATA_MAXIMUM_UDP_CONNECTIONS_ALLOWED);
  3379. }
  3380. /*
  3381. * Load BPF
  3382. *
  3383. * Load BPF files.
  3384. *
  3385. * @param em the structure with configuration
  3386. */
  3387. static int ebpf_socket_load_bpf(ebpf_module_t *em)
  3388. {
  3389. int ret = 0;
  3390. if (em->load & EBPF_LOAD_LEGACY) {
  3391. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  3392. if (!em->probe_links) {
  3393. ret = -1;
  3394. }
  3395. }
  3396. #ifdef LIBBPF_MAJOR_VERSION
  3397. else {
  3398. bpf_obj = socket_bpf__open();
  3399. if (!bpf_obj)
  3400. ret = -1;
  3401. else
  3402. ret = ebpf_socket_load_and_attach(bpf_obj, em);
  3403. }
  3404. #endif
  3405. if (ret) {
  3406. error("%s %s", EBPF_DEFAULT_ERROR_MSG, em->thread_name);
  3407. }
  3408. return ret;
  3409. }
  3410. /**
  3411. * Socket thread
  3412. *
  3413. * Thread used to generate socket charts.
  3414. *
  3415. * @param ptr a pointer to `struct ebpf_module`
  3416. *
  3417. * @return It always return NULL
  3418. */
  3419. void *ebpf_socket_thread(void *ptr)
  3420. {
  3421. netdata_thread_cleanup_push(ebpf_socket_exit, ptr);
  3422. memset(&inbound_vectors.tree, 0, sizeof(avl_tree_lock));
  3423. memset(&outbound_vectors.tree, 0, sizeof(avl_tree_lock));
  3424. avl_init_lock(&inbound_vectors.tree, compare_sockets);
  3425. avl_init_lock(&outbound_vectors.tree, compare_sockets);
  3426. ebpf_module_t *em = (ebpf_module_t *)ptr;
  3427. em->maps = socket_maps;
  3428. parse_network_viewer_section(&socket_config);
  3429. parse_service_name_section(&socket_config);
  3430. parse_table_size_options(&socket_config);
  3431. if (!em->enabled)
  3432. goto endsocket;
  3433. if (pthread_mutex_init(&nv_mutex, NULL)) {
  3434. em->enabled = CONFIG_BOOLEAN_NO;
  3435. error("Cannot initialize local mutex");
  3436. goto endsocket;
  3437. }
  3438. ebpf_socket_allocate_global_vectors(em->apps_charts);
  3439. initialize_inbound_outbound();
  3440. if (running_on_kernel < NETDATA_EBPF_KERNEL_5_0)
  3441. em->mode = MODE_ENTRY;
  3442. #ifdef LIBBPF_MAJOR_VERSION
  3443. ebpf_adjust_thread_load(em, default_btf);
  3444. #endif
  3445. if (ebpf_socket_load_bpf(em)) {
  3446. em->enabled = CONFIG_BOOLEAN_NO;
  3447. pthread_mutex_unlock(&lock);
  3448. goto endsocket;
  3449. }
  3450. int algorithms[NETDATA_MAX_SOCKET_VECTOR] = {
  3451. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  3452. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  3453. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  3454. NETDATA_EBPF_INCREMENTAL_IDX
  3455. };
  3456. ebpf_global_labels(
  3457. socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
  3458. algorithms, NETDATA_MAX_SOCKET_VECTOR);
  3459. pthread_mutex_lock(&lock);
  3460. ebpf_create_global_charts(em);
  3461. ebpf_update_stats(&plugin_statistics, em);
  3462. pthread_mutex_unlock(&lock);
  3463. socket_collector((usec_t)(em->update_every * USEC_PER_SEC), em);
  3464. endsocket:
  3465. if (!em->enabled)
  3466. ebpf_update_disabled_plugin_stats(em);
  3467. netdata_thread_cleanup_pop(1);
  3468. return NULL;
  3469. }