ebpf_socket.c 146 KB

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