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_gauge * gauge ;
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_gauge * 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 -> gauge ;
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 -> gauge = cmt_gauge_create (ctx -> cmt , "node" , "netstat" , metric_name ,
109+ "Network statistics from /proc/net/netstat." ,
110+ 0 , NULL );
111+ if (entry -> gauge == 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 -> gauge ;
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_gauge * 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_gauge_set (metric , ts , d_val , 0 , NULL );
323+ }
324+ }
325+ }
326+ else {
327+ int idx ;
328+ double d_val ;
329+ struct cmt_gauge * 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_gauge_set (metric , ts , d_val , 0 , NULL );
363+ }
364+ }
365+ }
201366 }
202367
203368 flb_slist_destroy (& headers );
@@ -222,40 +387,142 @@ static int netstat_update(struct flb_ne *ctx)
222387
223388 ts = cfl_time_now ();
224389 prev_line = NULL ;
225- prev_proto = NETSTAT_PROTO_NONE ;
226390
227391 mk_list_foreach (head , & list ) {
228392 line = mk_list_entry (head , struct flb_slist_entry , _head );
229393
230- if (prev_proto != NETSTAT_PROTO_NONE ) {
231- if (prev_proto == NETSTAT_PROTO_TCP && strncmp (line -> str , "Tcp:" , 4 ) == 0 ) {
394+ if (prev_line != NULL ) {
395+ if (strncmp ( prev_line , "Tcp:" , 4 ) == 0 && strncmp (line -> str , "Tcp:" , 4 ) == 0 ) {
232396 netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_TCP , ts );
233- prev_proto = NETSTAT_PROTO_NONE ;
397+ netstat_process_pair ( ctx , prev_line , line -> str , NETSTAT_PROTO_NONE , ts ) ;
234398 prev_line = NULL ;
235399 continue ;
236400 }
237- else if (prev_proto == NETSTAT_PROTO_UDP && strncmp (line -> str , "Udp:" , 4 ) == 0 ) {
401+ else if (strncmp ( prev_line , "Udp:" , 4 ) == 0 && strncmp (line -> str , "Udp:" , 4 ) == 0 ) {
238402 netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_UDP , ts );
239- prev_proto = NETSTAT_PROTO_NONE ;
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 );
240412 prev_line = NULL ;
241413 continue ;
242414 }
243415
244- prev_proto = NETSTAT_PROTO_NONE ;
245416 prev_line = NULL ;
246417 }
247418
248- if (strncmp (line -> str , "Tcp:" , 4 ) == 0 ) {
419+ if (strchr (line -> str , ':' ) != NULL ) {
249420 prev_line = line -> str ;
250- prev_proto = NETSTAT_PROTO_TCP ;
251421 }
252- else if (strncmp (line -> str , "Udp:" , 4 ) == 0 ) {
253- prev_line = line -> str ;
254- prev_proto = NETSTAT_PROTO_UDP ;
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 == 0 ) {
429+ prev_line = NULL ;
430+ prev_proto = NETSTAT_PROTO_NONE ;
431+
432+ mk_list_foreach (head , & list ) {
433+ line = mk_list_entry (head , struct flb_slist_entry , _head );
434+
435+ if (prev_proto != NETSTAT_PROTO_NONE ) {
436+ if (prev_proto == NETSTAT_PROTO_TCPEXT && strncmp (line -> str , "TcpExt:" , 7 ) == 0 ) {
437+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_TCPEXT , ts );
438+ prev_proto = NETSTAT_PROTO_NONE ;
439+ prev_line = NULL ;
440+ continue ;
441+ }
442+ else if (prev_proto == NETSTAT_PROTO_IPEXT && strncmp (line -> str , "IpExt:" , 6 ) == 0 ) {
443+ netstat_process_pair (ctx , prev_line , line -> str , NETSTAT_PROTO_IPEXT , ts );
444+ prev_proto = NETSTAT_PROTO_NONE ;
445+ prev_line = NULL ;
446+ continue ;
447+ }
448+
449+ prev_proto = NETSTAT_PROTO_NONE ;
450+ prev_line = NULL ;
451+ }
452+
453+ if (strncmp (line -> str , "TcpExt:" , 7 ) == 0 ) {
454+ prev_line = line -> str ;
455+ prev_proto = NETSTAT_PROTO_TCPEXT ;
456+ }
457+ else if (strncmp (line -> str , "IpExt:" , 6 ) == 0 ) {
458+ prev_line = line -> str ;
459+ prev_proto = NETSTAT_PROTO_IPEXT ;
460+ }
255461 }
256462 }
257463
258464 flb_slist_destroy (& list );
465+
466+ mk_list_init (& list );
467+ ret = ne_utils_file_read_lines (ctx -> path_procfs , "/net/snmp6" , & list );
468+ if (ret == 0 ) {
469+ mk_list_foreach (head , & list ) {
470+ int i ;
471+ int six_index ;
472+ int metric_name_len ;
473+ double d_val ;
474+ char metric_name [256 ];
475+ char value [128 ];
476+ char raw_name [128 ];
477+ char proto_name [64 ];
478+ char field_name [64 ];
479+ struct cmt_gauge * metric ;
480+
481+ line = mk_list_entry (head , struct flb_slist_entry , _head );
482+ if (sscanf (line -> str , "%127s %127s" , raw_name , value ) != 2 ) {
483+ continue ;
484+ }
485+
486+ six_index = -1 ;
487+ i = 0 ;
488+ while (raw_name [i ] != '\0' ) {
489+ if (raw_name [i ] == '6' ) {
490+ six_index = i ;
491+ break ;
492+ }
493+ i ++ ;
494+ }
495+ if (six_index == -1 || six_index == 0 || raw_name [six_index + 1 ] == '\0' ) {
496+ continue ;
497+ }
498+
499+ snprintf (proto_name , sizeof (proto_name ) - 1 , "%.*s" ,
500+ six_index + 1 , raw_name );
501+ proto_name [sizeof (proto_name ) - 1 ] = '\0' ;
502+
503+ snprintf (field_name , sizeof (field_name ) - 1 , "%s" ,
504+ raw_name + six_index + 1 );
505+ field_name [sizeof (field_name ) - 1 ] = '\0' ;
506+
507+ metric_name_len = snprintf (metric_name , sizeof (metric_name ) - 1 , "%s_%s" ,
508+ proto_name , field_name );
509+ if (metric_name_len < 0 ) {
510+ continue ;
511+ }
512+ metric_name [sizeof (metric_name ) - 1 ] = '\0' ;
513+
514+ if (ne_utils_str_to_double (value , & d_val ) != 0 ) {
515+ continue ;
516+ }
517+
518+ metric = netstat_dynamic_metric_get (ctx , metric_name );
519+ if (metric != NULL ) {
520+ cmt_gauge_set (metric , ts , d_val , 0 , NULL );
521+ }
522+ }
523+ flb_slist_destroy (& list );
524+ }
525+
259526 return 0 ;
260527}
261528
@@ -273,10 +540,18 @@ static int ne_netstat_update(struct flb_input_instance *ins,
273540 return 0 ;
274541}
275542
543+ static int ne_netstat_exit (struct flb_ne * ctx )
544+ {
545+ if (ctx != NULL ) {
546+ netstat_dynamic_metrics_destroy (ctx );
547+ }
548+
549+ return 0 ;
550+ }
551+
276552struct flb_ne_collector netstat_collector = {
277553 .name = "netstat" ,
278554 .cb_init = ne_netstat_init ,
279555 .cb_update = ne_netstat_update ,
280- .cb_exit = NULL
556+ .cb_exit = ne_netstat_exit
281557};
282-
0 commit comments