ebpf_socket.c 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916
  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] = { "sent", "received", "close", "sent",
  11. "received", "retransmitted" };
  12. static char *socket_id_names[NETDATA_MAX_SOCKET_VECTOR] = { "tcp_sendmsg", "tcp_cleanup_rbuf", "tcp_close",
  13. "udp_sendmsg", "udp_recvmsg", "tcp_retransmit_skb" };
  14. static ebpf_local_maps_t socket_maps[] = {{.name = "tbl_bandwidth",
  15. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  16. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED},
  17. {.name = "tbl_conn_ipv4",
  18. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  19. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED},
  20. {.name = "tbl_conn_ipv6",
  21. .internal_input = NETDATA_COMPILED_CONNECTIONS_ALLOWED,
  22. .user_input = NETDATA_MAXIMUM_CONNECTIONS_ALLOWED},
  23. {.name = "tbl_nv_udp_conn_stats",
  24. .internal_input = NETDATA_COMPILED_UDP_CONNECTIONS_ALLOWED,
  25. .user_input = NETDATA_MAXIMUM_UDP_CONNECTIONS_ALLOWED},
  26. {.name = NULL, .internal_input = 0, .user_input = 0}};
  27. static netdata_idx_t *socket_hash_values = NULL;
  28. static netdata_syscall_stat_t socket_aggregated_data[NETDATA_MAX_SOCKET_VECTOR];
  29. static netdata_publish_syscall_t socket_publish_aggregated[NETDATA_MAX_SOCKET_VECTOR];
  30. static ebpf_data_t socket_data;
  31. ebpf_socket_publish_apps_t **socket_bandwidth_curr = NULL;
  32. static ebpf_bandwidth_t *bandwidth_vector = NULL;
  33. static int socket_apps_created = 0;
  34. pthread_mutex_t nv_mutex;
  35. int wait_to_plot = 0;
  36. int read_thread_closed = 1;
  37. netdata_vector_plot_t inbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
  38. netdata_vector_plot_t outbound_vectors = { .plot = NULL, .next = 0, .last = 0 };
  39. netdata_socket_t *socket_values;
  40. ebpf_network_viewer_port_list_t *listen_ports = NULL;
  41. static int *map_fd = NULL;
  42. static struct bpf_object *objects = NULL;
  43. static struct bpf_link **probe_links = NULL;
  44. struct config socket_config = { .first_section = NULL,
  45. .last_section = NULL,
  46. .mutex = NETDATA_MUTEX_INITIALIZER,
  47. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  48. .rwlock = AVL_LOCK_INITIALIZER } };
  49. /*****************************************************************
  50. *
  51. * PROCESS DATA AND SEND TO NETDATA
  52. *
  53. *****************************************************************/
  54. /**
  55. * Update publish structure before to send data to Netdata.
  56. *
  57. * @param publish the first output structure with independent dimensions
  58. * @param tcp structure to store IO from tcp sockets
  59. * @param udp structure to store IO from udp sockets
  60. * @param input the structure with the input data.
  61. */
  62. static void ebpf_update_global_publish(
  63. netdata_publish_syscall_t *publish, netdata_publish_vfs_common_t *tcp, netdata_publish_vfs_common_t *udp,
  64. netdata_syscall_stat_t *input)
  65. {
  66. netdata_publish_syscall_t *move = publish;
  67. while (move) {
  68. if (input->call != move->pcall) {
  69. // This condition happens to avoid initial values with dimensions higher than normal values.
  70. if (move->pcall) {
  71. move->ncall = (input->call > move->pcall) ? input->call - move->pcall : move->pcall - input->call;
  72. move->nbyte = (input->bytes > move->pbyte) ? input->bytes - move->pbyte : move->pbyte - input->bytes;
  73. move->nerr = (input->ecall > move->nerr) ? input->ecall - move->perr : move->perr - input->ecall;
  74. } else {
  75. move->ncall = 0;
  76. move->nbyte = 0;
  77. move->nerr = 0;
  78. }
  79. move->pcall = input->call;
  80. move->pbyte = input->bytes;
  81. move->perr = input->ecall;
  82. } else {
  83. move->ncall = 0;
  84. move->nbyte = 0;
  85. move->nerr = 0;
  86. }
  87. input = input->next;
  88. move = move->next;
  89. }
  90. tcp->write = -(long)publish[0].nbyte;
  91. tcp->read = (long)publish[1].nbyte;
  92. udp->write = -(long)publish[3].nbyte;
  93. udp->read = (long)publish[4].nbyte;
  94. }
  95. /**
  96. * Update Network Viewer plot data
  97. *
  98. * @param plot the structure where the data will be stored
  99. * @param sock the last update from the socket
  100. */
  101. static inline void update_nv_plot_data(netdata_plot_values_t *plot, netdata_socket_t *sock)
  102. {
  103. if (sock->ct > plot->last_time) {
  104. plot->last_time = sock->ct;
  105. plot->plot_recv_packets = sock->recv_packets;
  106. plot->plot_sent_packets = sock->sent_packets;
  107. plot->plot_recv_bytes = sock->recv_bytes;
  108. plot->plot_sent_bytes = sock->sent_bytes;
  109. plot->plot_retransmit = sock->retransmit;
  110. }
  111. sock->recv_packets = 0;
  112. sock->sent_packets = 0;
  113. sock->recv_bytes = 0;
  114. sock->sent_bytes = 0;
  115. sock->retransmit = 0;
  116. }
  117. /**
  118. * Calculate Network Viewer Plot
  119. *
  120. * Do math with collected values before to plot data.
  121. */
  122. static inline void calculate_nv_plot()
  123. {
  124. uint32_t i;
  125. uint32_t end = inbound_vectors.next;
  126. for (i = 0; i < end; i++) {
  127. update_nv_plot_data(&inbound_vectors.plot[i].plot, &inbound_vectors.plot[i].sock);
  128. }
  129. inbound_vectors.max_plot = end;
  130. // The 'Other' dimension is always calculated for the chart to have at least one dimension
  131. update_nv_plot_data(&inbound_vectors.plot[inbound_vectors.last].plot,
  132. &inbound_vectors.plot[inbound_vectors.last].sock);
  133. end = outbound_vectors.next;
  134. for (i = 0; i < end; i++) {
  135. update_nv_plot_data(&outbound_vectors.plot[i].plot, &outbound_vectors.plot[i].sock);
  136. }
  137. outbound_vectors.max_plot = end;
  138. // The 'Other' dimension is always calculated for the chart to have at least one dimension
  139. update_nv_plot_data(&outbound_vectors.plot[outbound_vectors.last].plot,
  140. &outbound_vectors.plot[outbound_vectors.last].sock);
  141. }
  142. /**
  143. * Network viewer send bytes
  144. *
  145. * @param ptr the structure with values to plot
  146. * @param chart the chart name.
  147. */
  148. static inline void ebpf_socket_nv_send_bytes(netdata_vector_plot_t *ptr, char *chart)
  149. {
  150. uint32_t i;
  151. uint32_t end = ptr->last_plot;
  152. netdata_socket_plot_t *w = ptr->plot;
  153. collected_number value;
  154. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  155. for (i = 0; i < end; i++) {
  156. value = ((collected_number) w[i].plot.plot_sent_bytes);
  157. write_chart_dimension(w[i].dimension_sent, value);
  158. value = (collected_number) w[i].plot.plot_recv_bytes;
  159. write_chart_dimension(w[i].dimension_recv, value);
  160. }
  161. i = ptr->last;
  162. value = ((collected_number) w[i].plot.plot_sent_bytes);
  163. write_chart_dimension(w[i].dimension_sent, value);
  164. value = (collected_number) w[i].plot.plot_recv_bytes;
  165. write_chart_dimension(w[i].dimension_recv, value);
  166. write_end_chart();
  167. }
  168. /**
  169. * Network Viewer Send packets
  170. *
  171. * @param ptr the structure with values to plot
  172. * @param chart the chart name.
  173. */
  174. static inline void ebpf_socket_nv_send_packets(netdata_vector_plot_t *ptr, char *chart)
  175. {
  176. uint32_t i;
  177. uint32_t end = ptr->last_plot;
  178. netdata_socket_plot_t *w = ptr->plot;
  179. collected_number value;
  180. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  181. for (i = 0; i < end; i++) {
  182. value = ((collected_number)w[i].plot.plot_sent_packets);
  183. write_chart_dimension(w[i].dimension_sent, value);
  184. value = (collected_number) w[i].plot.plot_recv_packets;
  185. write_chart_dimension(w[i].dimension_recv, value);
  186. }
  187. i = ptr->last;
  188. value = ((collected_number)w[i].plot.plot_sent_packets);
  189. write_chart_dimension(w[i].dimension_sent, value);
  190. value = (collected_number)w[i].plot.plot_recv_packets;
  191. write_chart_dimension(w[i].dimension_recv, value);
  192. write_end_chart();
  193. }
  194. /**
  195. * Network Viewer Send Retransmit
  196. *
  197. * @param ptr the structure with values to plot
  198. * @param chart the chart name.
  199. */
  200. static inline void ebpf_socket_nv_send_retransmit(netdata_vector_plot_t *ptr, char *chart)
  201. {
  202. uint32_t i;
  203. uint32_t end = ptr->last_plot;
  204. netdata_socket_plot_t *w = ptr->plot;
  205. collected_number value;
  206. write_begin_chart(NETDATA_EBPF_FAMILY, chart);
  207. for (i = 0; i < end; i++) {
  208. value = (collected_number) w[i].plot.plot_retransmit;
  209. write_chart_dimension(w[i].dimension_retransmit, value);
  210. }
  211. i = ptr->last;
  212. value = (collected_number)w[i].plot.plot_retransmit;
  213. write_chart_dimension(w[i].dimension_retransmit, value);
  214. write_end_chart();
  215. }
  216. /**
  217. * Send network viewer data
  218. *
  219. * @param ptr the pointer to plot data
  220. */
  221. static void ebpf_socket_send_nv_data(netdata_vector_plot_t *ptr)
  222. {
  223. if (!ptr->flags)
  224. return;
  225. if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
  226. ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_OUTBOUND_BYTES);
  227. fflush(stdout);
  228. ebpf_socket_nv_send_packets(ptr, NETDATA_NV_OUTBOUND_PACKETS);
  229. fflush(stdout);
  230. ebpf_socket_nv_send_retransmit(ptr, NETDATA_NV_OUTBOUND_RETRANSMIT);
  231. fflush(stdout);
  232. } else {
  233. ebpf_socket_nv_send_bytes(ptr, NETDATA_NV_INBOUND_BYTES);
  234. fflush(stdout);
  235. ebpf_socket_nv_send_packets(ptr, NETDATA_NV_INBOUND_PACKETS);
  236. fflush(stdout);
  237. }
  238. }
  239. /**
  240. * Send data to Netdata calling auxiliar functions.
  241. *
  242. * @param em the structure with thread information
  243. */
  244. static void ebpf_socket_send_data(ebpf_module_t *em)
  245. {
  246. netdata_publish_vfs_common_t common_tcp;
  247. netdata_publish_vfs_common_t common_udp;
  248. ebpf_update_global_publish(socket_publish_aggregated, &common_tcp, &common_udp, socket_aggregated_data);
  249. // We read bytes from function arguments, but bandiwdth is given in bits,
  250. // so we need to multiply by 8 to convert for the final value.
  251. write_count_chart(
  252. NETDATA_TCP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 3);
  253. write_io_chart(
  254. NETDATA_TCP_FUNCTION_BITS, NETDATA_EBPF_FAMILY, socket_id_names[0], common_tcp.write*8/1000,
  255. socket_id_names[1], common_tcp.read*8/1000);
  256. if (em->mode < MODE_ENTRY) {
  257. write_err_chart(
  258. NETDATA_TCP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY, socket_publish_aggregated, 2);
  259. }
  260. write_count_chart(
  261. NETDATA_TCP_RETRANSMIT, NETDATA_EBPF_FAMILY, &socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT],
  262. 1);
  263. write_count_chart(
  264. NETDATA_UDP_FUNCTION_COUNT, NETDATA_EBPF_FAMILY, &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  265. 2);
  266. write_io_chart(
  267. NETDATA_UDP_FUNCTION_BITS, NETDATA_EBPF_FAMILY,
  268. socket_id_names[3],(long long)common_udp.write*8/100,
  269. socket_id_names[4], (long long)common_udp.read*8/1000);
  270. if (em->mode < MODE_ENTRY) {
  271. write_err_chart(
  272. NETDATA_UDP_FUNCTION_ERROR, NETDATA_EBPF_FAMILY, &socket_publish_aggregated[NETDATA_UDP_START],
  273. 2);
  274. }
  275. }
  276. /**
  277. * Sum values for pid
  278. *
  279. * @param root the structure with all available PIDs
  280. *
  281. * @param offset the address that we are reading
  282. *
  283. * @return it returns the sum of all PIDs
  284. */
  285. long long ebpf_socket_sum_values_for_pids(struct pid_on_target *root, size_t offset)
  286. {
  287. long long ret = 0;
  288. while (root) {
  289. int32_t pid = root->pid;
  290. ebpf_socket_publish_apps_t *w = socket_bandwidth_curr[pid];
  291. if (w) {
  292. ret += get_value_from_structure((char *)w, offset);
  293. }
  294. root = root->next;
  295. }
  296. return ret;
  297. }
  298. /**
  299. * Send data to Netdata calling auxiliar functions.
  300. *
  301. * @param em the structure with thread information
  302. * @param root the target list.
  303. */
  304. void ebpf_socket_send_apps_data(ebpf_module_t *em, struct target *root)
  305. {
  306. UNUSED(em);
  307. if (!socket_apps_created)
  308. return;
  309. struct target *w;
  310. collected_number value;
  311. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_SENT);
  312. for (w = root; w; w = w->next) {
  313. if (unlikely(w->exposed && w->processes)) {
  314. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  315. bytes_sent));
  316. // We multiply by 0.008, because we read bytes, but we display bits
  317. write_chart_dimension(w->name, ((value)*8)/1000);
  318. }
  319. }
  320. write_end_chart();
  321. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_RECV);
  322. for (w = root; w; w = w->next) {
  323. if (unlikely(w->exposed && w->processes)) {
  324. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  325. bytes_received));
  326. // We multiply by 0.008, because we read bytes, but we display bits
  327. write_chart_dimension(w->name, ((value)*8)/1000);
  328. }
  329. }
  330. write_end_chart();
  331. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS);
  332. for (w = root; w; w = w->next) {
  333. if (unlikely(w->exposed && w->processes)) {
  334. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  335. call_tcp_sent));
  336. write_chart_dimension(w->name, value);
  337. }
  338. }
  339. write_end_chart();
  340. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS);
  341. for (w = root; w; w = w->next) {
  342. if (unlikely(w->exposed && w->processes)) {
  343. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  344. call_tcp_received));
  345. write_chart_dimension(w->name, value);
  346. }
  347. }
  348. write_end_chart();
  349. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT);
  350. for (w = root; w; w = w->next) {
  351. if (unlikely(w->exposed && w->processes)) {
  352. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  353. retransmit));
  354. write_chart_dimension(w->name, value);
  355. }
  356. }
  357. write_end_chart();
  358. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS);
  359. for (w = root; w; w = w->next) {
  360. if (unlikely(w->exposed && w->processes)) {
  361. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  362. call_udp_sent));
  363. write_chart_dimension(w->name, value);
  364. }
  365. }
  366. write_end_chart();
  367. write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS);
  368. for (w = root; w; w = w->next) {
  369. if (unlikely(w->exposed && w->processes)) {
  370. value = ebpf_socket_sum_values_for_pids(w->root_pid, offsetof(ebpf_socket_publish_apps_t,
  371. call_udp_received));
  372. write_chart_dimension(w->name, value);
  373. }
  374. }
  375. write_end_chart();
  376. }
  377. /*****************************************************************
  378. *
  379. * FUNCTIONS TO CREATE CHARTS
  380. *
  381. *****************************************************************/
  382. /**
  383. * Create global charts
  384. *
  385. * Call ebpf_create_chart to create the charts for the collector.
  386. *
  387. * @param em a pointer to the structure with the default values.
  388. */
  389. static void ebpf_create_global_charts(ebpf_module_t *em)
  390. {
  391. ebpf_create_chart(NETDATA_EBPF_FAMILY,
  392. NETDATA_TCP_FUNCTION_COUNT,
  393. "Calls to internal functions",
  394. EBPF_COMMON_DIMENSION_CALL,
  395. NETDATA_SOCKET_GROUP,
  396. NULL,
  397. NETDATA_EBPF_CHART_TYPE_LINE,
  398. 21070,
  399. ebpf_create_global_dimension,
  400. socket_publish_aggregated,
  401. 3);
  402. ebpf_create_chart(NETDATA_EBPF_FAMILY, NETDATA_TCP_FUNCTION_BITS,
  403. "TCP bandwidth", EBPF_COMMON_DIMENSION_BITS,
  404. NETDATA_SOCKET_GROUP,
  405. NULL,
  406. NETDATA_EBPF_CHART_TYPE_LINE,
  407. 21071,
  408. ebpf_create_global_dimension,
  409. socket_publish_aggregated,
  410. 3);
  411. if (em->mode < MODE_ENTRY) {
  412. ebpf_create_chart(NETDATA_EBPF_FAMILY,
  413. NETDATA_TCP_FUNCTION_ERROR,
  414. "TCP errors",
  415. EBPF_COMMON_DIMENSION_CALL,
  416. NETDATA_SOCKET_GROUP,
  417. NULL,
  418. NETDATA_EBPF_CHART_TYPE_LINE,
  419. 21072,
  420. ebpf_create_global_dimension,
  421. socket_publish_aggregated,
  422. 2);
  423. }
  424. ebpf_create_chart(NETDATA_EBPF_FAMILY,
  425. NETDATA_TCP_RETRANSMIT,
  426. "Packages retransmitted",
  427. EBPF_COMMON_DIMENSION_CALL,
  428. NETDATA_SOCKET_GROUP,
  429. NULL,
  430. NETDATA_EBPF_CHART_TYPE_LINE,
  431. 21073,
  432. ebpf_create_global_dimension,
  433. &socket_publish_aggregated[NETDATA_IDX_TCP_RETRANSMIT],
  434. 1);
  435. ebpf_create_chart(NETDATA_EBPF_FAMILY,
  436. NETDATA_UDP_FUNCTION_COUNT,
  437. "UDP calls",
  438. EBPF_COMMON_DIMENSION_CALL,
  439. NETDATA_SOCKET_GROUP,
  440. NULL,
  441. NETDATA_EBPF_CHART_TYPE_LINE,
  442. 21074,
  443. ebpf_create_global_dimension,
  444. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  445. 2);
  446. ebpf_create_chart(NETDATA_EBPF_FAMILY, NETDATA_UDP_FUNCTION_BITS,
  447. "UDP bandwidth", EBPF_COMMON_DIMENSION_BITS,
  448. NETDATA_SOCKET_GROUP,
  449. NULL,
  450. NETDATA_EBPF_CHART_TYPE_LINE,
  451. 21075,
  452. ebpf_create_global_dimension,
  453. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  454. 2);
  455. if (em->mode < MODE_ENTRY) {
  456. ebpf_create_chart(NETDATA_EBPF_FAMILY,
  457. NETDATA_UDP_FUNCTION_ERROR,
  458. "UDP errors",
  459. EBPF_COMMON_DIMENSION_CALL,
  460. NETDATA_SOCKET_GROUP,
  461. NULL,
  462. NETDATA_EBPF_CHART_TYPE_LINE,
  463. 21076,
  464. ebpf_create_global_dimension,
  465. &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
  466. 2);
  467. }
  468. }
  469. /**
  470. * Create apps charts
  471. *
  472. * Call ebpf_create_chart to create the charts on apps submenu.
  473. *
  474. * @param em a pointer to the structure with the default values.
  475. * @param ptr a pointer for targets
  476. */
  477. void ebpf_socket_create_apps_charts(struct ebpf_module *em, void *ptr)
  478. {
  479. UNUSED(em);
  480. struct target *root = ptr;;
  481. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_SENT,
  482. "Bytes sent", EBPF_COMMON_DIMENSION_BITS,
  483. NETDATA_APPS_NET_GROUP,
  484. NETDATA_EBPF_CHART_TYPE_STACKED,
  485. 20080,
  486. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  487. root);
  488. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_RECV,
  489. "bytes received", EBPF_COMMON_DIMENSION_BITS,
  490. NETDATA_APPS_NET_GROUP,
  491. NETDATA_EBPF_CHART_TYPE_STACKED,
  492. 20081,
  493. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  494. root);
  495. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_SEND_CALLS,
  496. "Calls for tcp_sendmsg",
  497. EBPF_COMMON_DIMENSION_CALL,
  498. NETDATA_APPS_NET_GROUP,
  499. NETDATA_EBPF_CHART_TYPE_STACKED,
  500. 20082,
  501. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  502. root);
  503. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_RECV_CALLS,
  504. "Calls for tcp_cleanup_rbuf",
  505. EBPF_COMMON_DIMENSION_CALL,
  506. NETDATA_APPS_NET_GROUP,
  507. NETDATA_EBPF_CHART_TYPE_STACKED,
  508. 20083,
  509. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  510. root);
  511. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_TCP_RETRANSMIT,
  512. "Calls for tcp_retransmit",
  513. EBPF_COMMON_DIMENSION_CALL,
  514. NETDATA_APPS_NET_GROUP,
  515. NETDATA_EBPF_CHART_TYPE_STACKED,
  516. 20084,
  517. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  518. root);
  519. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_UDP_SEND_CALLS,
  520. "Calls for udp_sendmsg",
  521. EBPF_COMMON_DIMENSION_CALL,
  522. NETDATA_APPS_NET_GROUP,
  523. NETDATA_EBPF_CHART_TYPE_STACKED,
  524. 20085,
  525. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  526. root);
  527. ebpf_create_charts_on_apps(NETDATA_NET_APPS_BANDWIDTH_UDP_RECV_CALLS,
  528. "Calls for udp_recvmsg",
  529. EBPF_COMMON_DIMENSION_CALL,
  530. NETDATA_APPS_NET_GROUP,
  531. NETDATA_EBPF_CHART_TYPE_STACKED,
  532. 20086,
  533. ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
  534. root);
  535. socket_apps_created = 1;
  536. }
  537. /**
  538. * Create network viewer chart
  539. *
  540. * Create common charts.
  541. *
  542. * @param id the chart id
  543. * @param title the chart title
  544. * @param units the units label
  545. * @param family the group name used to attach the chart on dashboard
  546. * @param order the chart order
  547. * @param ptr the plot structure with values.
  548. */
  549. static void ebpf_socket_create_nv_chart(char *id, char *title, char *units,
  550. char *family, int order, netdata_vector_plot_t *ptr)
  551. {
  552. ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
  553. id,
  554. title,
  555. units,
  556. family,
  557. NETDATA_EBPF_CHART_TYPE_STACKED,
  558. NULL,
  559. order);
  560. uint32_t i;
  561. uint32_t end = ptr->last_plot;
  562. netdata_socket_plot_t *w = ptr->plot;
  563. for (i = 0; i < end; i++) {
  564. fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[i].dimension_sent);
  565. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_recv);
  566. }
  567. end = ptr->last;
  568. fprintf(stdout, "DIMENSION %s '' incremental -1 1\n", w[end].dimension_sent);
  569. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_recv);
  570. }
  571. /**
  572. * Create network viewer retransmit
  573. *
  574. * Create a specific chart.
  575. *
  576. * @param id the chart id
  577. * @param title the chart title
  578. * @param units the units label
  579. * @param family the group name used to attach the chart on dashboard
  580. * @param order the chart order
  581. * @param ptr the plot structure with values.
  582. */
  583. static void ebpf_socket_create_nv_retransmit(char *id, char *title, char *units,
  584. char *family, int order, netdata_vector_plot_t *ptr)
  585. {
  586. ebpf_write_chart_cmd(NETDATA_EBPF_FAMILY,
  587. id,
  588. title,
  589. units,
  590. family,
  591. NETDATA_EBPF_CHART_TYPE_STACKED,
  592. NULL,
  593. order);
  594. uint32_t i;
  595. uint32_t end = ptr->last_plot;
  596. netdata_socket_plot_t *w = ptr->plot;
  597. for (i = 0; i < end; i++) {
  598. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[i].dimension_retransmit);
  599. }
  600. end = ptr->last;
  601. fprintf(stdout, "DIMENSION %s '' incremental 1 1\n", w[end].dimension_retransmit);
  602. }
  603. /**
  604. * Create Network Viewer charts
  605. *
  606. * Recreate the charts when new sockets are created.
  607. *
  608. * @param ptr a pointer for inbound or outbound vectors.
  609. */
  610. static void ebpf_socket_create_nv_charts(netdata_vector_plot_t *ptr)
  611. {
  612. // We do not have new sockets, so we do not need move forward
  613. if (ptr->max_plot == ptr->last_plot)
  614. return;
  615. ptr->last_plot = ptr->max_plot;
  616. if (ptr == (netdata_vector_plot_t *)&outbound_vectors) {
  617. ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_BYTES,
  618. "Outbound connections (bytes).", EBPF_COMMON_DIMENSION_BYTES,
  619. NETDATA_NETWORK_CONNECTIONS_GROUP,
  620. 21080,
  621. ptr);
  622. ebpf_socket_create_nv_chart(NETDATA_NV_OUTBOUND_PACKETS,
  623. "Outbound connections (packets)",
  624. EBPF_COMMON_DIMENSION_PACKETS,
  625. NETDATA_NETWORK_CONNECTIONS_GROUP,
  626. 21082,
  627. ptr);
  628. ebpf_socket_create_nv_retransmit(NETDATA_NV_OUTBOUND_RETRANSMIT,
  629. "Retransmitted packets",
  630. EBPF_COMMON_DIMENSION_CALL,
  631. NETDATA_NETWORK_CONNECTIONS_GROUP,
  632. 21083,
  633. ptr);
  634. } else {
  635. ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_BYTES,
  636. "Inbound connections (bytes)", EBPF_COMMON_DIMENSION_BYTES,
  637. NETDATA_NETWORK_CONNECTIONS_GROUP,
  638. 21084,
  639. ptr);
  640. ebpf_socket_create_nv_chart(NETDATA_NV_INBOUND_PACKETS,
  641. "Inbound connections (packets)",
  642. EBPF_COMMON_DIMENSION_PACKETS,
  643. NETDATA_NETWORK_CONNECTIONS_GROUP,
  644. 21085,
  645. ptr);
  646. }
  647. ptr->flags |= NETWORK_VIEWER_CHARTS_CREATED;
  648. }
  649. /*****************************************************************
  650. *
  651. * READ INFORMATION FROM KERNEL RING
  652. *
  653. *****************************************************************/
  654. /**
  655. * Is specific ip inside the range
  656. *
  657. * Check if the ip is inside a IP range previously defined
  658. *
  659. * @param cmp the IP to compare
  660. * @param family the IP family
  661. *
  662. * @return It returns 1 if the IP is inside the range and 0 otherwise
  663. */
  664. static int is_specific_ip_inside_range(union netdata_ip_t *cmp, int family)
  665. {
  666. if (!network_viewer_opt.excluded_ips && !network_viewer_opt.included_ips)
  667. return 1;
  668. uint32_t ipv4_test = ntohl(cmp->addr32[0]);
  669. ebpf_network_viewer_ip_list_t *move = network_viewer_opt.excluded_ips;
  670. while (move) {
  671. if (family == AF_INET) {
  672. if (ntohl(move->first.addr32[0]) <= ipv4_test &&
  673. ipv4_test <= ntohl(move->last.addr32[0]) )
  674. return 0;
  675. } else {
  676. if (memcmp(move->first.addr8, cmp->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  677. memcmp(move->last.addr8, cmp->addr8, sizeof(union netdata_ip_t)) >= 0) {
  678. return 0;
  679. }
  680. }
  681. move = move->next;
  682. }
  683. move = network_viewer_opt.included_ips;
  684. while (move) {
  685. if (family == AF_INET) {
  686. if (ntohl(move->first.addr32[0]) <= ipv4_test &&
  687. ntohl(move->last.addr32[0]) >= ipv4_test)
  688. return 1;
  689. } else {
  690. if (memcmp(move->first.addr8, cmp->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  691. memcmp(move->last.addr8, cmp->addr8, sizeof(union netdata_ip_t)) >= 0) {
  692. return 1;
  693. }
  694. }
  695. move = move->next;
  696. }
  697. return 0;
  698. }
  699. /**
  700. * Is port inside range
  701. *
  702. * Verify if the cmp port is inside the range [first, last].
  703. * This function expects only the last parameter as big endian.
  704. *
  705. * @param cmp the value to compare
  706. *
  707. * @return It returns 1 when cmp is inside and 0 otherwise.
  708. */
  709. static int is_port_inside_range(uint16_t cmp)
  710. {
  711. // We do not have restrictions for ports.
  712. if (!network_viewer_opt.excluded_port && !network_viewer_opt.included_port)
  713. return 1;
  714. // Test if port is excluded
  715. ebpf_network_viewer_port_list_t *move = network_viewer_opt.excluded_port;
  716. cmp = htons(cmp);
  717. while (move) {
  718. if (move->cmp_first <= cmp && cmp <= move->cmp_last)
  719. return 0;
  720. move = move->next;
  721. }
  722. // Test if the port is inside allowed range
  723. move = network_viewer_opt.included_port;
  724. while (move) {
  725. if (move->cmp_first <= cmp && cmp <= move->cmp_last)
  726. return 1;
  727. move = move->next;
  728. }
  729. return 0;
  730. }
  731. /**
  732. * Hostname matches pattern
  733. *
  734. * @param cmp the value to compare
  735. *
  736. * @return It returns 1 when the value matches and zero otherwise.
  737. */
  738. int hostname_matches_pattern(char *cmp)
  739. {
  740. if (!network_viewer_opt.included_hostnames && !network_viewer_opt.excluded_hostnames)
  741. return 1;
  742. ebpf_network_viewer_hostname_list_t *move = network_viewer_opt.excluded_hostnames;
  743. while (move) {
  744. if (simple_pattern_matches(move->value_pattern, cmp))
  745. return 0;
  746. move = move->next;
  747. }
  748. move = network_viewer_opt.included_hostnames;
  749. while (move) {
  750. if (simple_pattern_matches(move->value_pattern, cmp))
  751. return 1;
  752. move = move->next;
  753. }
  754. return 0;
  755. }
  756. /**
  757. * Is socket allowed?
  758. *
  759. * Compare destination addresses and destination ports to define next steps
  760. *
  761. * @param key the socket read from kernel ring
  762. * @param family the family used to compare IPs (AF_INET and AF_INET6)
  763. *
  764. * @return It returns 1 if this socket is inside the ranges and 0 otherwise.
  765. */
  766. int is_socket_allowed(netdata_socket_idx_t *key, int family)
  767. {
  768. if (!is_port_inside_range(key->dport))
  769. return 0;
  770. return is_specific_ip_inside_range(&key->daddr, family);
  771. }
  772. /**
  773. * Compare sockets
  774. *
  775. * Compare destination address and destination port.
  776. * We do not compare source port, because it is random.
  777. * We also do not compare source address, because inbound and outbound connections are stored in separated AVL trees.
  778. *
  779. * @param a pointer to netdata_socket_plot
  780. * @param b pointer to netdata_socket_plot
  781. *
  782. * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
  783. */
  784. static int compare_sockets(void *a, void *b)
  785. {
  786. struct netdata_socket_plot *val1 = a;
  787. struct netdata_socket_plot *val2 = b;
  788. int cmp;
  789. // We do not need to compare val2 family, because data inside hash table is always from the same family
  790. if (val1->family == AF_INET) { //IPV4
  791. if (val1->flags & NETDATA_INBOUND_DIRECTION) {
  792. if (val1->index.sport == val2->index.sport)
  793. cmp = 0;
  794. else {
  795. cmp = (val1->index.sport > val2->index.sport)?1:-1;
  796. }
  797. } else {
  798. cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
  799. if (!cmp) {
  800. cmp = memcmp(&val1->index.daddr.addr32[0], &val2->index.daddr.addr32[0], sizeof(uint32_t));
  801. }
  802. }
  803. } else {
  804. if (val1->flags & NETDATA_INBOUND_DIRECTION) {
  805. if (val1->index.sport == val2->index.sport)
  806. cmp = 0;
  807. else {
  808. cmp = (val1->index.sport > val2->index.sport)?1:-1;
  809. }
  810. } else {
  811. cmp = memcmp(&val1->index.dport, &val2->index.dport, sizeof(uint16_t));
  812. if (!cmp) {
  813. cmp = memcmp(&val1->index.daddr.addr32, &val2->index.daddr.addr32, 4*sizeof(uint32_t));
  814. }
  815. }
  816. }
  817. return cmp;
  818. }
  819. /**
  820. * Build dimension name
  821. *
  822. * Fill dimension name vector with values given
  823. *
  824. * @param dimname the output vector
  825. * @param hostname the hostname for the socket.
  826. * @param service_name the service used to connect.
  827. * @param proto the protocol used in this connection
  828. * @param family is this IPV4(AF_INET) or IPV6(AF_INET6)
  829. *
  830. * @return it returns the size of the data copied on success and -1 otherwise.
  831. */
  832. static inline int build_outbound_dimension_name(char *dimname, char *hostname, char *service_name,
  833. char *proto, int family)
  834. {
  835. return snprintf(dimname, CONFIG_MAX_NAME - 7, (family == AF_INET)?"%s:%s:%s_":"%s:%s:[%s]_",
  836. service_name, proto,
  837. hostname);
  838. }
  839. /**
  840. * Fill inbound dimension name
  841. *
  842. * Mount the dimension name with the input given
  843. *
  844. * @param dimname the output vector
  845. * @param service_name the service used to connect.
  846. * @param proto the protocol used in this connection
  847. *
  848. * @return it returns the size of the data copied on success and -1 otherwise.
  849. */
  850. static inline int build_inbound_dimension_name(char *dimname, char *service_name, char *proto)
  851. {
  852. return snprintf(dimname, CONFIG_MAX_NAME - 7, "%s:%s_", service_name,
  853. proto);
  854. }
  855. /**
  856. * Fill Resolved Name
  857. *
  858. * Fill the resolved name structure with the value given.
  859. * The hostname is the largest value possible, if it is necessary to cut some value, it must be cut.
  860. *
  861. * @param ptr the output vector
  862. * @param hostname the hostname resolved or IP.
  863. * @param length the length for the hostname.
  864. * @param service_name the service name associated to the connection
  865. * @param is_outbound the is this an outbound connection
  866. */
  867. static inline void fill_resolved_name(netdata_socket_plot_t *ptr, char *hostname, size_t length,
  868. char *service_name, int is_outbound)
  869. {
  870. if (length < NETDATA_MAX_NETWORK_COMBINED_LENGTH)
  871. ptr->resolved_name = strdupz(hostname);
  872. else {
  873. length = NETDATA_MAX_NETWORK_COMBINED_LENGTH;
  874. ptr->resolved_name = mallocz( NETDATA_MAX_NETWORK_COMBINED_LENGTH + 1);
  875. memcpy(ptr->resolved_name, hostname, length);
  876. ptr->resolved_name[length] = '\0';
  877. }
  878. char dimname[CONFIG_MAX_NAME];
  879. int size;
  880. char *protocol;
  881. if (ptr->sock.protocol == IPPROTO_UDP) {
  882. protocol = "UDP";
  883. } else if (ptr->sock.protocol == IPPROTO_TCP) {
  884. protocol = "TCP";
  885. } else {
  886. protocol = "ALL";
  887. }
  888. if (is_outbound)
  889. size = build_outbound_dimension_name(dimname, hostname, service_name, protocol, ptr->family);
  890. else
  891. size = build_inbound_dimension_name(dimname,service_name, protocol);
  892. if (size > 0) {
  893. strcpy(&dimname[size], "sent");
  894. dimname[size + 4] = '\0';
  895. ptr->dimension_sent = strdupz(dimname);
  896. strcpy(&dimname[size], "recv");
  897. ptr->dimension_recv = strdupz(dimname);
  898. dimname[size - 1] = '\0';
  899. ptr->dimension_retransmit = strdupz(dimname);
  900. }
  901. }
  902. /**
  903. * Mount dimension names
  904. *
  905. * Fill the vector names after to resolve the addresses
  906. *
  907. * @param ptr a pointer to the structure where the values are stored.
  908. * @param is_outbound is a outbound ptr value?
  909. *
  910. * @return It returns 1 if the name is valid and 0 otherwise.
  911. */
  912. int fill_names(netdata_socket_plot_t *ptr, int is_outbound)
  913. {
  914. char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
  915. if (ptr->resolved)
  916. return 1;
  917. int ret;
  918. static int resolve_name = -1;
  919. static int resolve_service = -1;
  920. if (resolve_name == -1)
  921. resolve_name = network_viewer_opt.hostname_resolution_enabled;
  922. if (resolve_service == -1)
  923. resolve_service = network_viewer_opt.service_resolution_enabled;
  924. netdata_socket_idx_t *idx = &ptr->index;
  925. char *errname = { "Not resolved" };
  926. // Resolve Name
  927. if (ptr->family == AF_INET) { //IPV4
  928. struct sockaddr_in myaddr;
  929. memset(&myaddr, 0 , sizeof(myaddr));
  930. myaddr.sin_family = ptr->family;
  931. if (is_outbound) {
  932. myaddr.sin_port = idx->dport;
  933. myaddr.sin_addr.s_addr = idx->daddr.addr32[0];
  934. } else {
  935. myaddr.sin_port = idx->sport;
  936. myaddr.sin_addr.s_addr = idx->saddr.addr32[0];
  937. }
  938. ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr, sizeof(myaddr), hostname,
  939. sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
  940. if (!ret && !resolve_service) {
  941. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
  942. }
  943. if (ret) {
  944. // I cannot resolve the name, I will use the IP
  945. if (!inet_ntop(AF_INET, &myaddr.sin_addr.s_addr, hostname, NI_MAXHOST)) {
  946. strncpy(hostname, errname, 13);
  947. }
  948. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr.sin_port));
  949. ret = 1;
  950. }
  951. } else { // IPV6
  952. struct sockaddr_in6 myaddr6;
  953. memset(&myaddr6, 0 , sizeof(myaddr6));
  954. myaddr6.sin6_family = AF_INET6;
  955. if (is_outbound) {
  956. myaddr6.sin6_port = idx->dport;
  957. memcpy(myaddr6.sin6_addr.s6_addr, idx->daddr.addr8, sizeof(union netdata_ip_t));
  958. } else {
  959. myaddr6.sin6_port = idx->sport;
  960. memcpy(myaddr6.sin6_addr.s6_addr, idx->saddr.addr8, sizeof(union netdata_ip_t));
  961. }
  962. ret = (!resolve_name)?-1:getnameinfo((struct sockaddr *)&myaddr6, sizeof(myaddr6), hostname,
  963. sizeof(hostname), service_name, sizeof(service_name), NI_NAMEREQD);
  964. if (!ret && !resolve_service) {
  965. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
  966. }
  967. if (ret) {
  968. // I cannot resolve the name, I will use the IP
  969. if (!inet_ntop(AF_INET6, myaddr6.sin6_addr.s6_addr, hostname, NI_MAXHOST)) {
  970. strncpy(hostname, errname, 13);
  971. }
  972. snprintf(service_name, sizeof(service_name), "%u", ntohs(myaddr6.sin6_port));
  973. ret = 1;
  974. }
  975. }
  976. fill_resolved_name(ptr, hostname,
  977. strlen(hostname) + strlen(service_name)+ NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH,
  978. service_name, is_outbound);
  979. if (resolve_name && !ret)
  980. ret = hostname_matches_pattern(hostname);
  981. ptr->resolved++;
  982. return ret;
  983. }
  984. /**
  985. * Fill last Network Viewer Dimension
  986. *
  987. * Fill the unique dimension that is always plotted.
  988. *
  989. * @param ptr the pointer for the last dimension
  990. * @param is_outbound is this an inbound structure?
  991. */
  992. static void fill_last_nv_dimension(netdata_socket_plot_t *ptr, int is_outbound)
  993. {
  994. char hostname[NI_MAXHOST], service_name[NI_MAXSERV];
  995. char *other = { "other" };
  996. // We are also copying the NULL bytes to avoid warnings in new compilers
  997. strncpy(hostname, other, 6);
  998. strncpy(service_name, other, 6);
  999. ptr->family = AF_INET;
  1000. ptr->sock.protocol = 255;
  1001. ptr->flags = (!is_outbound)?NETDATA_INBOUND_DIRECTION:NETDATA_OUTBOUND_DIRECTION;
  1002. fill_resolved_name(ptr, hostname, 10 + NETDATA_DOTS_PROTOCOL_COMBINED_LENGTH, service_name, is_outbound);
  1003. #ifdef NETDATA_INTERNAL_CHECKS
  1004. info("Last %s dimension added: ID = %u, IP = OTHER, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
  1005. (is_outbound)?"outbound":"inbound", network_viewer_opt.max_dim - 1, ptr->resolved_name,
  1006. ptr->dimension_recv, ptr->dimension_sent, ptr->dimension_retransmit);
  1007. #endif
  1008. }
  1009. /**
  1010. * Update Socket Data
  1011. *
  1012. * Update the socket information with last collected data
  1013. *
  1014. * @param sock
  1015. * @param lvalues
  1016. */
  1017. static inline void update_socket_data(netdata_socket_t *sock, netdata_socket_t *lvalues)
  1018. {
  1019. sock->recv_packets += lvalues->recv_packets;
  1020. sock->sent_packets += lvalues->sent_packets;
  1021. sock->recv_bytes += lvalues->recv_bytes;
  1022. sock->sent_bytes += lvalues->sent_bytes;
  1023. sock->retransmit += lvalues->retransmit;
  1024. if (lvalues->ct > sock->ct)
  1025. sock->ct = lvalues->ct;
  1026. }
  1027. /**
  1028. * Store socket inside avl
  1029. *
  1030. * Store the socket values inside the avl tree.
  1031. *
  1032. * @param out the structure with information used to plot charts.
  1033. * @param lvalues Values read from socket ring.
  1034. * @param lindex the index information, the real socket.
  1035. * @param family the family associated to the socket
  1036. * @param flags the connection flags
  1037. */
  1038. static void store_socket_inside_avl(netdata_vector_plot_t *out, netdata_socket_t *lvalues,
  1039. netdata_socket_idx_t *lindex, int family, uint32_t flags)
  1040. {
  1041. netdata_socket_plot_t test, *ret ;
  1042. memcpy(&test.index, lindex, sizeof(netdata_socket_idx_t));
  1043. test.flags = flags;
  1044. ret = (netdata_socket_plot_t *) avl_search_lock(&out->tree, (avl_t *)&test);
  1045. if (ret) {
  1046. if (lvalues->ct > ret->plot.last_time) {
  1047. update_socket_data(&ret->sock, lvalues);
  1048. }
  1049. } else {
  1050. uint32_t curr = out->next;
  1051. uint32_t last = out->last;
  1052. netdata_socket_plot_t *w = &out->plot[curr];
  1053. int resolved;
  1054. if (curr == last) {
  1055. if (lvalues->ct > w->plot.last_time) {
  1056. update_socket_data(&w->sock, lvalues);
  1057. }
  1058. return;
  1059. } else {
  1060. memcpy(&w->sock, lvalues, sizeof(netdata_socket_t));
  1061. memcpy(&w->index, lindex, sizeof(netdata_socket_idx_t));
  1062. w->family = family;
  1063. resolved = fill_names(w, out != (netdata_vector_plot_t *)&inbound_vectors);
  1064. }
  1065. if (!resolved) {
  1066. freez(w->resolved_name);
  1067. freez(w->dimension_sent);
  1068. freez(w->dimension_recv);
  1069. freez(w->dimension_retransmit);
  1070. memset(w, 0, sizeof(netdata_socket_plot_t));
  1071. return;
  1072. }
  1073. w->flags = flags;
  1074. netdata_socket_plot_t *check ;
  1075. check = (netdata_socket_plot_t *) avl_insert_lock(&out->tree, (avl_t *)w);
  1076. if (check != w)
  1077. error("Internal error, cannot insert the AVL tree.");
  1078. #ifdef NETDATA_INTERNAL_CHECKS
  1079. char iptext[INET6_ADDRSTRLEN];
  1080. if (inet_ntop(family, &w->index.daddr.addr8, iptext, sizeof(iptext)))
  1081. info("New %s dimension added: ID = %u, IP = %s, NAME = %s, DIM1 = %s, DIM2 = %s, DIM3 = %s",
  1082. (out == &inbound_vectors)?"inbound":"outbound", curr, iptext, w->resolved_name,
  1083. w->dimension_recv, w->dimension_sent, w->dimension_retransmit);
  1084. #endif
  1085. curr++;
  1086. if (curr > last)
  1087. curr = last;
  1088. out->next = curr;
  1089. }
  1090. }
  1091. /**
  1092. * Compare Vector to store
  1093. *
  1094. * Compare input values with local address to select table to store.
  1095. *
  1096. * @param direction store inbound and outbound direction.
  1097. * @param cmp index read from hash table.
  1098. * @param proto the protocol read.
  1099. *
  1100. * @return It returns the structure with address to compare.
  1101. */
  1102. netdata_vector_plot_t * select_vector_to_store(uint32_t *direction, netdata_socket_idx_t *cmp, uint8_t proto)
  1103. {
  1104. if (!listen_ports) {
  1105. *direction = NETDATA_OUTBOUND_DIRECTION;
  1106. return &outbound_vectors;
  1107. }
  1108. ebpf_network_viewer_port_list_t *move_ports = listen_ports;
  1109. while (move_ports) {
  1110. if (move_ports->protocol == proto && move_ports->first == cmp->sport) {
  1111. *direction = NETDATA_INBOUND_DIRECTION;
  1112. return &inbound_vectors;
  1113. }
  1114. move_ports = move_ports->next;
  1115. }
  1116. *direction = NETDATA_OUTBOUND_DIRECTION;
  1117. return &outbound_vectors;
  1118. }
  1119. /**
  1120. * Hash accumulator
  1121. *
  1122. * @param values the values used to calculate the data.
  1123. * @param key the key to store data.
  1124. * @param removesock check if this socket must be removed .
  1125. * @param family the connection family
  1126. * @param end the values size.
  1127. */
  1128. static void hash_accumulator(netdata_socket_t *values, netdata_socket_idx_t *key, int *removesock, int family, int end)
  1129. {
  1130. uint64_t bsent = 0, brecv = 0, psent = 0, precv = 0;
  1131. uint16_t retransmit = 0;
  1132. int i;
  1133. uint8_t protocol = values[0].protocol;
  1134. uint64_t ct = values[0].ct;
  1135. for (i = 1; i < end; i++) {
  1136. netdata_socket_t *w = &values[i];
  1137. precv += w->recv_packets;
  1138. psent += w->sent_packets;
  1139. brecv += w->recv_bytes;
  1140. bsent += w->sent_bytes;
  1141. retransmit += w->retransmit;
  1142. if (!protocol)
  1143. protocol = w->protocol;
  1144. if (w->ct > ct)
  1145. ct = w->ct;
  1146. *removesock += (int)w->removeme;
  1147. }
  1148. values[0].recv_packets += precv;
  1149. values[0].sent_packets += psent;
  1150. values[0].recv_bytes += brecv;
  1151. values[0].sent_bytes += bsent;
  1152. values[0].retransmit += retransmit;
  1153. values[0].removeme += (uint8_t)*removesock;
  1154. values[0].protocol = (!protocol)?IPPROTO_TCP:protocol;
  1155. values[0].ct = ct;
  1156. if (is_socket_allowed(key, family)) {
  1157. uint32_t dir;
  1158. netdata_vector_plot_t *table = select_vector_to_store(&dir, key, protocol);
  1159. store_socket_inside_avl(table, &values[0], key, family, dir);
  1160. }
  1161. }
  1162. /**
  1163. * Read socket hash table
  1164. *
  1165. * Read data from hash tables created on kernel ring.
  1166. *
  1167. * @param fd the hash table with data.
  1168. * @param family the family associated to the hash table
  1169. *
  1170. * @return it returns 0 on success and -1 otherwise.
  1171. */
  1172. static void read_socket_hash_table(int fd, int family, int network_connection)
  1173. {
  1174. if (wait_to_plot)
  1175. return;
  1176. netdata_socket_idx_t key = {};
  1177. netdata_socket_idx_t next_key = {};
  1178. netdata_socket_idx_t removeme;
  1179. int removesock = 0;
  1180. netdata_socket_t *values = socket_values;
  1181. size_t length = ebpf_nprocs*sizeof(netdata_socket_t);
  1182. int test, end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
  1183. while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  1184. // We need to reset the values when we are working on kernel 4.15 or newer, because kernel does not create
  1185. // values for specific processor unless it is used to store data. As result of this behavior one the next socket
  1186. // can have values from the previous one.
  1187. memset(values, 0, length);
  1188. test = bpf_map_lookup_elem(fd, &key, values);
  1189. if (test < 0) {
  1190. key = next_key;
  1191. continue;
  1192. }
  1193. if (removesock)
  1194. bpf_map_delete_elem(fd, &removeme);
  1195. if (network_connection) {
  1196. removesock = 0;
  1197. hash_accumulator(values, &key, &removesock, family, end);
  1198. }
  1199. if (removesock)
  1200. removeme = key;
  1201. key = next_key;
  1202. }
  1203. if (removesock)
  1204. bpf_map_delete_elem(fd, &removeme);
  1205. test = bpf_map_lookup_elem(fd, &next_key, values);
  1206. if (test < 0) {
  1207. return;
  1208. }
  1209. if (network_connection) {
  1210. removesock = 0;
  1211. hash_accumulator(values, &next_key, &removesock, family, end);
  1212. }
  1213. if (removesock)
  1214. bpf_map_delete_elem(fd, &next_key);
  1215. }
  1216. /**
  1217. * Update listen table
  1218. *
  1219. * Update link list when it is necessary.
  1220. *
  1221. * @param value the ports we are listen to.
  1222. * @param proto the protocol used with port connection.
  1223. */
  1224. void update_listen_table(uint16_t value, uint8_t proto)
  1225. {
  1226. ebpf_network_viewer_port_list_t *w;
  1227. if (likely(listen_ports)) {
  1228. ebpf_network_viewer_port_list_t *move = listen_ports, *store = listen_ports;
  1229. while (move) {
  1230. if (move->protocol == proto && move->first == value)
  1231. return;
  1232. store = move;
  1233. move = move->next;
  1234. }
  1235. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1236. w->first = value;
  1237. w->protocol = proto;
  1238. store->next = w;
  1239. } else {
  1240. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1241. w->first = value;
  1242. w->protocol = proto;
  1243. listen_ports = w;
  1244. }
  1245. #ifdef NETDATA_INTERNAL_CHECKS
  1246. info("The network viewer is monitoring inbound connections for port %u", ntohs(value));
  1247. #endif
  1248. }
  1249. /**
  1250. * Read listen table
  1251. *
  1252. * Read the table with all ports that we are listen on host.
  1253. */
  1254. static void read_listen_table()
  1255. {
  1256. uint16_t key = 0;
  1257. uint16_t next_key = 0;
  1258. int fd = map_fd[NETDATA_SOCKET_LISTEN_TABLE];
  1259. uint8_t value;
  1260. while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
  1261. int test = bpf_map_lookup_elem(fd, &key, &value);
  1262. if (test < 0) {
  1263. key = next_key;
  1264. continue;
  1265. }
  1266. // The correct protocol must come from kernel
  1267. update_listen_table(htons(key), (key == 53)?IPPROTO_UDP:IPPROTO_TCP);
  1268. key = next_key;
  1269. }
  1270. if (next_key) {
  1271. // The correct protocol must come from kernel
  1272. update_listen_table(htons(next_key), (key == 53)?IPPROTO_UDP:IPPROTO_TCP);
  1273. }
  1274. }
  1275. /**
  1276. * Socket read hash
  1277. *
  1278. * This is the thread callback.
  1279. * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
  1280. *
  1281. * @param ptr It is a NULL value for this thread.
  1282. *
  1283. * @return It always returns NULL.
  1284. */
  1285. void *ebpf_socket_read_hash(void *ptr)
  1286. {
  1287. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1288. read_thread_closed = 0;
  1289. heartbeat_t hb;
  1290. heartbeat_init(&hb);
  1291. usec_t step = NETDATA_SOCKET_READ_SLEEP_MS * em->update_time;
  1292. int fd_ipv4 = map_fd[NETDATA_SOCKET_IPV4_HASH_TABLE];
  1293. int fd_ipv6 = map_fd[NETDATA_SOCKET_IPV6_HASH_TABLE];
  1294. int network_connection = em->optional;
  1295. while (!close_ebpf_plugin) {
  1296. usec_t dt = heartbeat_next(&hb, step);
  1297. (void)dt;
  1298. pthread_mutex_lock(&nv_mutex);
  1299. read_listen_table();
  1300. read_socket_hash_table(fd_ipv4, AF_INET, network_connection);
  1301. read_socket_hash_table(fd_ipv6, AF_INET6, network_connection);
  1302. wait_to_plot = 1;
  1303. pthread_mutex_unlock(&nv_mutex);
  1304. }
  1305. read_thread_closed = 1;
  1306. return NULL;
  1307. }
  1308. /**
  1309. * Read the hash table and store data to allocated vectors.
  1310. */
  1311. static void read_hash_global_tables()
  1312. {
  1313. uint64_t idx;
  1314. netdata_idx_t res[NETDATA_SOCKET_COUNTER];
  1315. netdata_idx_t *val = socket_hash_values;
  1316. int fd = map_fd[NETDATA_SOCKET_GLOBAL_HASH_TABLE];
  1317. for (idx = 0; idx < NETDATA_SOCKET_COUNTER; idx++) {
  1318. if (!bpf_map_lookup_elem(fd, &idx, val)) {
  1319. uint64_t total = 0;
  1320. int i;
  1321. int end = ebpf_nprocs;
  1322. for (i = 0; i < end; i++)
  1323. total += val[i];
  1324. res[idx] = total;
  1325. } else {
  1326. res[idx] = 0;
  1327. }
  1328. }
  1329. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].call = res[NETDATA_KEY_CALLS_TCP_SENDMSG];
  1330. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].call = res[NETDATA_KEY_CALLS_TCP_CLEANUP_RBUF];
  1331. socket_aggregated_data[NETDATA_IDX_TCP_CLOSE].call = res[NETDATA_KEY_CALLS_TCP_CLOSE];
  1332. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].call = res[NETDATA_KEY_CALLS_UDP_RECVMSG];
  1333. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].call = res[NETDATA_KEY_CALLS_UDP_SENDMSG];
  1334. socket_aggregated_data[NETDATA_IDX_TCP_RETRANSMIT].call = res[NETDATA_KEY_TCP_RETRANSMIT];
  1335. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].ecall = res[NETDATA_KEY_ERROR_TCP_SENDMSG];
  1336. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].ecall = res[NETDATA_KEY_ERROR_TCP_CLEANUP_RBUF];
  1337. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].ecall = res[NETDATA_KEY_ERROR_UDP_RECVMSG];
  1338. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].ecall = res[NETDATA_KEY_ERROR_UDP_SENDMSG];
  1339. socket_aggregated_data[NETDATA_IDX_TCP_SENDMSG].bytes = res[NETDATA_KEY_BYTES_TCP_SENDMSG];
  1340. socket_aggregated_data[NETDATA_IDX_TCP_CLEANUP_RBUF].bytes = res[NETDATA_KEY_BYTES_TCP_CLEANUP_RBUF];
  1341. socket_aggregated_data[NETDATA_IDX_UDP_RECVBUF].bytes = res[NETDATA_KEY_BYTES_UDP_RECVMSG];
  1342. socket_aggregated_data[NETDATA_IDX_UDP_SENDMSG].bytes = res[NETDATA_KEY_BYTES_UDP_SENDMSG];
  1343. }
  1344. /**
  1345. * Fill publish apps when necessary.
  1346. *
  1347. * @param current_pid the PID that I am updating
  1348. * @param eb the structure with data read from memory.
  1349. */
  1350. void ebpf_socket_fill_publish_apps(uint32_t current_pid, ebpf_bandwidth_t *eb)
  1351. {
  1352. ebpf_socket_publish_apps_t *curr = socket_bandwidth_curr[current_pid];
  1353. if (!curr) {
  1354. curr = callocz(1, sizeof(ebpf_socket_publish_apps_t));
  1355. socket_bandwidth_curr[current_pid] = curr;
  1356. }
  1357. curr->bytes_sent = eb->bytes_sent;
  1358. curr->bytes_received = eb->bytes_received;
  1359. curr->call_tcp_sent = eb->call_tcp_sent;
  1360. curr->call_tcp_received = eb->call_tcp_received;
  1361. curr->retransmit = eb->retransmit;
  1362. curr->call_udp_sent = eb->call_udp_sent;
  1363. curr->call_udp_received = eb->call_udp_received;
  1364. }
  1365. /**
  1366. * Bandwidth accumulator.
  1367. *
  1368. * @param out the vector with the values to sum
  1369. */
  1370. void ebpf_socket_bandwidth_accumulator(ebpf_bandwidth_t *out)
  1371. {
  1372. int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
  1373. ebpf_bandwidth_t *total = &out[0];
  1374. for (i = 1; i < end; i++) {
  1375. ebpf_bandwidth_t *move = &out[i];
  1376. total->bytes_sent += move->bytes_sent;
  1377. total->bytes_received += move->bytes_received;
  1378. total->call_tcp_sent += move->call_tcp_sent;
  1379. total->call_tcp_received += move->call_tcp_received;
  1380. total->retransmit += move->retransmit;
  1381. total->call_udp_sent += move->call_udp_sent;
  1382. total->call_udp_received += move->call_udp_received;
  1383. }
  1384. }
  1385. /**
  1386. * Update the apps data reading information from the hash table
  1387. */
  1388. static void ebpf_socket_update_apps_data()
  1389. {
  1390. int fd = map_fd[NETDATA_SOCKET_APPS_HASH_TABLE];
  1391. ebpf_bandwidth_t *eb = bandwidth_vector;
  1392. uint32_t key;
  1393. struct pid_stat *pids = root_of_pids;
  1394. while (pids) {
  1395. key = pids->pid;
  1396. if (bpf_map_lookup_elem(fd, &key, eb)) {
  1397. pids = pids->next;
  1398. continue;
  1399. }
  1400. ebpf_socket_bandwidth_accumulator(eb);
  1401. ebpf_socket_fill_publish_apps(key, eb);
  1402. pids = pids->next;
  1403. }
  1404. }
  1405. /*****************************************************************
  1406. *
  1407. * FUNCTIONS WITH THE MAIN LOOP
  1408. *
  1409. *****************************************************************/
  1410. struct netdata_static_thread socket_threads = {"EBPF SOCKET READ",
  1411. NULL, NULL, 1, NULL,
  1412. NULL, ebpf_socket_read_hash };
  1413. /**
  1414. * Main loop for this collector.
  1415. *
  1416. * @param step the number of microseconds used with heart beat
  1417. * @param em the structure with thread information
  1418. */
  1419. static void socket_collector(usec_t step, ebpf_module_t *em)
  1420. {
  1421. UNUSED(em);
  1422. UNUSED(step);
  1423. heartbeat_t hb;
  1424. heartbeat_init(&hb);
  1425. socket_threads.thread = mallocz(sizeof(netdata_thread_t));
  1426. netdata_thread_create(socket_threads.thread, socket_threads.name,
  1427. NETDATA_THREAD_OPTION_JOINABLE, ebpf_socket_read_hash, em);
  1428. int socket_apps_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].apps_charts;
  1429. int socket_global_enabled = ebpf_modules[EBPF_MODULE_SOCKET_IDX].global_charts;
  1430. int network_connection = em->optional;
  1431. while (!close_ebpf_plugin) {
  1432. pthread_mutex_lock(&collect_data_mutex);
  1433. pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
  1434. if (socket_global_enabled)
  1435. read_hash_global_tables();
  1436. if (socket_apps_enabled)
  1437. ebpf_socket_update_apps_data();
  1438. calculate_nv_plot();
  1439. pthread_mutex_lock(&lock);
  1440. if (socket_global_enabled)
  1441. ebpf_socket_send_data(em);
  1442. if (socket_apps_enabled)
  1443. ebpf_socket_send_apps_data(em, apps_groups_root_target);
  1444. fflush(stdout);
  1445. if (network_connection) {
  1446. // We are calling fflush many times, because when we have a lot of dimensions
  1447. // we began to have not expected outputs and Netdata closed the plugin.
  1448. pthread_mutex_lock(&nv_mutex);
  1449. ebpf_socket_create_nv_charts(&inbound_vectors);
  1450. fflush(stdout);
  1451. ebpf_socket_send_nv_data(&inbound_vectors);
  1452. ebpf_socket_create_nv_charts(&outbound_vectors);
  1453. fflush(stdout);
  1454. ebpf_socket_send_nv_data(&outbound_vectors);
  1455. wait_to_plot = 0;
  1456. pthread_mutex_unlock(&nv_mutex);
  1457. }
  1458. pthread_mutex_unlock(&collect_data_mutex);
  1459. pthread_mutex_unlock(&lock);
  1460. }
  1461. }
  1462. /*****************************************************************
  1463. *
  1464. * FUNCTIONS TO CLOSE THE THREAD
  1465. *
  1466. *****************************************************************/
  1467. /**
  1468. * Clean internal socket plot
  1469. *
  1470. * Clean all structures allocated with strdupz.
  1471. *
  1472. * @param ptr the pointer with addresses to clean.
  1473. */
  1474. static inline void clean_internal_socket_plot(netdata_socket_plot_t *ptr)
  1475. {
  1476. freez(ptr->dimension_recv);
  1477. freez(ptr->dimension_sent);
  1478. freez(ptr->resolved_name);
  1479. freez(ptr->dimension_retransmit);
  1480. }
  1481. /**
  1482. * Clean socket plot
  1483. *
  1484. * Clean the allocated data for inbound and outbound vectors.
  1485. */
  1486. static void clean_allocated_socket_plot()
  1487. {
  1488. uint32_t i;
  1489. uint32_t end = inbound_vectors.last;
  1490. netdata_socket_plot_t *plot = inbound_vectors.plot;
  1491. for (i = 0; i < end; i++) {
  1492. clean_internal_socket_plot(&plot[i]);
  1493. }
  1494. clean_internal_socket_plot(&plot[inbound_vectors.last]);
  1495. end = outbound_vectors.last;
  1496. plot = outbound_vectors.plot;
  1497. for (i = 0; i < end; i++) {
  1498. clean_internal_socket_plot(&plot[i]);
  1499. }
  1500. clean_internal_socket_plot(&plot[outbound_vectors.last]);
  1501. }
  1502. /**
  1503. * Clean network ports allocated during initialization.
  1504. *
  1505. * @param ptr a pointer to the link list.
  1506. */
  1507. static void clean_network_ports(ebpf_network_viewer_port_list_t *ptr)
  1508. {
  1509. if (unlikely(!ptr))
  1510. return;
  1511. while (ptr) {
  1512. ebpf_network_viewer_port_list_t *next = ptr->next;
  1513. freez(ptr->value);
  1514. freez(ptr);
  1515. ptr = next;
  1516. }
  1517. }
  1518. /**
  1519. * Clean service names
  1520. *
  1521. * Clean the allocated link list that stores names.
  1522. *
  1523. * @param names the link list.
  1524. */
  1525. static void clean_service_names(ebpf_network_viewer_dim_name_t *names)
  1526. {
  1527. if (unlikely(!names))
  1528. return;
  1529. while (names) {
  1530. ebpf_network_viewer_dim_name_t *next = names->next;
  1531. freez(names->name);
  1532. freez(names);
  1533. names = next;
  1534. }
  1535. }
  1536. /**
  1537. * Clean hostnames
  1538. *
  1539. * @param hostnames the hostnames to clean
  1540. */
  1541. static void clean_hostnames(ebpf_network_viewer_hostname_list_t *hostnames)
  1542. {
  1543. if (unlikely(!hostnames))
  1544. return;
  1545. while (hostnames) {
  1546. ebpf_network_viewer_hostname_list_t *next = hostnames->next;
  1547. freez(hostnames->value);
  1548. simple_pattern_free(hostnames->value_pattern);
  1549. freez(hostnames);
  1550. hostnames = next;
  1551. }
  1552. }
  1553. void clean_socket_apps_structures() {
  1554. struct pid_stat *pids = root_of_pids;
  1555. while (pids) {
  1556. freez(socket_bandwidth_curr[pids->pid]);
  1557. pids = pids->next;
  1558. }
  1559. }
  1560. /**
  1561. * Cleanup publish syscall
  1562. *
  1563. * @param nps list of structures to clean
  1564. */
  1565. void ebpf_cleanup_publish_syscall(netdata_publish_syscall_t *nps)
  1566. {
  1567. while (nps) {
  1568. freez(nps->algorithm);
  1569. nps = nps->next;
  1570. }
  1571. }
  1572. /**
  1573. * Clean port Structure
  1574. *
  1575. * Clean the allocated list.
  1576. *
  1577. * @param clean the list that will be cleaned
  1578. */
  1579. void clean_port_structure(ebpf_network_viewer_port_list_t **clean)
  1580. {
  1581. ebpf_network_viewer_port_list_t *move = *clean;
  1582. while (move) {
  1583. ebpf_network_viewer_port_list_t *next = move->next;
  1584. freez(move->value);
  1585. freez(move);
  1586. move = next;
  1587. }
  1588. *clean = NULL;
  1589. }
  1590. /**
  1591. * Clean IP structure
  1592. *
  1593. * Clean the allocated list.
  1594. *
  1595. * @param clean the list that will be cleaned
  1596. */
  1597. static void clean_ip_structure(ebpf_network_viewer_ip_list_t **clean)
  1598. {
  1599. ebpf_network_viewer_ip_list_t *move = *clean;
  1600. while (move) {
  1601. ebpf_network_viewer_ip_list_t *next = move->next;
  1602. freez(move->value);
  1603. freez(move);
  1604. move = next;
  1605. }
  1606. *clean = NULL;
  1607. }
  1608. /**
  1609. * Clean up the main thread.
  1610. *
  1611. * @param ptr thread data.
  1612. */
  1613. static void ebpf_socket_cleanup(void *ptr)
  1614. {
  1615. ebpf_module_t *em = (ebpf_module_t *)ptr;
  1616. if (!em->enabled)
  1617. return;
  1618. heartbeat_t hb;
  1619. heartbeat_init(&hb);
  1620. uint32_t tick = 2*USEC_PER_MS;
  1621. while (!read_thread_closed) {
  1622. usec_t dt = heartbeat_next(&hb, tick);
  1623. UNUSED(dt);
  1624. }
  1625. ebpf_cleanup_publish_syscall(socket_publish_aggregated);
  1626. freez(socket_hash_values);
  1627. freez(bandwidth_vector);
  1628. freez(socket_values);
  1629. clean_allocated_socket_plot();
  1630. freez(inbound_vectors.plot);
  1631. freez(outbound_vectors.plot);
  1632. clean_port_structure(&listen_ports);
  1633. ebpf_modules[EBPF_MODULE_SOCKET_IDX].enabled = 0;
  1634. clean_network_ports(network_viewer_opt.included_port);
  1635. clean_network_ports(network_viewer_opt.excluded_port);
  1636. clean_service_names(network_viewer_opt.names);
  1637. clean_hostnames(network_viewer_opt.included_hostnames);
  1638. clean_hostnames(network_viewer_opt.excluded_hostnames);
  1639. pthread_mutex_destroy(&nv_mutex);
  1640. freez(socket_data.map_fd);
  1641. freez(socket_threads.thread);
  1642. if (probe_links) {
  1643. struct bpf_program *prog;
  1644. size_t i = 0 ;
  1645. bpf_object__for_each_program(prog, objects) {
  1646. bpf_link__destroy(probe_links[i]);
  1647. i++;
  1648. }
  1649. bpf_object__close(objects);
  1650. }
  1651. finalized_threads = 1;
  1652. }
  1653. /*****************************************************************
  1654. *
  1655. * FUNCTIONS TO START THREAD
  1656. *
  1657. *****************************************************************/
  1658. /**
  1659. * Allocate vectors used with this thread.
  1660. * We are not testing the return, because callocz does this and shutdown the software
  1661. * case it was not possible to allocate.
  1662. *
  1663. * @param length is the length for the vectors used inside the collector.
  1664. */
  1665. static void ebpf_socket_allocate_global_vectors(size_t length)
  1666. {
  1667. memset(socket_aggregated_data, 0 ,length * sizeof(netdata_syscall_stat_t));
  1668. memset(socket_publish_aggregated, 0 ,length * sizeof(netdata_publish_syscall_t));
  1669. socket_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
  1670. socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
  1671. bandwidth_vector = callocz((size_t)ebpf_nprocs, sizeof(ebpf_bandwidth_t));
  1672. socket_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_socket_t));
  1673. inbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
  1674. outbound_vectors.plot = callocz(network_viewer_opt.max_dim, sizeof(netdata_socket_plot_t));
  1675. }
  1676. /**
  1677. * Set local function pointers, this function will never be compiled with static libraries
  1678. */
  1679. static void set_local_pointers()
  1680. {
  1681. map_fd = socket_data.map_fd;
  1682. }
  1683. /**
  1684. * Initialize Inbound and Outbound
  1685. *
  1686. * Initialize the common outbound and inbound sockets.
  1687. */
  1688. static void initialize_inbound_outbound()
  1689. {
  1690. inbound_vectors.last = network_viewer_opt.max_dim - 1;
  1691. outbound_vectors.last = inbound_vectors.last;
  1692. fill_last_nv_dimension(&inbound_vectors.plot[inbound_vectors.last], 0);
  1693. fill_last_nv_dimension(&outbound_vectors.plot[outbound_vectors.last], 1);
  1694. }
  1695. /*****************************************************************
  1696. *
  1697. * EBPF SOCKET THREAD
  1698. *
  1699. *****************************************************************/
  1700. /**
  1701. * Fill Port list
  1702. *
  1703. * @param out a pointer to the link list.
  1704. * @param in the structure that will be linked.
  1705. */
  1706. static inline void fill_port_list(ebpf_network_viewer_port_list_t **out, ebpf_network_viewer_port_list_t *in)
  1707. {
  1708. if (likely(*out)) {
  1709. ebpf_network_viewer_port_list_t *move = *out, *store = *out;
  1710. uint16_t first = ntohs(in->first);
  1711. uint16_t last = ntohs(in->last);
  1712. while (move) {
  1713. uint16_t cmp_first = ntohs(move->first);
  1714. uint16_t cmp_last = ntohs(move->last);
  1715. if (cmp_first <= first && first <= cmp_last &&
  1716. cmp_first <= last && last <= cmp_last ) {
  1717. info("The range/value (%u, %u) is inside the range/value (%u, %u) already inserted, it will be ignored.",
  1718. first, last, cmp_first, cmp_last);
  1719. freez(in->value);
  1720. freez(in);
  1721. return;
  1722. } else if (first <= cmp_first && cmp_first <= last &&
  1723. first <= cmp_last && cmp_last <= last) {
  1724. info("The range (%u, %u) is bigger than previous range (%u, %u) already inserted, the previous will be ignored.",
  1725. first, last, cmp_first, cmp_last);
  1726. freez(move->value);
  1727. move->value = in->value;
  1728. move->first = in->first;
  1729. move->last = in->last;
  1730. freez(in);
  1731. return;
  1732. }
  1733. store = move;
  1734. move = move->next;
  1735. }
  1736. store->next = in;
  1737. } else {
  1738. *out = in;
  1739. }
  1740. #ifdef NETDATA_INTERNAL_CHECKS
  1741. info("Adding values %s( %u, %u) to %s port list used on network viewer",
  1742. in->value, ntohs(in->first), ntohs(in->last),
  1743. (*out == network_viewer_opt.included_port)?"included":"excluded");
  1744. #endif
  1745. }
  1746. /**
  1747. * Parse Service List
  1748. *
  1749. * @param out a pointer to store the link list
  1750. * @param service the service used to create the structure that will be linked.
  1751. */
  1752. static void parse_service_list(void **out, char *service)
  1753. {
  1754. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  1755. struct servent *serv = getservbyname((const char *)service, "tcp");
  1756. if (!serv)
  1757. serv = getservbyname((const char *)service, "udp");
  1758. if (!serv) {
  1759. info("Cannot resolv the service '%s' with protocols TCP and UDP, it will be ignored", service);
  1760. return;
  1761. }
  1762. ebpf_network_viewer_port_list_t *w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  1763. w->value = strdupz(service);
  1764. w->hash = simple_hash(service);
  1765. w->first = w->last = (uint16_t)serv->s_port;
  1766. fill_port_list(list, w);
  1767. }
  1768. /**
  1769. * Netmask
  1770. *
  1771. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1772. *
  1773. * @param prefix create the netmask based in the CIDR value.
  1774. *
  1775. * @return
  1776. */
  1777. static inline in_addr_t netmask(int prefix) {
  1778. if (prefix == 0)
  1779. return (~((in_addr_t) - 1));
  1780. else
  1781. return (in_addr_t)(~((1 << (32 - prefix)) - 1));
  1782. }
  1783. /**
  1784. * Broadcast
  1785. *
  1786. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1787. *
  1788. * @param addr is the ip address
  1789. * @param prefix is the CIDR value.
  1790. *
  1791. * @return It returns the last address of the range
  1792. */
  1793. static inline in_addr_t broadcast(in_addr_t addr, int prefix)
  1794. {
  1795. return (addr | ~netmask(prefix));
  1796. }
  1797. /**
  1798. * Network
  1799. *
  1800. * Copied from iprange (https://github.com/firehol/iprange/blob/master/iprange.h)
  1801. *
  1802. * @param addr is the ip address
  1803. * @param prefix is the CIDR value.
  1804. *
  1805. * @return It returns the first address of the range.
  1806. */
  1807. static inline in_addr_t ipv4_network(in_addr_t addr, int prefix)
  1808. {
  1809. return (addr & netmask(prefix));
  1810. }
  1811. /**
  1812. * IP to network long
  1813. *
  1814. * @param dst the vector to store the result
  1815. * @param ip the source ip given by our users.
  1816. * @param domain the ip domain (IPV4 or IPV6)
  1817. * @param source the original string
  1818. *
  1819. * @return it returns 0 on success and -1 otherwise.
  1820. */
  1821. static inline int ip2nl(uint8_t *dst, char *ip, int domain, char *source)
  1822. {
  1823. if (inet_pton(domain, ip, dst) <= 0) {
  1824. error("The address specified (%s) is invalid ", source);
  1825. return -1;
  1826. }
  1827. return 0;
  1828. }
  1829. /**
  1830. * Get IPV6 Last Address
  1831. *
  1832. * @param out the address to store the last address.
  1833. * @param in the address used to do the math.
  1834. * @param prefix number of bits used to calculate the address
  1835. */
  1836. static void get_ipv6_last_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  1837. {
  1838. uint64_t mask,tmp;
  1839. uint64_t ret[2];
  1840. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  1841. if (prefix == 128) {
  1842. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  1843. return;
  1844. } else if (!prefix) {
  1845. ret[0] = ret[1] = 0xFFFFFFFFFFFFFFFF;
  1846. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1847. return;
  1848. } else if (prefix <= 64) {
  1849. ret[1] = 0xFFFFFFFFFFFFFFFFULL;
  1850. tmp = be64toh(ret[0]);
  1851. if (prefix > 0) {
  1852. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  1853. tmp |= ~mask;
  1854. }
  1855. ret[0] = htobe64(tmp);
  1856. } else {
  1857. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  1858. tmp = be64toh(ret[1]);
  1859. tmp |= ~mask;
  1860. ret[1] = htobe64(tmp);
  1861. }
  1862. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1863. }
  1864. /**
  1865. * Calculate ipv6 first address
  1866. *
  1867. * @param out the address to store the first address.
  1868. * @param in the address used to do the math.
  1869. * @param prefix number of bits used to calculate the address
  1870. */
  1871. static void get_ipv6_first_addr(union netdata_ip_t *out, union netdata_ip_t *in, uint64_t prefix)
  1872. {
  1873. uint64_t mask,tmp;
  1874. uint64_t ret[2];
  1875. memcpy(ret, in->addr32, sizeof(union netdata_ip_t));
  1876. if (prefix == 128) {
  1877. memcpy(out->addr32, in->addr32, sizeof(union netdata_ip_t));
  1878. return;
  1879. } else if (!prefix) {
  1880. ret[0] = ret[1] = 0;
  1881. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1882. return;
  1883. } else if (prefix <= 64) {
  1884. ret[1] = 0ULL;
  1885. tmp = be64toh(ret[0]);
  1886. if (prefix > 0) {
  1887. mask = 0xFFFFFFFFFFFFFFFFULL << (64 - prefix);
  1888. tmp &= mask;
  1889. }
  1890. ret[0] = htobe64(tmp);
  1891. } else {
  1892. mask = 0xFFFFFFFFFFFFFFFFULL << (128 - prefix);
  1893. tmp = be64toh(ret[1]);
  1894. tmp &= mask;
  1895. ret[1] = htobe64(tmp);
  1896. }
  1897. memcpy(out->addr32, ret, sizeof(union netdata_ip_t));
  1898. }
  1899. /**
  1900. * Is ip inside the range
  1901. *
  1902. * Check if the ip is inside a IP range
  1903. *
  1904. * @param rfirst the first ip address of the range
  1905. * @param rlast the last ip address of the range
  1906. * @param cmpfirst the first ip to compare
  1907. * @param cmplast the last ip to compare
  1908. * @param family the IP family
  1909. *
  1910. * @return It returns 1 if the IP is inside the range and 0 otherwise
  1911. */
  1912. static int is_ip_inside_range(union netdata_ip_t *rfirst, union netdata_ip_t *rlast,
  1913. union netdata_ip_t *cmpfirst, union netdata_ip_t *cmplast, int family)
  1914. {
  1915. if (family == AF_INET) {
  1916. if (ntohl(rfirst->addr32[0]) <= ntohl(cmpfirst->addr32[0]) &&
  1917. ntohl(rlast->addr32[0]) >= ntohl(cmplast->addr32[0]))
  1918. return 1;
  1919. } else {
  1920. if (memcmp(rfirst->addr8, cmpfirst->addr8, sizeof(union netdata_ip_t)) <= 0 &&
  1921. memcmp(rlast->addr8, cmplast->addr8, sizeof(union netdata_ip_t)) >= 0) {
  1922. return 1;
  1923. }
  1924. }
  1925. return 0;
  1926. }
  1927. /**
  1928. * Fill IP list
  1929. *
  1930. * @param out a pointer to the link list.
  1931. * @param in the structure that will be linked.
  1932. */
  1933. void fill_ip_list(ebpf_network_viewer_ip_list_t **out, ebpf_network_viewer_ip_list_t *in, char *table)
  1934. {
  1935. #ifndef NETDATA_INTERNAL_CHECKS
  1936. UNUSED(table);
  1937. #endif
  1938. if (likely(*out)) {
  1939. ebpf_network_viewer_ip_list_t *move = *out, *store = *out;
  1940. while (move) {
  1941. if (in->ver == move->ver && is_ip_inside_range(&move->first, &move->last, &in->first, &in->last, in->ver)) {
  1942. info("The range/value (%s) is inside the range/value (%s) already inserted, it will be ignored.",
  1943. in->value, move->value);
  1944. freez(in->value);
  1945. freez(in);
  1946. return;
  1947. }
  1948. store = move;
  1949. move = move->next;
  1950. }
  1951. store->next = in;
  1952. } else {
  1953. *out = in;
  1954. }
  1955. #ifdef NETDATA_INTERNAL_CHECKS
  1956. char first[512], last[512];
  1957. if (in->ver == AF_INET) {
  1958. if (inet_ntop(AF_INET, in->first.addr8, first, INET_ADDRSTRLEN) &&
  1959. inet_ntop(AF_INET, in->last.addr8, last, INET_ADDRSTRLEN))
  1960. info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
  1961. first, last,
  1962. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  1963. table);
  1964. } else {
  1965. if (inet_ntop(AF_INET6, in->first.addr8, first, INET6_ADDRSTRLEN) &&
  1966. inet_ntop(AF_INET6, in->last.addr8, last, INET6_ADDRSTRLEN))
  1967. info("Adding values %s - %s to %s IP list \"%s\" used on network viewer",
  1968. first, last,
  1969. (*out == network_viewer_opt.included_ips)?"included":"excluded",
  1970. table);
  1971. }
  1972. #endif
  1973. }
  1974. /**
  1975. * Parse IP List
  1976. *
  1977. * Parse IP list and link it.
  1978. *
  1979. * @param out a pointer to store the link list
  1980. * @param ip the value given as parameter
  1981. */
  1982. static void parse_ip_list(void **out, char *ip)
  1983. {
  1984. ebpf_network_viewer_ip_list_t **list = (ebpf_network_viewer_ip_list_t **)out;
  1985. char *ipdup = strdupz(ip);
  1986. union netdata_ip_t first = { };
  1987. union netdata_ip_t last = { };
  1988. char *is_ipv6;
  1989. if (*ip == '*' && *(ip+1) == '\0') {
  1990. memset(first.addr8, 0, sizeof(first.addr8));
  1991. memset(last.addr8, 0xFF, sizeof(last.addr8));
  1992. is_ipv6 = ip;
  1993. clean_ip_structure(list);
  1994. goto storethisip;
  1995. }
  1996. char *end = ip;
  1997. // Move while I cannot find a separator
  1998. while (*end && *end != '/' && *end != '-') end++;
  1999. // We will use only the classic IPV6 for while, but we could consider the base 85 in a near future
  2000. // https://tools.ietf.org/html/rfc1924
  2001. is_ipv6 = strchr(ip, ':');
  2002. int select;
  2003. if (*end && !is_ipv6) { // IPV4 range
  2004. select = (*end == '/') ? 0 : 1;
  2005. *end++ = '\0';
  2006. if (*end == '!') {
  2007. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2008. goto cleanipdup;
  2009. }
  2010. if (!select) { // CIDR
  2011. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  2012. if (select)
  2013. goto cleanipdup;
  2014. select = (int) str2i(end);
  2015. if (select < NETDATA_MINIMUM_IPV4_CIDR || select > NETDATA_MAXIMUM_IPV4_CIDR) {
  2016. info("The specified CIDR %s is not valid, the IP %s will be ignored.", end, ip);
  2017. goto cleanipdup;
  2018. }
  2019. last.addr32[0] = htonl(broadcast(ntohl(first.addr32[0]), select));
  2020. // This was added to remove
  2021. // https://app.codacy.com/manual/netdata/netdata/pullRequest?prid=5810941&bid=19021977
  2022. UNUSED(last.addr32[0]);
  2023. uint32_t ipv4_test = htonl(ipv4_network(ntohl(first.addr32[0]), select));
  2024. if (first.addr32[0] != ipv4_test) {
  2025. first.addr32[0] = ipv4_test;
  2026. struct in_addr ipv4_convert;
  2027. ipv4_convert.s_addr = ipv4_test;
  2028. char ipv4_msg[INET_ADDRSTRLEN];
  2029. if(inet_ntop(AF_INET, &ipv4_convert, ipv4_msg, INET_ADDRSTRLEN))
  2030. info("The network value of CIDR %s was updated for %s .", ipdup, ipv4_msg);
  2031. }
  2032. } else { // Range
  2033. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  2034. if (select)
  2035. goto cleanipdup;
  2036. select = ip2nl(last.addr8, end, AF_INET, ipdup);
  2037. if (select)
  2038. goto cleanipdup;
  2039. }
  2040. if (htonl(first.addr32[0]) > htonl(last.addr32[0])) {
  2041. info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  2042. ipdup);
  2043. goto cleanipdup;
  2044. }
  2045. } else if (is_ipv6) { // IPV6
  2046. if (!*end) { // Unique
  2047. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2048. if (select)
  2049. goto cleanipdup;
  2050. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  2051. } else if (*end == '-') {
  2052. *end++ = 0x00;
  2053. if (*end == '!') {
  2054. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2055. goto cleanipdup;
  2056. }
  2057. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2058. if (select)
  2059. goto cleanipdup;
  2060. select = ip2nl(last.addr8, end, AF_INET6, ipdup);
  2061. if (select)
  2062. goto cleanipdup;
  2063. } else { // CIDR
  2064. *end++ = 0x00;
  2065. if (*end == '!') {
  2066. info("The exclusion cannot be in the second part of the range %s, it will be ignored.", ipdup);
  2067. goto cleanipdup;
  2068. }
  2069. select = str2i(end);
  2070. if (select < 0 || select > 128) {
  2071. info("The CIDR %s is not valid, the address %s will be ignored.", end, ip);
  2072. goto cleanipdup;
  2073. }
  2074. uint64_t prefix = (uint64_t)select;
  2075. select = ip2nl(first.addr8, ip, AF_INET6, ipdup);
  2076. if (select)
  2077. goto cleanipdup;
  2078. get_ipv6_last_addr(&last, &first, prefix);
  2079. union netdata_ip_t ipv6_test;
  2080. get_ipv6_first_addr(&ipv6_test, &first, prefix);
  2081. if (memcmp(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t)) != 0) {
  2082. memcpy(first.addr8, ipv6_test.addr8, sizeof(union netdata_ip_t));
  2083. struct in6_addr ipv6_convert;
  2084. memcpy(ipv6_convert.s6_addr, ipv6_test.addr8, sizeof(union netdata_ip_t));
  2085. char ipv6_msg[INET6_ADDRSTRLEN];
  2086. if(inet_ntop(AF_INET6, &ipv6_convert, ipv6_msg, INET6_ADDRSTRLEN))
  2087. info("The network value of CIDR %s was updated for %s .", ipdup, ipv6_msg);
  2088. }
  2089. }
  2090. if ((be64toh(*(uint64_t *)&first.addr32[2]) > be64toh(*(uint64_t *)&last.addr32[2]) &&
  2091. !memcmp(first.addr32, last.addr32, 2*sizeof(uint32_t))) ||
  2092. (be64toh(*(uint64_t *)&first.addr32) > be64toh(*(uint64_t *)&last.addr32)) ) {
  2093. info("The specified range %s is invalid, the second address is smallest than the first, it will be ignored.",
  2094. ipdup);
  2095. goto cleanipdup;
  2096. }
  2097. } else { // Unique ip
  2098. select = ip2nl(first.addr8, ip, AF_INET, ipdup);
  2099. if (select)
  2100. goto cleanipdup;
  2101. memcpy(last.addr8, first.addr8, sizeof(first.addr8));
  2102. }
  2103. ebpf_network_viewer_ip_list_t *store;
  2104. storethisip:
  2105. store = callocz(1, sizeof(ebpf_network_viewer_ip_list_t));
  2106. store->value = ipdup;
  2107. store->hash = simple_hash(ipdup);
  2108. store->ver = (uint8_t)(!is_ipv6)?AF_INET:AF_INET6;
  2109. memcpy(store->first.addr8, first.addr8, sizeof(first.addr8));
  2110. memcpy(store->last.addr8, last.addr8, sizeof(last.addr8));
  2111. fill_ip_list(list, store, "socket");
  2112. return;
  2113. cleanipdup:
  2114. freez(ipdup);
  2115. }
  2116. /**
  2117. * Parse IP Range
  2118. *
  2119. * Parse the IP ranges given and create Network Viewer IP Structure
  2120. *
  2121. * @param ptr is a pointer with the text to parse.
  2122. */
  2123. static void parse_ips(char *ptr)
  2124. {
  2125. // No value
  2126. if (unlikely(!ptr))
  2127. return;
  2128. while (likely(ptr)) {
  2129. // Move forward until next valid character
  2130. while (isspace(*ptr)) ptr++;
  2131. // No valid value found
  2132. if (unlikely(!*ptr))
  2133. return;
  2134. // Find space that ends the list
  2135. char *end = strchr(ptr, ' ');
  2136. if (end) {
  2137. *end++ = '\0';
  2138. }
  2139. int neg = 0;
  2140. if (*ptr == '!') {
  2141. neg++;
  2142. ptr++;
  2143. }
  2144. if (isascii(*ptr)) { // Parse port
  2145. parse_ip_list((!neg)?(void **)&network_viewer_opt.included_ips:(void **)&network_viewer_opt.excluded_ips,
  2146. ptr);
  2147. }
  2148. ptr = end;
  2149. }
  2150. }
  2151. /**
  2152. * Parse port list
  2153. *
  2154. * Parse an allocated port list with the range given
  2155. *
  2156. * @param out a pointer to store the link list
  2157. * @param range the informed range for the user.
  2158. */
  2159. static void parse_port_list(void **out, char *range)
  2160. {
  2161. int first, last;
  2162. ebpf_network_viewer_port_list_t **list = (ebpf_network_viewer_port_list_t **)out;
  2163. char *copied = strdupz(range);
  2164. if (*range == '*' && *(range+1) == '\0') {
  2165. first = 1;
  2166. last = 65535;
  2167. clean_port_structure(list);
  2168. goto fillenvpl;
  2169. }
  2170. char *end = range;
  2171. //Move while I cannot find a separator
  2172. while (*end && *end != ':' && *end != '-') end++;
  2173. //It has a range
  2174. if (likely(*end)) {
  2175. *end++ = '\0';
  2176. if (*end == '!') {
  2177. info("The exclusion cannot be in the second part of the range, the range %s will be ignored.", copied);
  2178. freez(copied);
  2179. return;
  2180. }
  2181. last = str2i((const char *)end);
  2182. } else {
  2183. last = 0;
  2184. }
  2185. first = str2i((const char *)range);
  2186. if (first < NETDATA_MINIMUM_PORT_VALUE || first > NETDATA_MAXIMUM_PORT_VALUE) {
  2187. info("The first port %d of the range \"%s\" is invalid and it will be ignored!", first, copied);
  2188. freez(copied);
  2189. return;
  2190. }
  2191. if (!last)
  2192. last = first;
  2193. if (last < NETDATA_MINIMUM_PORT_VALUE || last > NETDATA_MAXIMUM_PORT_VALUE) {
  2194. info("The second port %d of the range \"%s\" is invalid and the whole range will be ignored!", last, copied);
  2195. freez(copied);
  2196. return;
  2197. }
  2198. if (first > last) {
  2199. info("The specified order %s is wrong, the smallest value is always the first, it will be ignored!", copied);
  2200. freez(copied);
  2201. return;
  2202. }
  2203. ebpf_network_viewer_port_list_t *w;
  2204. fillenvpl:
  2205. w = callocz(1, sizeof(ebpf_network_viewer_port_list_t));
  2206. w->value = copied;
  2207. w->hash = simple_hash(copied);
  2208. w->first = (uint16_t)htons((uint16_t)first);
  2209. w->last = (uint16_t)htons((uint16_t)last);
  2210. w->cmp_first = (uint16_t)first;
  2211. w->cmp_last = (uint16_t)last;
  2212. fill_port_list(list, w);
  2213. }
  2214. /**
  2215. * Read max dimension.
  2216. *
  2217. * Netdata plot two dimensions per connection, so it is necessary to adjust the values.
  2218. *
  2219. * @param cfg the configuration structure
  2220. */
  2221. static void read_max_dimension(struct config *cfg)
  2222. {
  2223. int maxdim ;
  2224. maxdim = (int) appconfig_get_number(cfg,
  2225. EBPF_NETWORK_VIEWER_SECTION,
  2226. EBPF_MAXIMUM_DIMENSIONS,
  2227. NETDATA_NV_CAP_VALUE);
  2228. if (maxdim < 0) {
  2229. error("'maximum dimensions = %d' must be a positive number, Netdata will change for default value %ld.",
  2230. maxdim, NETDATA_NV_CAP_VALUE);
  2231. maxdim = NETDATA_NV_CAP_VALUE;
  2232. }
  2233. maxdim /= 2;
  2234. if (!maxdim) {
  2235. info("The number of dimensions is too small (%u), we are setting it to minimum 2", network_viewer_opt.max_dim);
  2236. network_viewer_opt.max_dim = 1;
  2237. return;
  2238. }
  2239. network_viewer_opt.max_dim = (uint32_t)maxdim;
  2240. }
  2241. /**
  2242. * Parse Port Range
  2243. *
  2244. * Parse the port ranges given and create Network Viewer Port Structure
  2245. *
  2246. * @param ptr is a pointer with the text to parse.
  2247. */
  2248. static void parse_ports(char *ptr)
  2249. {
  2250. // No value
  2251. if (unlikely(!ptr))
  2252. return;
  2253. while (likely(ptr)) {
  2254. // Move forward until next valid character
  2255. while (isspace(*ptr)) ptr++;
  2256. // No valid value found
  2257. if (unlikely(!*ptr))
  2258. return;
  2259. // Find space that ends the list
  2260. char *end = strchr(ptr, ' ');
  2261. if (end) {
  2262. *end++ = '\0';
  2263. }
  2264. int neg = 0;
  2265. if (*ptr == '!') {
  2266. neg++;
  2267. ptr++;
  2268. }
  2269. if (isdigit(*ptr)) { // Parse port
  2270. parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  2271. ptr);
  2272. } else if (isalpha(*ptr)) { // Parse service
  2273. parse_service_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  2274. ptr);
  2275. } else if (*ptr == '*') { // All
  2276. parse_port_list((!neg)?(void **)&network_viewer_opt.included_port:(void **)&network_viewer_opt.excluded_port,
  2277. ptr);
  2278. }
  2279. ptr = end;
  2280. }
  2281. }
  2282. /**
  2283. * Link hostname
  2284. *
  2285. * @param out is the output link list
  2286. * @param in the hostname to add to list.
  2287. */
  2288. static void link_hostname(ebpf_network_viewer_hostname_list_t **out, ebpf_network_viewer_hostname_list_t *in)
  2289. {
  2290. if (likely(*out)) {
  2291. ebpf_network_viewer_hostname_list_t *move = *out;
  2292. for (; move->next ; move = move->next ) {
  2293. if (move->hash == in->hash && !strcmp(move->value, in->value)) {
  2294. info("The hostname %s was already inserted, it will be ignored.", in->value);
  2295. freez(in->value);
  2296. simple_pattern_free(in->value_pattern);
  2297. freez(in);
  2298. return;
  2299. }
  2300. }
  2301. move->next = in;
  2302. } else {
  2303. *out = in;
  2304. }
  2305. #ifdef NETDATA_INTERNAL_CHECKS
  2306. info("Adding value %s to %s hostname list used on network viewer",
  2307. in->value,
  2308. (*out == network_viewer_opt.included_hostnames)?"included":"excluded");
  2309. #endif
  2310. }
  2311. /**
  2312. * Link Hostnames
  2313. *
  2314. * Parse the list of hostnames to create the link list.
  2315. * This is not associated with the IP, because simple patterns like *example* cannot be resolved to IP.
  2316. *
  2317. * @param out is the output link list
  2318. * @param parse is a pointer with the text to parser.
  2319. */
  2320. static void link_hostnames(char *parse)
  2321. {
  2322. // No value
  2323. if (unlikely(!parse))
  2324. return;
  2325. while (likely(parse)) {
  2326. // Find the first valid value
  2327. while (isspace(*parse)) parse++;
  2328. // No valid value found
  2329. if (unlikely(!*parse))
  2330. return;
  2331. // Find space that ends the list
  2332. char *end = strchr(parse, ' ');
  2333. if (end) {
  2334. *end++ = '\0';
  2335. }
  2336. int neg = 0;
  2337. if (*parse == '!') {
  2338. neg++;
  2339. parse++;
  2340. }
  2341. ebpf_network_viewer_hostname_list_t *hostname = callocz(1 , sizeof(ebpf_network_viewer_hostname_list_t));
  2342. hostname->value = strdupz(parse);
  2343. hostname->hash = simple_hash(parse);
  2344. hostname->value_pattern = simple_pattern_create(parse, NULL, SIMPLE_PATTERN_EXACT);
  2345. link_hostname((!neg)?&network_viewer_opt.included_hostnames:&network_viewer_opt.excluded_hostnames,
  2346. hostname);
  2347. parse = end;
  2348. }
  2349. }
  2350. /**
  2351. * Parse network viewer section
  2352. *
  2353. * @param cfg the configuration structure
  2354. */
  2355. void parse_network_viewer_section(struct config *cfg)
  2356. {
  2357. read_max_dimension(cfg);
  2358. network_viewer_opt.hostname_resolution_enabled = appconfig_get_boolean(cfg,
  2359. EBPF_NETWORK_VIEWER_SECTION,
  2360. EBPF_CONFIG_RESOLVE_HOSTNAME,
  2361. CONFIG_BOOLEAN_NO);
  2362. network_viewer_opt.service_resolution_enabled = appconfig_get_boolean(cfg,
  2363. EBPF_NETWORK_VIEWER_SECTION,
  2364. EBPF_CONFIG_RESOLVE_SERVICE,
  2365. CONFIG_BOOLEAN_NO);
  2366. char *value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_PORTS, NULL);
  2367. parse_ports(value);
  2368. if (network_viewer_opt.hostname_resolution_enabled) {
  2369. value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION, EBPF_CONFIG_HOSTNAMES, NULL);
  2370. link_hostnames(value);
  2371. } else {
  2372. info("Name resolution is disabled, collector will not parser \"hostnames\" list.");
  2373. }
  2374. value = appconfig_get(cfg, EBPF_NETWORK_VIEWER_SECTION,
  2375. "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");
  2376. parse_ips(value);
  2377. }
  2378. /**
  2379. * Link dimension name
  2380. *
  2381. * Link user specified names inside a link list.
  2382. *
  2383. * @param port the port number associated to the dimension name.
  2384. * @param hash the calculated hash for the dimension name.
  2385. * @param name the dimension name.
  2386. */
  2387. static void link_dimension_name(char *port, uint32_t hash, char *value)
  2388. {
  2389. int test = str2i(port);
  2390. if (test < NETDATA_MINIMUM_PORT_VALUE || test > NETDATA_MAXIMUM_PORT_VALUE){
  2391. error("The dimension given (%s = %s) has an invalid value and it will be ignored.", port, value);
  2392. return;
  2393. }
  2394. ebpf_network_viewer_dim_name_t *w;
  2395. w = callocz(1, sizeof(ebpf_network_viewer_dim_name_t));
  2396. w->name = strdupz(value);
  2397. w->hash = hash;
  2398. w->port = (uint16_t) htons(test);
  2399. ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names;
  2400. if (unlikely(!names)) {
  2401. network_viewer_opt.names = w;
  2402. } else {
  2403. for (; names->next; names = names->next) {
  2404. if (names->port == w->port) {
  2405. info("Duplicated definition for a service, the name %s will be ignored. ", names->name);
  2406. freez(names->name);
  2407. names->name = w->name;
  2408. names->hash = w->hash;
  2409. freez(w);
  2410. return;
  2411. }
  2412. }
  2413. names->next = w;
  2414. }
  2415. #ifdef NETDATA_INTERNAL_CHECKS
  2416. info("Adding values %s( %u) to dimension name list used on network viewer", w->name, htons(w->port));
  2417. #endif
  2418. }
  2419. /**
  2420. * Parse service Name section.
  2421. *
  2422. * This function gets the values that will be used to overwrite dimensions.
  2423. *
  2424. * @param cfg the configuration structure
  2425. */
  2426. void parse_service_name_section(struct config *cfg)
  2427. {
  2428. struct section *co = appconfig_get_section(cfg, EBPF_SERVICE_NAME_SECTION);
  2429. if (co) {
  2430. struct config_option *cv;
  2431. for (cv = co->values; cv ; cv = cv->next) {
  2432. link_dimension_name(cv->name, cv->hash, cv->value);
  2433. }
  2434. }
  2435. // Always associated the default port to Netdata
  2436. ebpf_network_viewer_dim_name_t *names = network_viewer_opt.names;
  2437. if (names) {
  2438. uint16_t default_port = htons(19999);
  2439. while (names) {
  2440. if (names->port == default_port)
  2441. return;
  2442. names = names->next;
  2443. }
  2444. }
  2445. char *port_string = getenv("NETDATA_LISTEN_PORT");
  2446. if (port_string) {
  2447. // if variable has an invalid value, we assume netdata is using 19999
  2448. int default_port = str2i(port_string);
  2449. if (default_port > 0 && default_port < 65536)
  2450. link_dimension_name(port_string, simple_hash(port_string), "Netdata");
  2451. }
  2452. }
  2453. void parse_table_size_options(struct config *cfg)
  2454. {
  2455. socket_maps[NETDATA_SOCKET_TABLE_BANDWIDTH].user_input = (uint32_t) appconfig_get_number(cfg,
  2456. EBPF_GLOBAL_SECTION,
  2457. EBPF_CONFIG_BANDWIDTH_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  2458. socket_maps[NETDATA_SOCKET_TABLE_IPV4].user_input = (uint32_t) appconfig_get_number(cfg,
  2459. EBPF_GLOBAL_SECTION,
  2460. EBPF_CONFIG_IPV4_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  2461. socket_maps[NETDATA_SOCKET_TABLE_IPV6].user_input = (uint32_t) appconfig_get_number(cfg,
  2462. EBPF_GLOBAL_SECTION,
  2463. EBPF_CONFIG_IPV6_SIZE, NETDATA_MAXIMUM_CONNECTIONS_ALLOWED);
  2464. socket_maps[NETDATA_SOCKET_TABLE_UDP].user_input = (uint32_t) appconfig_get_number(cfg,
  2465. EBPF_GLOBAL_SECTION,
  2466. EBPF_CONFIG_UDP_SIZE, NETDATA_MAXIMUM_UDP_CONNECTIONS_ALLOWED);
  2467. }
  2468. /**
  2469. * Socket thread
  2470. *
  2471. * Thread used to generate socket charts.
  2472. *
  2473. * @param ptr a pointer to `struct ebpf_module`
  2474. *
  2475. * @return It always return NULL
  2476. */
  2477. void *ebpf_socket_thread(void *ptr)
  2478. {
  2479. netdata_thread_cleanup_push(ebpf_socket_cleanup, ptr);
  2480. memset(&inbound_vectors.tree, 0, sizeof(avl_tree_lock));
  2481. memset(&outbound_vectors.tree, 0, sizeof(avl_tree_lock));
  2482. avl_init_lock(&inbound_vectors.tree, compare_sockets);
  2483. avl_init_lock(&outbound_vectors.tree, compare_sockets);
  2484. ebpf_module_t *em = (ebpf_module_t *)ptr;
  2485. em->maps = socket_maps;
  2486. fill_ebpf_data(&socket_data);
  2487. parse_network_viewer_section(&socket_config);
  2488. parse_service_name_section(&socket_config);
  2489. parse_table_size_options(&socket_config);
  2490. if (!em->enabled)
  2491. goto endsocket;
  2492. if (pthread_mutex_init(&nv_mutex, NULL)) {
  2493. error("Cannot initialize local mutex");
  2494. goto endsocket;
  2495. }
  2496. pthread_mutex_lock(&lock);
  2497. ebpf_socket_allocate_global_vectors(NETDATA_MAX_SOCKET_VECTOR);
  2498. initialize_inbound_outbound();
  2499. if (ebpf_update_kernel(&socket_data)) {
  2500. pthread_mutex_unlock(&lock);
  2501. goto endsocket;
  2502. }
  2503. set_local_pointers();
  2504. if (running_on_kernel < NETDATA_EBPF_KERNEL_5_0)
  2505. em->mode = MODE_ENTRY;
  2506. probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects, socket_data.map_fd);
  2507. if (!probe_links) {
  2508. pthread_mutex_unlock(&lock);
  2509. goto endsocket;
  2510. }
  2511. int algorithms[NETDATA_MAX_SOCKET_VECTOR] = {
  2512. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
  2513. NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
  2514. };
  2515. ebpf_global_labels(
  2516. socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
  2517. algorithms, NETDATA_MAX_SOCKET_VECTOR);
  2518. ebpf_create_global_charts(em);
  2519. finalized_threads = 0;
  2520. pthread_mutex_unlock(&lock);
  2521. socket_collector((usec_t)(em->update_time * USEC_PER_SEC), em);
  2522. endsocket:
  2523. netdata_thread_cleanup_pop(1);
  2524. return NULL;
  2525. }