3030#define NETSTAT_PROTO_NONE 0
3131#define NETSTAT_PROTO_TCP 1
3232#define NETSTAT_PROTO_UDP 2
33+ #define NETSTAT_PROTO_TCPEXT 3
34+ #define NETSTAT_PROTO_IPEXT 4
35+
36+ struct netstat_dynamic_metric {
37+ char * name ;
38+ struct cmt_counter * counter ;
39+ struct mk_list _head ;
40+ };
41+
42+ static void netstat_dynamic_metrics_destroy (struct flb_ne * ctx )
43+ {
44+ struct mk_list * tmp ;
45+ struct mk_list * head ;
46+ struct netstat_dynamic_metric * entry ;
47+
48+ mk_list_foreach_safe (head , tmp , & ctx -> netstat_dynamic_metrics ) {
49+ entry = mk_list_entry (head , struct netstat_dynamic_metric , _head );
50+ mk_list_del (& entry -> _head );
51+ if (entry -> name != NULL ) {
52+ flb_free (entry -> name );
53+ }
54+ flb_free (entry );
55+ }
56+ }
57+
58+ static int netstat_is_static_metric (const char * name )
59+ {
60+ if (strcmp (name , "Tcp_CurrEstab" ) == 0 ||
61+ strcmp (name , "Tcp_ActiveOpens" ) == 0 ||
62+ strcmp (name , "Tcp_PassiveOpens" ) == 0 ||
63+ strcmp (name , "Tcp_RetransSegs" ) == 0 ||
64+ strcmp (name , "Udp_InDatagrams" ) == 0 ||
65+ strcmp (name , "Udp_NoPorts" ) == 0 ||
66+ strcmp (name , "Udp_InErrors" ) == 0 ||
67+ strcmp (name , "Udp_OutDatagrams" ) == 0 ) {
68+ return FLB_TRUE ;
69+ }
70+
71+ return FLB_FALSE ;
72+ }
73+
74+ static struct cmt_counter * netstat_dynamic_metric_get (struct flb_ne * ctx , const char * name )
75+ {
76+ int ret ;
77+ size_t name_len ;
78+ char * metric_name ;
79+ struct mk_list * head ;
80+ struct netstat_dynamic_metric * entry ;
81+
82+ mk_list_foreach (head , & ctx -> netstat_dynamic_metrics ) {
83+ entry = mk_list_entry (head , struct netstat_dynamic_metric , _head );
84+ if (strcmp (entry -> name , name ) == 0 ) {
85+ return entry -> counter ;
86+ }
87+ }
88+
89+ entry = flb_calloc (1 , sizeof (struct netstat_dynamic_metric ));
90+ if (entry == NULL ) {
91+ return NULL ;
92+ }
93+
94+ name_len = strlen (name );
95+ metric_name = flb_malloc (name_len + 1 );
96+ if (metric_name == NULL ) {
97+ flb_free (entry );
98+ return NULL ;
99+ }
100+
101+ ret = snprintf (metric_name , name_len + 1 , "%s" , name );
102+ if (ret < 0 || ret >= (int ) (name_len + 1 )) {
103+ flb_free (metric_name );
104+ flb_free (entry );
105+ return NULL ;
106+ }
107+
108+ entry -> counter = cmt_counter_create (ctx -> cmt , "node" , "netstat" , metric_name ,
109+ "Network statistics from /proc/net/netstat." ,
110+ 0 , NULL );
111+ if (entry -> counter == NULL ) {
112+ flb_free (metric_name );
113+ flb_free (entry );
114+ return NULL ;
115+ }
116+
117+ entry -> name = metric_name ;
118+ mk_list_add (& entry -> _head , & ctx -> netstat_dynamic_metrics );
119+
120+ return entry -> counter ;
121+ }
33122
34123static int netstat_configure (struct flb_ne * ctx )
35124{
125+ mk_list_init (& ctx -> netstat_dynamic_metrics );
126+
36127 ctx -> netstat_Tcp_CurrEstab =
37128 cmt_gauge_create (ctx -> cmt , "node" , "netstat" , "Tcp_CurrEstab" ,
38129 "Number of TCP connections in ESTABLISHED or CLOSE-WAIT state." ,
@@ -198,6 +289,80 @@ static void netstat_process_pair(struct flb_ne *ctx,
198289 else if (proto == NETSTAT_PROTO_UDP ) {
199290 netstat_process_udp (ctx , & headers , headers_count , & values , values_count , ts );
200291 }
292+ else if (proto == NETSTAT_PROTO_TCPEXT || proto == NETSTAT_PROTO_IPEXT ) {
293+ int idx ;
294+ double d_val ;
295+ struct cmt_counter * metric ;
296+ char metric_name [256 ];
297+ struct flb_slist_entry * key ;
298+ struct flb_slist_entry * val ;
299+
300+ for (idx = 1 ; idx < headers_count && idx < values_count ; idx ++ ) {
301+ key = flb_slist_entry_get (& headers , idx );
302+ val = flb_slist_entry_get (& values , idx );
303+
304+ if (key == NULL || val == NULL ) {
305+ continue ;
306+ }
307+
308+ if (ne_utils_str_to_double (val -> str , & d_val ) != 0 ) {
309+ continue ;
310+ }
311+
312+ if (proto == NETSTAT_PROTO_TCPEXT ) {
313+ snprintf (metric_name , sizeof (metric_name ) - 1 , "TcpExt_%s" , key -> str );
314+ }
315+ else {
316+ snprintf (metric_name , sizeof (metric_name ) - 1 , "IpExt_%s" , key -> str );
317+ }
318+ metric_name [sizeof (metric_name ) - 1 ] = '\0' ;
319+
320+ metric = netstat_dynamic_metric_get (ctx , metric_name );
321+ if (metric != NULL ) {
322+ cmt_counter_set (metric , ts , d_val , 0 , NULL );
323+ }
324+ }
325+ }
326+ else {
327+ int idx ;
328+ double d_val ;
329+ struct cmt_counter * metric ;
330+ char metric_name [256 ];
331+ struct flb_slist_entry * proto_name ;
332+ struct flb_slist_entry * key ;
333+ struct flb_slist_entry * val ;
334+
335+ proto_name = flb_slist_entry_get (& headers , 0 );
336+ if (proto_name != NULL && strlen (proto_name -> str ) > 1 ) {
337+ proto_name -> str [strlen (proto_name -> str ) - 1 ] = '\0' ;
338+ }
339+
340+ for (idx = 1 ; idx < headers_count && idx < values_count ; idx ++ ) {
341+ key = flb_slist_entry_get (& headers , idx );
342+ val = flb_slist_entry_get (& values , idx );
343+
344+ if (key == NULL || val == NULL || proto_name == NULL ) {
345+ continue ;
346+ }
347+
348+ if (ne_utils_str_to_double (val -> str , & d_val ) != 0 ) {
349+ continue ;
350+ }
351+
352+ snprintf (metric_name , sizeof (metric_name ) - 1 , "%s_%s" ,
353+ proto_name -> str , key -> str );
354+ metric_name [sizeof (metric_name ) - 1 ] = '\0' ;
355+
356+ if (netstat_is_static_metric (metric_name ) == FLB_TRUE ) {
357+ continue ;
358+ }
359+
360+ metric = netstat_dynamic_metric_get (ctx , metric_name );
361+ if (metric != NULL ) {
362+ cmt_counter_set (metric , ts , d_val , 0 , NULL );
363+ }
364+ }
365+ }
201366 }
202367
203368 flb_slist_destroy (& headers );
@@ -221,21 +386,64 @@ static int netstat_update(struct flb_ne *ctx)
221386 }
222387
223388 ts = cfl_time_now ();
389+ prev_line = NULL ;
390+
391+ mk_list_foreach (head , & list ) {
392+ line = mk_list_entry (head , struct flb_slist_entry , _head );
393+
394+ if (prev_line != NULL ) {
395+ if (strncmp (prev_line , "Tcp:" , 4 ) == 0 && strncmp (line -> str , "Tcp:" , 4 ) == 0 ) {
396+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_TCP , ts );
397+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_NONE , ts );
398+ prev_line = NULL ;
399+ continue ;
400+ }
401+ else if (strncmp (prev_line , "Udp:" , 4 ) == 0 && strncmp (line -> str , "Udp:" , 4 ) == 0 ) {
402+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_UDP , ts );
403+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_NONE , ts );
404+ prev_line = NULL ;
405+ continue ;
406+ }
407+ else if ((strncmp (prev_line , "Ip:" , 3 ) == 0 && strncmp (line -> str , "Ip:" , 3 ) == 0 ) ||
408+ (strncmp (prev_line , "Icmp:" , 5 ) == 0 && strncmp (line -> str , "Icmp:" , 5 ) == 0 ) ||
409+ (strncmp (prev_line , "IcmpMsg:" , 8 ) == 0 && strncmp (line -> str , "IcmpMsg:" , 8 ) == 0 ) ||
410+ (strncmp (prev_line , "UdpLite:" , 8 ) == 0 && strncmp (line -> str , "UdpLite:" , 8 ) == 0 )) {
411+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_NONE , ts );
412+ prev_line = NULL ;
413+ continue ;
414+ }
415+
416+ prev_line = NULL ;
417+ }
418+
419+ if (strchr (line -> str , ':' ) != NULL ) {
420+ prev_line = line -> str ;
421+ }
422+ }
423+
424+ flb_slist_destroy (& list );
425+
426+ mk_list_init (& list );
427+ ret = ne_utils_file_read_lines (ctx -> path_procfs , "/net/netstat" , & list );
428+ if (ret == -1 ) {
429+ return 0 ;
430+ }
431+
224432 prev_line = NULL ;
225433 prev_proto = NETSTAT_PROTO_NONE ;
226434
227435 mk_list_foreach (head , & list ) {
228436 line = mk_list_entry (head , struct flb_slist_entry , _head );
229437
230438 if (prev_proto != NETSTAT_PROTO_NONE ) {
231- if (prev_proto == NETSTAT_PROTO_TCP && strncmp (line -> str , "Tcp :" , 4 ) == 0 ) {
232- netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_TCP , ts );
439+ if (prev_proto == NETSTAT_PROTO_TCPEXT && strncmp (line -> str , "TcpExt :" , 7 ) == 0 ) {
440+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_TCPEXT , ts );
233441 prev_proto = NETSTAT_PROTO_NONE ;
234442 prev_line = NULL ;
235443 continue ;
236444 }
237- else if (prev_proto == NETSTAT_PROTO_UDP && strncmp (line -> str , "Udp :" , 4 ) == 0 ) {
238- netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_UDP , ts );
445+ else if (prev_proto == NETSTAT_PROTO_IPEXT && strncmp (line -> str , "IpExt :" , 6 ) == 0 ) {
446+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_IPEXT , ts );
239447 prev_proto = NETSTAT_PROTO_NONE ;
240448 prev_line = NULL ;
241449 continue ;
@@ -245,17 +453,78 @@ static int netstat_update(struct flb_ne *ctx)
245453 prev_line = NULL ;
246454 }
247455
248- if (strncmp (line -> str , "Tcp :" , 4 ) == 0 ) {
456+ if (strncmp (line -> str , "TcpExt :" , 7 ) == 0 ) {
249457 prev_line = line -> str ;
250- prev_proto = NETSTAT_PROTO_TCP ;
458+ prev_proto = NETSTAT_PROTO_TCPEXT ;
251459 }
252- else if (strncmp (line -> str , "Udp :" , 4 ) == 0 ) {
460+ else if (strncmp (line -> str , "IpExt :" , 6 ) == 0 ) {
253461 prev_line = line -> str ;
254- prev_proto = NETSTAT_PROTO_UDP ;
462+ prev_proto = NETSTAT_PROTO_IPEXT ;
255463 }
256464 }
257465
258466 flb_slist_destroy (& list );
467+
468+ mk_list_init (& list );
469+ ret = ne_utils_file_read_lines (ctx -> path_procfs , "/net/snmp6" , & list );
470+ if (ret == 0 ) {
471+ mk_list_foreach (head , & list ) {
472+ int i ;
473+ int six_index ;
474+ int metric_name_len ;
475+ double d_val ;
476+ char metric_name [256 ];
477+ char value [128 ];
478+ char raw_name [128 ];
479+ char proto_name [64 ];
480+ char field_name [64 ];
481+ struct cmt_counter * metric ;
482+
483+ line = mk_list_entry (head , struct flb_slist_entry , _head );
484+ if (sscanf (line -> str , "%127s %127s" , raw_name , value ) != 2 ) {
485+ continue ;
486+ }
487+
488+ six_index = -1 ;
489+ i = 0 ;
490+ while (raw_name [i ] != '\0' ) {
491+ if (raw_name [i ] == '6' ) {
492+ six_index = i ;
493+ break ;
494+ }
495+ i ++ ;
496+ }
497+ if (six_index == -1 || six_index == 0 || raw_name [six_index + 1 ] == '\0' ) {
498+ continue ;
499+ }
500+
501+ snprintf (proto_name , sizeof (proto_name ) - 1 , "%.*s" ,
502+ six_index + 1 , raw_name );
503+ proto_name [sizeof (proto_name ) - 1 ] = '\0' ;
504+
505+ snprintf (field_name , sizeof (field_name ) - 1 , "%s" ,
506+ raw_name + six_index + 1 );
507+ field_name [sizeof (field_name ) - 1 ] = '\0' ;
508+
509+ metric_name_len = snprintf (metric_name , sizeof (metric_name ) - 1 , "%s_%s" ,
510+ proto_name , field_name );
511+ if (metric_name_len < 0 ) {
512+ continue ;
513+ }
514+ metric_name [sizeof (metric_name ) - 1 ] = '\0' ;
515+
516+ if (ne_utils_str_to_double (value , & d_val ) != 0 ) {
517+ continue ;
518+ }
519+
520+ metric = netstat_dynamic_metric_get (ctx , metric_name );
521+ if (metric != NULL ) {
522+ cmt_counter_set (metric , ts , d_val , 0 , NULL );
523+ }
524+ }
525+ flb_slist_destroy (& list );
526+ }
527+
259528 return 0 ;
260529}
261530
@@ -273,10 +542,18 @@ static int ne_netstat_update(struct flb_input_instance *ins,
273542 return 0 ;
274543}
275544
545+ static int ne_netstat_exit (struct flb_ne * ctx )
546+ {
547+ if (ctx != NULL ) {
548+ netstat_dynamic_metrics_destroy (ctx );
549+ }
550+
551+ return 0 ;
552+ }
553+
276554struct flb_ne_collector netstat_collector = {
277555 .name = "netstat" ,
278556 .cb_init = ne_netstat_init ,
279557 .cb_update = ne_netstat_update ,
280- .cb_exit = NULL
558+ .cb_exit = ne_netstat_exit
281559};
282-
0 commit comments