]> arthur.barton.de Git - netdata.git/blob - src/proc_net_dev.c
dns_query_time plugin: replace "." with "_" in dimensions
[netdata.git] / src / proc_net_dev.c
1 #include "common.h"
2
3 struct netdev {
4     char *name;
5     uint32_t hash;
6     size_t len;
7
8     // flags
9     int configured;
10     int enabled;
11     int updated;
12
13     int do_bandwidth;
14     int do_packets;
15     int do_errors;
16     int do_drops;
17     int do_fifo;
18     int do_compressed;
19     int do_events;
20
21     // data collected
22     kernel_uint_t rbytes;
23     kernel_uint_t rpackets;
24     kernel_uint_t rerrors;
25     kernel_uint_t rdrops;
26     kernel_uint_t rfifo;
27     kernel_uint_t rframe;
28     kernel_uint_t rcompressed;
29     kernel_uint_t rmulticast;
30
31     kernel_uint_t tbytes;
32     kernel_uint_t tpackets;
33     kernel_uint_t terrors;
34     kernel_uint_t tdrops;
35     kernel_uint_t tfifo;
36     kernel_uint_t tcollisions;
37     kernel_uint_t tcarrier;
38     kernel_uint_t tcompressed;
39
40     // charts
41     RRDSET *st_bandwidth;
42     RRDSET *st_packets;
43     RRDSET *st_errors;
44     RRDSET *st_drops;
45     RRDSET *st_fifo;
46     RRDSET *st_compressed;
47     RRDSET *st_events;
48
49     // dimensions
50     RRDDIM *rd_rbytes;
51     RRDDIM *rd_rpackets;
52     RRDDIM *rd_rerrors;
53     RRDDIM *rd_rdrops;
54     RRDDIM *rd_rfifo;
55     RRDDIM *rd_rframe;
56     RRDDIM *rd_rcompressed;
57     RRDDIM *rd_rmulticast;
58
59     RRDDIM *rd_tbytes;
60     RRDDIM *rd_tpackets;
61     RRDDIM *rd_terrors;
62     RRDDIM *rd_tdrops;
63     RRDDIM *rd_tfifo;
64     RRDDIM *rd_tcollisions;
65     RRDDIM *rd_tcarrier;
66     RRDDIM *rd_tcompressed;
67
68     struct netdev *next;
69 };
70
71 static struct netdev *netdev_root = NULL, *netdev_last_used = NULL;
72
73 static size_t netdev_added = 0, netdev_found = 0;
74
75 static void netdev_free(struct netdev *d) {
76     if(d->st_bandwidth)  rrdset_flag_set(d->st_bandwidth,  RRDSET_FLAG_OBSOLETE);
77     if(d->st_packets)    rrdset_flag_set(d->st_packets,    RRDSET_FLAG_OBSOLETE);
78     if(d->st_errors)     rrdset_flag_set(d->st_errors,     RRDSET_FLAG_OBSOLETE);
79     if(d->st_drops)      rrdset_flag_set(d->st_drops,      RRDSET_FLAG_OBSOLETE);
80     if(d->st_fifo)       rrdset_flag_set(d->st_fifo,       RRDSET_FLAG_OBSOLETE);
81     if(d->st_compressed) rrdset_flag_set(d->st_compressed, RRDSET_FLAG_OBSOLETE);
82     if(d->st_events)     rrdset_flag_set(d->st_events,     RRDSET_FLAG_OBSOLETE);
83
84     netdev_added--;
85     freez(d->name);
86     freez(d);
87 }
88
89 static void netdev_cleanup() {
90     if(likely(netdev_found == netdev_added)) return;
91
92     netdev_added = 0;
93     struct netdev *d = netdev_root, *last = NULL;
94     while(d) {
95         if(unlikely(!d->updated)) {
96             // info("Removing network device '%s', linked after '%s'", d->name, last?last->name:"ROOT");
97
98             if(netdev_last_used == d)
99                 netdev_last_used = last;
100
101             struct netdev *t = d;
102
103             if(d == netdev_root || !last)
104                 netdev_root = d = d->next;
105
106             else
107                 last->next = d = d->next;
108
109             t->next = NULL;
110             netdev_free(t);
111         }
112         else {
113             netdev_added++;
114             last = d;
115             d->updated = 0;
116             d = d->next;
117         }
118     }
119 }
120
121 static struct netdev *get_netdev(const char *name) {
122     struct netdev *d;
123
124     uint32_t hash = simple_hash(name);
125
126     // search it, from the last position to the end
127     for(d = netdev_last_used ; d ; d = d->next) {
128         if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
129             netdev_last_used = d->next;
130             return d;
131         }
132     }
133
134     // search it from the beginning to the last position we used
135     for(d = netdev_root ; d != netdev_last_used ; d = d->next) {
136         if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
137             netdev_last_used = d->next;
138             return d;
139         }
140     }
141
142     // create a new one
143     d = callocz(1, sizeof(struct netdev));
144     d->name = strdupz(name);
145     d->hash = simple_hash(d->name);
146     d->len = strlen(d->name);
147     netdev_added++;
148
149     // link it to the end
150     if(netdev_root) {
151         struct netdev *e;
152         for(e = netdev_root; e->next ; e = e->next) ;
153         e->next = d;
154     }
155     else
156         netdev_root = d;
157
158     return d;
159 }
160
161 int do_proc_net_dev(int update_every, usec_t dt) {
162     (void)dt;
163     static SIMPLE_PATTERN *disabled_list = NULL;
164     static procfile *ff = NULL;
165     static int enable_new_interfaces = -1;
166     static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
167
168     if(unlikely(enable_new_interfaces == -1)) {
169         enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
170
171         do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
172         do_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_BOOLEAN_AUTO);
173         do_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_BOOLEAN_AUTO);
174         do_drops        = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_BOOLEAN_AUTO);
175         do_fifo         = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
176         do_compressed   = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
177         do_events       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
178
179         disabled_list = simple_pattern_create(
180                 config_get("plugin:proc:/proc/net/dev", "disable by default interfaces matching", "lo fireqos* *-ifb")
181                 , SIMPLE_PATTERN_EXACT);
182     }
183
184     if(unlikely(!ff)) {
185         char filename[FILENAME_MAX + 1];
186         snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/dev");
187         ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
188         if(unlikely(!ff)) return 1;
189     }
190
191     ff = procfile_readall(ff);
192     if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
193
194     netdev_found = 0;
195
196     size_t lines = procfile_lines(ff), l;
197     for(l = 2; l < lines ;l++) {
198         // require 17 words on each line
199         if(unlikely(procfile_linewords(ff, l) < 17)) continue;
200
201         struct netdev *d = get_netdev(procfile_lineword(ff, l, 0));
202         d->updated = 1;
203         netdev_found++;
204
205         if(unlikely(!d->configured)) {
206             // this is the first time we see this interface
207
208             // remember we configured it
209             d->configured = 1;
210
211             d->enabled = enable_new_interfaces;
212
213             if(d->enabled)
214                 d->enabled = !simple_pattern_matches(disabled_list, d->name);
215
216             char var_name[512 + 1];
217             snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", d->name);
218             d->enabled = config_get_boolean_ondemand(var_name, "enabled", d->enabled);
219
220             if(d->enabled == CONFIG_BOOLEAN_NO)
221                 continue;
222
223             d->do_bandwidth  = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
224             d->do_packets    = config_get_boolean_ondemand(var_name, "packets", do_packets);
225             d->do_errors     = config_get_boolean_ondemand(var_name, "errors", do_errors);
226             d->do_drops      = config_get_boolean_ondemand(var_name, "drops", do_drops);
227             d->do_fifo       = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
228             d->do_compressed = config_get_boolean_ondemand(var_name, "compressed", do_compressed);
229             d->do_events     = config_get_boolean_ondemand(var_name, "events", do_events);
230         }
231
232         if(unlikely(!d->enabled))
233             continue;
234
235         if(likely(d->do_bandwidth != CONFIG_BOOLEAN_NO)) {
236             d->rbytes      = str2kernel_uint_t(procfile_lineword(ff, l, 1));
237             d->tbytes      = str2kernel_uint_t(procfile_lineword(ff, l, 9));
238         }
239
240         if(likely(d->do_packets != CONFIG_BOOLEAN_NO)) {
241             d->rpackets    = str2kernel_uint_t(procfile_lineword(ff, l, 2));
242             d->rmulticast  = str2kernel_uint_t(procfile_lineword(ff, l, 8));
243             d->tpackets    = str2kernel_uint_t(procfile_lineword(ff, l, 10));
244         }
245
246         if(likely(d->do_errors != CONFIG_BOOLEAN_NO)) {
247             d->rerrors     = str2kernel_uint_t(procfile_lineword(ff, l, 3));
248             d->terrors     = str2kernel_uint_t(procfile_lineword(ff, l, 11));
249         }
250
251         if(likely(d->do_drops != CONFIG_BOOLEAN_NO)) {
252             d->rdrops      = str2kernel_uint_t(procfile_lineword(ff, l, 4));
253             d->tdrops      = str2kernel_uint_t(procfile_lineword(ff, l, 12));
254         }
255
256         if(likely(d->do_fifo != CONFIG_BOOLEAN_NO)) {
257             d->rfifo       = str2kernel_uint_t(procfile_lineword(ff, l, 5));
258             d->tfifo       = str2kernel_uint_t(procfile_lineword(ff, l, 13));
259         }
260
261         if(likely(d->do_compressed != CONFIG_BOOLEAN_NO)) {
262             d->rcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 7));
263             d->tcompressed = str2kernel_uint_t(procfile_lineword(ff, l, 16));
264         }
265
266         if(likely(d->do_events != CONFIG_BOOLEAN_NO)) {
267             d->rframe      = str2kernel_uint_t(procfile_lineword(ff, l, 6));
268             d->tcollisions = str2kernel_uint_t(procfile_lineword(ff, l, 14));
269             d->tcarrier    = str2kernel_uint_t(procfile_lineword(ff, l, 15));
270         }
271
272         // --------------------------------------------------------------------
273
274         if(unlikely((d->do_bandwidth == CONFIG_BOOLEAN_AUTO && (d->rbytes || d->tbytes))))
275             d->do_bandwidth = CONFIG_BOOLEAN_YES;
276
277         if(d->do_bandwidth == CONFIG_BOOLEAN_YES) {
278             if(unlikely(!d->st_bandwidth)) {
279
280                 d->st_bandwidth = rrdset_create_localhost(
281                         "net"
282                         , d->name
283                         , NULL
284                         , d->name
285                         , "net.net"
286                         , "Bandwidth"
287                         , "kilobits/s"
288                         , 7000
289                         , update_every
290                         , RRDSET_TYPE_AREA
291                 );
292
293                 d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
294                 d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
295             }
296             else rrdset_next(d->st_bandwidth);
297
298             rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, (collected_number)d->rbytes);
299             rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, (collected_number)d->tbytes);
300             rrdset_done(d->st_bandwidth);
301         }
302
303         // --------------------------------------------------------------------
304
305         if(unlikely((d->do_packets == CONFIG_BOOLEAN_AUTO && (d->rpackets || d->tpackets || d->rmulticast))))
306             d->do_packets = CONFIG_BOOLEAN_YES;
307
308         if(d->do_packets == CONFIG_BOOLEAN_YES) {
309             if(unlikely(!d->st_packets)) {
310
311                 d->st_packets = rrdset_create_localhost(
312                         "net_packets"
313                         , d->name
314                         , NULL
315                         , d->name
316                         , "net.packets"
317                         , "Packets"
318                         , "packets/s"
319                         , 7001
320                         , update_every
321                         , RRDSET_TYPE_LINE
322                 );
323
324                 rrdset_flag_set(d->st_packets, RRDSET_FLAG_DETAIL);
325
326                 d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
327                 d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
328                 d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
329             }
330             else rrdset_next(d->st_packets);
331
332             rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, (collected_number)d->rpackets);
333             rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, (collected_number)d->tpackets);
334             rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, (collected_number)d->rmulticast);
335             rrdset_done(d->st_packets);
336         }
337
338         // --------------------------------------------------------------------
339
340         if(unlikely((d->do_errors == CONFIG_BOOLEAN_AUTO && (d->rerrors || d->terrors))))
341             d->do_errors = CONFIG_BOOLEAN_YES;
342
343         if(d->do_errors == CONFIG_BOOLEAN_YES) {
344             if(unlikely(!d->st_errors)) {
345
346                 d->st_errors = rrdset_create_localhost(
347                         "net_errors"
348                         , d->name
349                         , NULL
350                         , d->name
351                         , "net.errors"
352                         , "Interface Errors"
353                         , "errors/s"
354                         , 7002
355                         , update_every
356                         , RRDSET_TYPE_LINE
357                 );
358
359                 rrdset_flag_set(d->st_errors, RRDSET_FLAG_DETAIL);
360
361                 d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
362                 d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
363             }
364             else rrdset_next(d->st_errors);
365
366             rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, (collected_number)d->rerrors);
367             rrddim_set_by_pointer(d->st_errors, d->rd_terrors, (collected_number)d->terrors);
368             rrdset_done(d->st_errors);
369         }
370
371         // --------------------------------------------------------------------
372
373         if(unlikely((d->do_drops == CONFIG_BOOLEAN_AUTO && (d->rdrops || d->tdrops))))
374             d->do_drops = CONFIG_BOOLEAN_YES;
375
376         if(d->do_drops == CONFIG_BOOLEAN_YES) {
377             if(unlikely(!d->st_drops)) {
378
379                 d->st_drops = rrdset_create_localhost(
380                         "net_drops"
381                         , d->name
382                         , NULL
383                         , d->name
384                         , "net.drops"
385                         , "Interface Drops"
386                         , "drops/s"
387                         , 7003
388                         , update_every
389                         , RRDSET_TYPE_LINE
390                 );
391
392                 rrdset_flag_set(d->st_drops, RRDSET_FLAG_DETAIL);
393
394                 d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
395                 d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
396             }
397             else rrdset_next(d->st_drops);
398
399             rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, (collected_number)d->rdrops);
400             rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, (collected_number)d->tdrops);
401             rrdset_done(d->st_drops);
402         }
403
404         // --------------------------------------------------------------------
405
406         if(unlikely((d->do_fifo == CONFIG_BOOLEAN_AUTO && (d->rfifo || d->tfifo))))
407             d->do_fifo = CONFIG_BOOLEAN_YES;
408
409         if(d->do_fifo == CONFIG_BOOLEAN_YES) {
410             if(unlikely(!d->st_fifo)) {
411
412                 d->st_fifo = rrdset_create_localhost(
413                         "net_fifo"
414                         , d->name
415                         , NULL
416                         , d->name
417                         , "net.fifo"
418                         , "Interface FIFO Buffer Errors"
419                         , "errors"
420                         , 7004
421                         , update_every
422                         , RRDSET_TYPE_LINE
423                 );
424
425                 rrdset_flag_set(d->st_fifo, RRDSET_FLAG_DETAIL);
426
427                 d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
428                 d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
429             }
430             else rrdset_next(d->st_fifo);
431
432             rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, (collected_number)d->rfifo);
433             rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, (collected_number)d->tfifo);
434             rrdset_done(d->st_fifo);
435         }
436
437         // --------------------------------------------------------------------
438
439         if(unlikely((d->do_compressed == CONFIG_BOOLEAN_AUTO && (d->rcompressed || d->tcompressed))))
440             d->do_compressed = CONFIG_BOOLEAN_YES;
441
442         if(d->do_compressed == CONFIG_BOOLEAN_YES) {
443             if(unlikely(!d->st_compressed)) {
444
445                 d->st_compressed = rrdset_create_localhost(
446                         "net_compressed"
447                         , d->name
448                         , NULL
449                         , d->name
450                         , "net.compressed"
451                         , "Compressed Packets"
452                         , "packets/s"
453                         , 7005
454                         , update_every
455                         , RRDSET_TYPE_LINE
456                 );
457
458                 rrdset_flag_set(d->st_compressed, RRDSET_FLAG_DETAIL);
459
460                 d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
461                 d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
462             }
463             else rrdset_next(d->st_compressed);
464
465             rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, (collected_number)d->rcompressed);
466             rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, (collected_number)d->tcompressed);
467             rrdset_done(d->st_compressed);
468         }
469
470         // --------------------------------------------------------------------
471
472         if(unlikely((d->do_events == CONFIG_BOOLEAN_AUTO && (d->rframe || d->tcollisions || d->tcarrier))))
473             d->do_events = CONFIG_BOOLEAN_YES;
474
475         if(d->do_events == CONFIG_BOOLEAN_YES) {
476             if(unlikely(!d->st_events)) {
477
478                 d->st_events = rrdset_create_localhost(
479                         "net_events"
480                         , d->name
481                         , NULL
482                         , d->name
483                         , "net.events"
484                         , "Network Interface Events"
485                         , "events/s"
486                         , 7006
487                         , update_every
488                         , RRDSET_TYPE_LINE
489                 );
490
491                 rrdset_flag_set(d->st_events, RRDSET_FLAG_DETAIL);
492
493                 d->rd_rframe      = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
494                 d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
495                 d->rd_tcarrier    = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
496             }
497             else rrdset_next(d->st_events);
498
499             rrddim_set_by_pointer(d->st_events, d->rd_rframe,      (collected_number)d->rframe);
500             rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, (collected_number)d->tcollisions);
501             rrddim_set_by_pointer(d->st_events, d->rd_tcarrier,    (collected_number)d->tcarrier);
502             rrdset_done(d->st_events);
503         }
504     }
505
506     netdev_cleanup();
507
508     return 0;
509 }