master
c 531 lines 19.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "plugin_proc.h"
4
5 #define PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME "/proc/net/sockstat"
6
7 static struct proc_net_sockstat {
8 kernel_uint_t sockets_used;
9
10 kernel_uint_t tcp_inuse;
11 kernel_uint_t tcp_orphan;
12 kernel_uint_t tcp_tw;
13 kernel_uint_t tcp_alloc;
14 kernel_uint_t tcp_mem;
15
16 kernel_uint_t udp_inuse;
17 kernel_uint_t udp_mem;
18
19 kernel_uint_t udplite_inuse;
20
21 kernel_uint_t raw_inuse;
22
23 kernel_uint_t frag_inuse;
24 kernel_uint_t frag_memory;
25 } sockstat_root = { 0 };
26
27
28 static const RRDVAR_ACQUIRED
29 *tcp_mem_low_threshold = NULL,
30 *tcp_mem_pressure_threshold = NULL,
31 *tcp_mem_high_threshold = NULL,
32 *tcp_max_orphans_var = NULL;
33
34 void proc_net_sockstat_plugin_cleanup(void) {
35 // Cleanup any acquired RRDVARs
36 if (tcp_mem_low_threshold) {
37 rrdvar_host_variable_release(localhost, tcp_mem_low_threshold);
38 tcp_mem_low_threshold = NULL;
39 }
40 if (tcp_mem_pressure_threshold) {
41 rrdvar_host_variable_release(localhost, tcp_mem_pressure_threshold);
42 tcp_mem_pressure_threshold = NULL;
43 }
44 if (tcp_mem_high_threshold) {
45 rrdvar_host_variable_release(localhost, tcp_mem_high_threshold);
46 tcp_mem_high_threshold = NULL;
47 }
48 if (tcp_max_orphans_var) {
49 rrdvar_host_variable_release(localhost, tcp_max_orphans_var);
50 tcp_max_orphans_var = NULL;
51 }
52 }
53
54 static int read_tcp_mem(void) {
55 static char *filename = NULL;
56
57 if(unlikely(!tcp_mem_low_threshold)) {
58 tcp_mem_low_threshold = rrdvar_host_variable_add_and_acquire(localhost, "tcp_mem_low");
59 tcp_mem_pressure_threshold = rrdvar_host_variable_add_and_acquire(localhost, "tcp_mem_pressure");
60 tcp_mem_high_threshold = rrdvar_host_variable_add_and_acquire(localhost, "tcp_mem_high");
61 }
62
63 if(unlikely(!filename)) {
64 char buffer[FILENAME_MAX + 1];
65 snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_mem", netdata_configured_host_prefix);
66 filename = strdupz(buffer);
67 }
68
69 char buffer[200 + 1], *start, *end;
70 if(read_txt_file(filename, buffer, sizeof(buffer)) != 0) return 1;
71 buffer[200] = '\0';
72
73 unsigned long long low = 0, pressure = 0, high = 0;
74
75 start = buffer;
76 low = strtoull(start, &end, 10);
77
78 start = end;
79 pressure = strtoull(start, &end, 10);
80
81 start = end;
82 high = strtoull(start, &end, 10);
83
84 // fprintf(stderr, "TCP MEM low = %llu, pressure = %llu, high = %llu\n", low, pressure, high);
85
86 rrdvar_host_variable_set(localhost, tcp_mem_low_threshold, low * sysconf(_SC_PAGESIZE) / 1024.0);
87 rrdvar_host_variable_set(localhost, tcp_mem_pressure_threshold, pressure * sysconf(_SC_PAGESIZE) / 1024.0);
88 rrdvar_host_variable_set(localhost, tcp_mem_high_threshold, high * sysconf(_SC_PAGESIZE) / 1024.0);
89
90 return 0;
91 }
92
93 static kernel_uint_t read_tcp_max_orphans(void) {
94 static char *filename = NULL;
95
96 if(unlikely(!filename)) {
97 char buffer[FILENAME_MAX + 1];
98 snprintfz(buffer, FILENAME_MAX, "%s/proc/sys/net/ipv4/tcp_max_orphans", netdata_configured_host_prefix);
99 filename = strdupz(buffer);
100 }
101
102 unsigned long long tcp_max_orphans = 0;
103 if(read_single_number_file(filename, &tcp_max_orphans) == 0) {
104
105 if(unlikely(!tcp_max_orphans_var))
106 tcp_max_orphans_var = rrdvar_host_variable_add_and_acquire(localhost, "tcp_max_orphans");
107
108 rrdvar_host_variable_set(localhost, tcp_max_orphans_var, tcp_max_orphans);
109 return tcp_max_orphans;
110 }
111
112 return 0;
113 }
114
115 int do_proc_net_sockstat(int update_every, usec_t dt) {
116 (void)dt;
117
118 static procfile *ff = NULL;
119
120 static uint32_t hash_sockets = 0,
121 hash_raw = 0,
122 hash_frag = 0,
123 hash_tcp = 0,
124 hash_udp = 0,
125 hash_udplite = 0;
126
127 static long long update_constants_every = 60, update_constants_count = 0;
128
129 static ARL_BASE *arl_sockets = NULL;
130 static ARL_BASE *arl_tcp = NULL;
131 static ARL_BASE *arl_udp = NULL;
132 static ARL_BASE *arl_udplite = NULL;
133 static ARL_BASE *arl_raw = NULL;
134 static ARL_BASE *arl_frag = NULL;
135
136 static int do_sockets = -1, do_tcp_sockets = -1, do_tcp_mem = -1, do_udp_sockets = -1, do_udp_mem = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1, do_frag_mem = -1;
137
138 static char *keys[7] = { NULL };
139 static uint32_t hashes[7] = { 0 };
140 static ARL_BASE *bases[7] = { NULL };
141
142 if(unlikely(!arl_sockets)) {
143 do_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 sockets", CONFIG_BOOLEAN_AUTO);
144 do_tcp_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 TCP sockets", CONFIG_BOOLEAN_AUTO);
145 do_tcp_mem = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 TCP memory", CONFIG_BOOLEAN_AUTO);
146 do_udp_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 UDP sockets", CONFIG_BOOLEAN_AUTO);
147 do_udp_mem = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 UDP memory", CONFIG_BOOLEAN_AUTO);
148 do_udplite_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 UDPLITE sockets", CONFIG_BOOLEAN_AUTO);
149 do_raw_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 RAW sockets", CONFIG_BOOLEAN_AUTO);
150 do_frag_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 FRAG sockets", CONFIG_BOOLEAN_AUTO);
151 do_frag_mem = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat", "ipv4 FRAG memory", CONFIG_BOOLEAN_AUTO);
152
153 update_constants_every = inicfg_get_duration_seconds(&netdata_config, "plugin:proc:/proc/net/sockstat", "update constants every", update_constants_every);
154 update_constants_count = update_constants_every;
155
156 arl_sockets = arl_create("sockstat/sockets", arl_callback_str2kernel_uint_t, 60);
157 arl_expect(arl_sockets, "used", &sockstat_root.sockets_used);
158
159 arl_tcp = arl_create("sockstat/TCP", arl_callback_str2kernel_uint_t, 60);
160 arl_expect(arl_tcp, "inuse", &sockstat_root.tcp_inuse);
161 arl_expect(arl_tcp, "orphan", &sockstat_root.tcp_orphan);
162 arl_expect(arl_tcp, "tw", &sockstat_root.tcp_tw);
163 arl_expect(arl_tcp, "alloc", &sockstat_root.tcp_alloc);
164 arl_expect(arl_tcp, "mem", &sockstat_root.tcp_mem);
165
166 arl_udp = arl_create("sockstat/UDP", arl_callback_str2kernel_uint_t, 60);
167 arl_expect(arl_udp, "inuse", &sockstat_root.udp_inuse);
168 arl_expect(arl_udp, "mem", &sockstat_root.udp_mem);
169
170 arl_udplite = arl_create("sockstat/UDPLITE", arl_callback_str2kernel_uint_t, 60);
171 arl_expect(arl_udplite, "inuse", &sockstat_root.udplite_inuse);
172
173 arl_raw = arl_create("sockstat/RAW", arl_callback_str2kernel_uint_t, 60);
174 arl_expect(arl_raw, "inuse", &sockstat_root.raw_inuse);
175
176 arl_frag = arl_create("sockstat/FRAG", arl_callback_str2kernel_uint_t, 60);
177 arl_expect(arl_frag, "inuse", &sockstat_root.frag_inuse);
178 arl_expect(arl_frag, "memory", &sockstat_root.frag_memory);
179
180 hash_sockets = simple_hash("sockets");
181 hash_tcp = simple_hash("TCP");
182 hash_udp = simple_hash("UDP");
183 hash_udplite = simple_hash("UDPLITE");
184 hash_raw = simple_hash("RAW");
185 hash_frag = simple_hash("FRAG");
186
187 keys[0] = "sockets"; hashes[0] = hash_sockets; bases[0] = arl_sockets;
188 keys[1] = "TCP"; hashes[1] = hash_tcp; bases[1] = arl_tcp;
189 keys[2] = "UDP"; hashes[2] = hash_udp; bases[2] = arl_udp;
190 keys[3] = "UDPLITE"; hashes[3] = hash_udplite; bases[3] = arl_udplite;
191 keys[4] = "RAW"; hashes[4] = hash_raw; bases[4] = arl_raw;
192 keys[5] = "FRAG"; hashes[5] = hash_frag; bases[5] = arl_frag;
193 keys[6] = NULL; // terminator
194 }
195
196 update_constants_count += update_every;
197 if(unlikely(update_constants_count > update_constants_every)) {
198 read_tcp_max_orphans();
199 read_tcp_mem();
200 update_constants_count = 0;
201 }
202
203 if(unlikely(!ff)) {
204 char filename[FILENAME_MAX + 1];
205 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat");
206 ff = procfile_open(inicfg_get(&netdata_config, "plugin:proc:/proc/net/sockstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
207 if(unlikely(!ff)) return 1;
208 }
209
210 ff = procfile_readall(ff);
211 if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
212
213 size_t lines = procfile_lines(ff), l;
214
215 for(l = 0; l < lines ;l++) {
216 size_t words = procfile_linewords(ff, l);
217 char *key = procfile_lineword(ff, l, 0);
218 uint32_t hash = simple_hash(key);
219
220 int k;
221 for(k = 0; keys[k] ; k++) {
222 if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) {
223 // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words);
224 ARL_BASE *arl = bases[k];
225 arl_begin(arl);
226 size_t w = 1;
227
228 while(w + 1 < words) {
229 char *name = procfile_lineword(ff, l, w); w++;
230 char *value = procfile_lineword(ff, l, w); w++;
231 // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words);
232 if(unlikely(arl_check(arl, name, value) != 0))
233 break;
234 }
235
236 break;
237 }
238 }
239 }
240
241 // ------------------------------------------------------------------------
242
243 if (do_sockets == CONFIG_BOOLEAN_YES || do_sockets == CONFIG_BOOLEAN_AUTO) {
244 do_sockets = CONFIG_BOOLEAN_YES;
245
246 static RRDSET *st = NULL;
247 static RRDDIM *rd_used = NULL;
248
249 if(unlikely(!st)) {
250 st = rrdset_create_localhost(
251 "ip"
252 , "sockstat_sockets"
253 , NULL
254 , "sockets"
255 , NULL
256 , "Sockets used for all address families"
257 , "sockets"
258 , PLUGIN_PROC_NAME
259 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
260 , NETDATA_CHART_PRIO_IP_SOCKETS
261 , update_every
262 , RRDSET_TYPE_LINE
263 );
264
265 rd_used = rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
266 }
267
268 rrddim_set_by_pointer(st, rd_used, (collected_number)sockstat_root.sockets_used);
269 rrdset_done(st);
270 }
271
272 // ------------------------------------------------------------------------
273
274 if (do_tcp_sockets == CONFIG_BOOLEAN_YES || do_tcp_sockets == CONFIG_BOOLEAN_AUTO) {
275 do_tcp_sockets = CONFIG_BOOLEAN_YES;
276
277 static RRDSET *st = NULL;
278 static RRDDIM *rd_inuse = NULL,
279 *rd_orphan = NULL,
280 *rd_timewait = NULL,
281 *rd_alloc = NULL;
282
283 if(unlikely(!st)) {
284 st = rrdset_create_localhost(
285 "ipv4"
286 , "sockstat_tcp_sockets"
287 , NULL
288 , "tcp"
289 , NULL
290 , "TCP Sockets"
291 , "sockets"
292 , PLUGIN_PROC_NAME
293 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
294 , NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS
295 , update_every
296 , RRDSET_TYPE_LINE
297 );
298
299 rd_alloc = rrddim_add(st, "alloc", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
300 rd_orphan = rrddim_add(st, "orphan", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
301 rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
302 rd_timewait = rrddim_add(st, "timewait", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
303 }
304
305 rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.tcp_inuse);
306 rrddim_set_by_pointer(st, rd_orphan, (collected_number)sockstat_root.tcp_orphan);
307 rrddim_set_by_pointer(st, rd_timewait, (collected_number)sockstat_root.tcp_tw);
308 rrddim_set_by_pointer(st, rd_alloc, (collected_number)sockstat_root.tcp_alloc);
309 rrdset_done(st);
310 }
311
312 // ------------------------------------------------------------------------
313
314 if (do_tcp_mem == CONFIG_BOOLEAN_YES || do_tcp_mem == CONFIG_BOOLEAN_AUTO) {
315 do_tcp_mem = CONFIG_BOOLEAN_YES;
316
317 static RRDSET *st = NULL;
318 static RRDDIM *rd_mem = NULL;
319
320 if(unlikely(!st)) {
321 st = rrdset_create_localhost(
322 "ipv4"
323 , "sockstat_tcp_mem"
324 , NULL
325 , "tcp"
326 , NULL
327 , "TCP Sockets Memory"
328 , "KiB"
329 , PLUGIN_PROC_NAME
330 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
331 , NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS_MEM
332 , update_every
333 , RRDSET_TYPE_AREA
334 );
335
336 rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE);
337 }
338
339 rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.tcp_mem);
340 rrdset_done(st);
341 }
342
343 // ------------------------------------------------------------------------
344
345 if (do_udp_sockets == CONFIG_BOOLEAN_YES || do_udp_sockets == CONFIG_BOOLEAN_AUTO) {
346 do_udp_sockets = CONFIG_BOOLEAN_YES;
347
348 static RRDSET *st = NULL;
349 static RRDDIM *rd_inuse = NULL;
350
351 if(unlikely(!st)) {
352 st = rrdset_create_localhost(
353 "ipv4"
354 , "sockstat_udp_sockets"
355 , NULL
356 , "udp"
357 , NULL
358 , "IPv4 UDP Sockets"
359 , "sockets"
360 , PLUGIN_PROC_NAME
361 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
362 , NETDATA_CHART_PRIO_IPV4_UDP_SOCKETS
363 , update_every
364 , RRDSET_TYPE_LINE
365 );
366
367 rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
368 }
369
370 rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udp_inuse);
371 rrdset_done(st);
372 }
373
374 // ------------------------------------------------------------------------
375
376 if (do_udp_mem == CONFIG_BOOLEAN_YES || do_udp_mem == CONFIG_BOOLEAN_AUTO) {
377 do_udp_mem = CONFIG_BOOLEAN_YES;
378
379 static RRDSET *st = NULL;
380 static RRDDIM *rd_mem = NULL;
381
382 if(unlikely(!st)) {
383 st = rrdset_create_localhost(
384 "ipv4"
385 , "sockstat_udp_mem"
386 , NULL
387 , "udp"
388 , NULL
389 , "IPv4 UDP Sockets Memory"
390 , "KiB"
391 , PLUGIN_PROC_NAME
392 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
393 , NETDATA_CHART_PRIO_IPV4_UDP_SOCKETS_MEM
394 , update_every
395 , RRDSET_TYPE_AREA
396 );
397
398 rd_mem = rrddim_add(st, "mem", NULL, sysconf(_SC_PAGESIZE), 1024, RRD_ALGORITHM_ABSOLUTE);
399 }
400
401 rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.udp_mem);
402 rrdset_done(st);
403 }
404
405 // ------------------------------------------------------------------------
406
407 if (do_udplite_sockets == CONFIG_BOOLEAN_YES || do_udplite_sockets == CONFIG_BOOLEAN_AUTO) {
408 do_udplite_sockets = CONFIG_BOOLEAN_YES;
409
410 static RRDSET *st = NULL;
411 static RRDDIM *rd_inuse = NULL;
412
413 if(unlikely(!st)) {
414 st = rrdset_create_localhost(
415 "ipv4"
416 , "sockstat_udplite_sockets"
417 , NULL
418 , "udplite"
419 , NULL
420 , "IPv4 UDPLITE Sockets"
421 , "sockets"
422 , PLUGIN_PROC_NAME
423 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
424 , NETDATA_CHART_PRIO_IPV4_UDPLITE_SOCKETS
425 , update_every
426 , RRDSET_TYPE_LINE
427 );
428
429 rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
430 }
431
432 rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.udplite_inuse);
433 rrdset_done(st);
434 }
435
436 // ------------------------------------------------------------------------
437
438 if (do_raw_sockets == CONFIG_BOOLEAN_YES || do_raw_sockets == CONFIG_BOOLEAN_AUTO) {
439 do_raw_sockets = CONFIG_BOOLEAN_YES;
440
441 static RRDSET *st = NULL;
442 static RRDDIM *rd_inuse = NULL;
443
444 if(unlikely(!st)) {
445 st = rrdset_create_localhost(
446 "ipv4"
447 , "sockstat_raw_sockets"
448 , NULL
449 , "raw"
450 , NULL
451 , "IPv4 RAW Sockets"
452 , "sockets"
453 , PLUGIN_PROC_NAME
454 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
455 , NETDATA_CHART_PRIO_IPV4_RAW
456 , update_every
457 , RRDSET_TYPE_LINE
458 );
459
460 rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
461 }
462
463 rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.raw_inuse);
464 rrdset_done(st);
465 }
466
467 // ------------------------------------------------------------------------
468
469 if (do_frag_sockets == CONFIG_BOOLEAN_YES || do_frag_sockets == CONFIG_BOOLEAN_AUTO) {
470 do_frag_sockets = CONFIG_BOOLEAN_YES;
471
472 static RRDSET *st = NULL;
473 static RRDDIM *rd_inuse = NULL;
474
475 if(unlikely(!st)) {
476 st = rrdset_create_localhost(
477 "ipv4"
478 , "sockstat_frag_sockets"
479 , NULL
480 , "fragments"
481 , NULL
482 , "IPv4 FRAG Sockets"
483 , "fragments"
484 , PLUGIN_PROC_NAME
485 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
486 , NETDATA_CHART_PRIO_IPV4_FRAGMENTS_SOCKETS
487 , update_every
488 , RRDSET_TYPE_LINE
489 );
490
491 rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
492 }
493
494 rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat_root.frag_inuse);
495 rrdset_done(st);
496 }
497
498 // ------------------------------------------------------------------------
499
500 if (do_frag_mem == CONFIG_BOOLEAN_YES || do_frag_mem == CONFIG_BOOLEAN_AUTO) {
501 do_frag_mem = CONFIG_BOOLEAN_YES;
502
503 static RRDSET *st = NULL;
504 static RRDDIM *rd_mem = NULL;
505
506 if(unlikely(!st)) {
507 st = rrdset_create_localhost(
508 "ipv4"
509 , "sockstat_frag_mem"
510 , NULL
511 , "fragments"
512 , NULL
513 , "IPv4 FRAG Sockets Memory"
514 , "KiB"
515 , PLUGIN_PROC_NAME
516 , PLUGIN_PROC_MODULE_NET_SOCKSTAT_NAME
517 , NETDATA_CHART_PRIO_IPV4_FRAGMENTS_SOCKETS_MEM
518 , update_every
519 , RRDSET_TYPE_AREA
520 );
521
522 rd_mem = rrddim_add(st, "mem", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
523 }
524
525 rrddim_set_by_pointer(st, rd_mem, (collected_number)sockstat_root.frag_memory);
526 rrdset_done(st);
527 }
528
529 return 0;
530 }
531