Skip to content

Commit d0c921b

Browse files
committed
in_node_exporter_metrics: collect TcpExt and IpExt counters on netstat
Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
1 parent c50e81b commit d0c921b

2 files changed

Lines changed: 288 additions & 10 deletions

File tree

plugins/in_node_exporter_metrics/ne.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ struct flb_ne {
172172
struct cmt_counter *netstat_Udp_InErrors;
173173
struct cmt_counter *netstat_Udp_OutDatagrams;
174174
struct cmt_counter *netstat_Udp_NoPorts;
175+
struct mk_list netstat_dynamic_metrics;
175176

176177
/* time */
177178
struct cmt_gauge *time;

plugins/in_node_exporter_metrics/ne_netstat_linux.c

Lines changed: 287 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,100 @@
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

34123
static 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+
276554
struct 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

Comments
 (0)