]> arthur.barton.de Git - netdata.git/blob - src/proc_net_snmp.c
properly parse dynamic columns in /proc/net/snmp; fixes #976
[netdata.git] / src / proc_net_snmp.c
1 #include "common.h"
2
3 #define RRD_TYPE_NET_SNMP           "ipv4"
4 #define RRD_TYPE_NET_SNMP_LEN       strlen(RRD_TYPE_NET_SNMP)
5
6 #define NETSTAT_PRESENT 0x00000001
7
8 struct netstat_columns {
9     char name[20];
10     uint32_t hash;
11     unsigned long long value;
12     int multiplier;     // not needed everywhere
13     RRDDIM *dimension;  // not currently used
14 };
15
16 static struct netstat_columns ip_data[] = {
17 //    { "Forwarding", 0, 0, 1, NULL },
18 //    { "DefaultTTL", 0, 0, 1, NULL },
19     { "InReceives", 0, 0, 1, NULL },
20     { "InHdrErrors", 0, 0, 1, NULL },
21     { "InAddrErrors", 0, 0, 1, NULL },
22     { "ForwDatagrams", 0, 0, 1, NULL },
23     { "InUnknownProtos", 0, 0, 1, NULL },
24     { "InDiscards", 0, 0, 1, NULL },
25     { "InDelivers", 0, 0, 1, NULL },
26     { "OutRequests", 0, 0, 1, NULL },
27     { "OutDiscards", 0, 0, 1, NULL },
28     { "OutNoRoutes", 0, 0, 1, NULL },
29 //    { "ReasmTimeout", 0, 0, 1, NULL },
30     { "ReasmReqds", 0, 0, 1, NULL },
31     { "ReasmOKs", 0, 0, 1, NULL },
32     { "ReasmFails", 0, 0, 1, NULL },
33     { "FragOKs", 0, 0, 1, NULL },
34     { "FragFails", 0, 0, 1, NULL },
35     { "FragCreates", 0, 0, 1, NULL },
36     { "", 0, 0, 0, NULL }
37 };
38
39 static struct netstat_columns icmp_data[] = {
40     { "InMsgs", 0, 0, 1, NULL },
41     { "OutMsgs", 0, 0, -1, NULL },
42     { "InErrors", 0, 0, 1, NULL },
43     { "OutErrors", 0, 0, -1, NULL },
44     { "InDestUnreachs", 0, 0, 1, NULL },
45     { "OutDestUnreachs", 0, 0, -1, NULL },
46     { "InTimeExcds", 0, 0, 1, NULL },
47     { "OutTimeExcds", 0, 0, -1, NULL },
48     { "InParmProbs", 0, 0, 1, NULL },
49     { "OutParmProbs", 0, 0, -1, NULL },
50     { "InSrcQuenchs", 0, 0, 1, NULL },
51     { "OutSrcQuenchs", 0, 0, -1, NULL },
52     { "InRedirects", 0, 0, 1, NULL },
53     { "OutRedirects", 0, 0, -1, NULL },
54     { "InEchos", 0, 0, 1, NULL },
55     { "OutEchos", 0, 0, -1, NULL },
56     { "InEchoReps", 0, 0, 1, NULL },
57     { "OutEchoReps", 0, 0, -1, NULL },
58     { "InTimestamps", 0, 0, 1, NULL },
59     { "OutTimestamps", 0, 0, -1, NULL },
60     { "InTimestampReps", 0, 0, 1, NULL },
61     { "OutTimestampReps", 0, 0, -1, NULL },
62     { "InAddrMasks", 0, 0, 1, NULL },
63     { "OutAddrMasks", 0, 0, -1, NULL },
64     { "InAddrMaskReps", 0, 0, 1, NULL },
65     { "OutAddrMaskReps", 0, 0, -1, NULL },
66     { "InCsumErrors", 0, 0, 1, NULL },
67     { "", 0, 0, 0, NULL }
68 };
69
70 static struct netstat_columns icmpmsg_data[] = {
71     { "InType0", 0, 0, 1, NULL },
72     { "OutType0", 0, 0, -1, NULL },
73     { "InType1", 0, 0, 1, NULL },
74     { "OutType1", 0, 0, -1, NULL },
75     { "InType2", 0, 0, 1, NULL },
76     { "OutType2", 0, 0, -1, NULL },
77     { "InType3", 0, 0, 1, NULL },
78     { "OutType3", 0, 0, -1, NULL },
79     { "InType4", 0, 0, 1, NULL },
80     { "OutType4", 0, 0, -1, NULL },
81     { "InType5", 0, 0, 1, NULL },
82     { "OutType5", 0, 0, -1, NULL },
83     { "InType6", 0, 0, 1, NULL },
84     { "OutType6", 0, 0, -1, NULL },
85     { "InType7", 0, 0, 1, NULL },
86     { "OutType7", 0, 0, -1, NULL },
87     { "InType8", 0, 0, 1, NULL },
88     { "OutType8", 0, 0, -1, NULL },
89     { "InType9", 0, 0, 1, NULL },
90     { "OutType9", 0, 0, -1, NULL },
91     { "InType10", 0, 0, 1, NULL },
92     { "OutType10", 0, 0, -1, NULL },
93     { "InType11", 0, 0, 1, NULL },
94     { "OutType11", 0, 0, -1, NULL },
95     { "", 0, 0, 0, NULL }
96 };
97
98 static struct netstat_columns tcp_data[] = {
99 //    { "RtoAlgorithm", 0, 0, 1, NULL },
100 //    { "RtoMin", 0, 0, 1, NULL },
101 //    { "RtoMax", 0, 0, 1, NULL },
102 //    { "MaxConn", 0, 0, 1, NULL },
103     { "ActiveOpens", 0, 0, 1, NULL },
104     { "PassiveOpens", 0, 0, 1, NULL },
105     { "AttemptFails", 0, 0, 1, NULL },
106     { "EstabResets", 0, 0, 1, NULL },
107     { "CurrEstab", 0, 0, 1, NULL },
108     { "InSegs", 0, 0, 1, NULL },
109     { "OutSegs", 0, 0, 1, NULL },
110     { "RetransSegs", 0, 0, 1, NULL },
111     { "InErrs", 0, 0, 1, NULL },
112     { "OutRsts", 0, 0, 1, NULL },
113     { "InCsumErrors", 0, 0, 1, NULL },
114     { "", 0, 0, 0, NULL }
115 };
116
117 static struct netstat_columns udp_data[] = {
118     { "InDatagrams", 0, 0, 1, NULL },
119     { "NoPorts", 0, 0, 1, NULL },
120     { "InErrors", 0, 0, 1, NULL },
121     { "OutDatagrams", 0, 0, 1, NULL },
122     { "RcvbufErrors", 0, 0, 1, NULL },
123     { "SndbufErrors", 0, 0, 1, NULL },
124     { "InCsumErrors", 0, 0, 1, NULL },
125     { "IgnoredMulti", 0, 0, 1, NULL },
126     { "", 0, 0, 0, NULL }
127 };
128
129 static struct netstat_columns udplite_data[] = {
130     { "InDatagrams", 0, 0, 1, NULL },
131     { "NoPorts", 0, 0, 1, NULL },
132     { "InErrors", 0, 0, 1, NULL },
133     { "OutDatagrams", 0, 0, 1, NULL },
134     { "RcvbufErrors", 0, 0, 1, NULL },
135     { "SndbufErrors", 0, 0, 1, NULL },
136     { "InCsumErrors", 0, 0, 1, NULL },
137     { "IgnoredMulti", 0, 0, 1, NULL },
138     { "", 0, 0, 0, NULL }
139 };
140
141 static void hash_array(struct netstat_columns *nc) {
142     int i;
143
144     for(i = 0; nc[i].name[0] ;i++)
145         nc[i].hash = simple_hash(nc[i].name);
146 }
147
148 static unsigned long long *netstat_columns_find(struct netstat_columns *nc, const char *name) {
149     uint32_t i, hash = simple_hash(name);
150
151     for(i = 0; nc[i].name[0] ;i++)
152         if(unlikely(nc[i].hash == hash && !strcmp(nc[i].name, name)))
153             return &nc[i].value;
154
155     fatal("Cannot find key '%s' in /proc/net/snmp internal array.", name);
156 }
157
158 static void parse_line_pair(procfile *ff, struct netstat_columns *nc, uint32_t header_line, uint32_t values_line) {
159     uint32_t hwords = procfile_linewords(ff, header_line);
160     uint32_t vwords = procfile_linewords(ff, values_line);
161     uint32_t w, i;
162
163     if(unlikely(vwords > hwords)) {
164         error("File /proc/net/snmp on header line %u has %u words, but on value line %u has %u words.", header_line, hwords, values_line, vwords);
165         vwords = hwords;
166     }
167
168     for(w = 1; w < vwords ;w++) {
169         char *key = procfile_lineword(ff, header_line, w);
170         uint32_t hash = simple_hash(key);
171
172         for(i = 0 ; nc[i].name[0] ;i++) {
173             if(unlikely(hash == nc[i].hash && !strcmp(key, nc[i].name))) {
174                 nc[i].value = strtoull(procfile_lineword(ff, values_line, w), NULL, 10);
175                 break;
176             }
177         }
178     }
179 }
180
181 int do_proc_net_snmp(int update_every, unsigned long long dt) {
182     (void)dt;
183
184     static procfile *ff = NULL;
185     static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
186         do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
187         do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1, do_udplite_packets = -1;
188     static uint32_t hash_ip = 0, hash_icmp = 0, hash_tcp = 0, hash_udp = 0, hash_icmpmsg = 0, hash_udplite = 0;
189
190     //static unsigned long long *ip_Forwarding = NULL;
191     //static unsigned long long *ip_DefaultTTL = NULL;
192     static unsigned long long *ip_InReceives = NULL;
193     static unsigned long long *ip_InHdrErrors = NULL;
194     static unsigned long long *ip_InAddrErrors = NULL;
195     static unsigned long long *ip_ForwDatagrams = NULL;
196     static unsigned long long *ip_InUnknownProtos = NULL;
197     static unsigned long long *ip_InDiscards = NULL;
198     static unsigned long long *ip_InDelivers = NULL;
199     static unsigned long long *ip_OutRequests = NULL;
200     static unsigned long long *ip_OutDiscards = NULL;
201     static unsigned long long *ip_OutNoRoutes = NULL;
202     //static unsigned long long *ip_ReasmTimeout = NULL;
203     static unsigned long long *ip_ReasmReqds = NULL;
204     static unsigned long long *ip_ReasmOKs = NULL;
205     static unsigned long long *ip_ReasmFails = NULL;
206     static unsigned long long *ip_FragOKs = NULL;
207     static unsigned long long *ip_FragFails = NULL;
208     static unsigned long long *ip_FragCreates = NULL;
209
210     //static unsigned long long *tcp_RtoAlgorithm = NULL;
211     //static unsigned long long *tcp_RtoMin = NULL;
212     //static unsigned long long *tcp_RtoMax = NULL;
213     //static unsigned long long *tcp_MaxConn = NULL;
214     static unsigned long long *tcp_ActiveOpens = NULL;
215     static unsigned long long *tcp_PassiveOpens = NULL;
216     static unsigned long long *tcp_AttemptFails = NULL;
217     static unsigned long long *tcp_EstabResets = NULL;
218     static unsigned long long *tcp_CurrEstab = NULL;
219     static unsigned long long *tcp_InSegs = NULL;
220     static unsigned long long *tcp_OutSegs = NULL;
221     static unsigned long long *tcp_RetransSegs = NULL;
222     static unsigned long long *tcp_InErrs = NULL;
223     static unsigned long long *tcp_OutRsts = NULL;
224     static unsigned long long *tcp_InCsumErrors = NULL;
225
226     static unsigned long long *udp_InDatagrams = NULL;
227     static unsigned long long *udp_NoPorts = NULL;
228     static unsigned long long *udp_InErrors = NULL;
229     static unsigned long long *udp_OutDatagrams = NULL;
230     static unsigned long long *udp_RcvbufErrors = NULL;
231     static unsigned long long *udp_SndbufErrors = NULL;
232     static unsigned long long *udp_InCsumErrors = NULL;
233     static unsigned long long *udp_IgnoredMulti = NULL;
234
235     static unsigned long long *udplite_InDatagrams = NULL;
236     static unsigned long long *udplite_NoPorts = NULL;
237     static unsigned long long *udplite_InErrors = NULL;
238     static unsigned long long *udplite_OutDatagrams = NULL;
239     static unsigned long long *udplite_RcvbufErrors = NULL;
240     static unsigned long long *udplite_SndbufErrors = NULL;
241     static unsigned long long *udplite_InCsumErrors = NULL;
242     static unsigned long long *udplite_IgnoredMulti = NULL;
243
244     if(unlikely(do_ip_packets == -1)) {
245         do_ip_packets       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
246         do_ip_fragsout      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
247         do_ip_fragsin       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
248         do_ip_errors        = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
249         do_tcp_sockets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
250         do_tcp_packets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
251         do_tcp_errors       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
252         do_tcp_handshake    = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
253         do_udp_packets      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
254         do_udp_errors       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
255         do_icmp_packets     = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP packets", 1);
256         do_icmpmsg          = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 ICMP messages", 1);
257         do_udplite_packets  = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDPLite packets", 1);
258
259         hash_ip = simple_hash("Ip");
260         hash_tcp = simple_hash("Tcp");
261         hash_udp = simple_hash("Udp");
262         hash_icmp = simple_hash("Icmp");
263         hash_icmpmsg = simple_hash("IcmpMsg");
264         hash_udplite = simple_hash("UdpLite");
265
266         hash_array(ip_data);
267         hash_array(tcp_data);
268         hash_array(udp_data);
269         hash_array(icmp_data);
270         hash_array(icmpmsg_data);
271         hash_array(udplite_data);
272
273         //ip_Forwarding = netstat_columns_find(ip_data, "Forwarding");
274         //ip_DefaultTTL = netstat_columns_find(ip_data, "DefaultTTL");
275         ip_InReceives = netstat_columns_find(ip_data, "InReceives");
276         ip_InHdrErrors = netstat_columns_find(ip_data, "InHdrErrors");
277         ip_InAddrErrors = netstat_columns_find(ip_data, "InAddrErrors");
278         ip_ForwDatagrams = netstat_columns_find(ip_data, "ForwDatagrams");
279         ip_InUnknownProtos = netstat_columns_find(ip_data, "InUnknownProtos");
280         ip_InDiscards = netstat_columns_find(ip_data, "InDiscards");
281         ip_InDelivers = netstat_columns_find(ip_data, "InDelivers");
282         ip_OutRequests = netstat_columns_find(ip_data, "OutRequests");
283         ip_OutDiscards = netstat_columns_find(ip_data, "OutDiscards");
284         ip_OutNoRoutes = netstat_columns_find(ip_data, "OutNoRoutes");
285         //ip_ReasmTimeout = netstat_columns_find(ip_data, "ReasmTimeout");
286         ip_ReasmReqds = netstat_columns_find(ip_data, "ReasmReqds");
287         ip_ReasmOKs = netstat_columns_find(ip_data, "ReasmOKs");
288         ip_ReasmFails = netstat_columns_find(ip_data, "ReasmFails");
289         ip_FragOKs = netstat_columns_find(ip_data, "FragOKs");
290         ip_FragFails = netstat_columns_find(ip_data, "FragFails");
291         ip_FragCreates = netstat_columns_find(ip_data, "FragCreates");
292
293         //tcp_RtoAlgorithm = netstat_columns_find(tcp_data, "RtoAlgorithm");
294         //tcp_RtoMin = netstat_columns_find(tcp_data, "RtoMin");
295         //tcp_RtoMax = netstat_columns_find(tcp_data, "RtoMax");
296         //tcp_MaxConn = netstat_columns_find(tcp_data, "MaxConn");
297         tcp_ActiveOpens = netstat_columns_find(tcp_data, "ActiveOpens");
298         tcp_PassiveOpens = netstat_columns_find(tcp_data, "PassiveOpens");
299         tcp_AttemptFails = netstat_columns_find(tcp_data, "AttemptFails");
300         tcp_EstabResets = netstat_columns_find(tcp_data, "EstabResets");
301         tcp_CurrEstab = netstat_columns_find(tcp_data, "CurrEstab");
302         tcp_InSegs = netstat_columns_find(tcp_data, "InSegs");
303         tcp_OutSegs = netstat_columns_find(tcp_data, "OutSegs");
304         tcp_RetransSegs = netstat_columns_find(tcp_data, "RetransSegs");
305         tcp_InErrs = netstat_columns_find(tcp_data, "InErrs");
306         tcp_OutRsts = netstat_columns_find(tcp_data, "OutRsts");
307         tcp_InCsumErrors = netstat_columns_find(tcp_data, "InCsumErrors");
308
309         udp_InDatagrams = netstat_columns_find(udp_data, "InDatagrams");
310         udp_NoPorts = netstat_columns_find(udp_data, "NoPorts");
311         udp_InErrors = netstat_columns_find(udp_data, "InErrors");
312         udp_OutDatagrams = netstat_columns_find(udp_data, "OutDatagrams");
313         udp_RcvbufErrors = netstat_columns_find(udp_data, "RcvbufErrors");
314         udp_SndbufErrors = netstat_columns_find(udp_data, "SndbufErrors");
315         udp_InCsumErrors = netstat_columns_find(udp_data, "InCsumErrors");
316         udp_IgnoredMulti = netstat_columns_find(udp_data, "IgnoredMulti");
317
318         udplite_InDatagrams = netstat_columns_find(udplite_data, "InDatagrams");
319         udplite_NoPorts = netstat_columns_find(udplite_data, "NoPorts");
320         udplite_InErrors = netstat_columns_find(udplite_data, "InErrors");
321         udplite_OutDatagrams = netstat_columns_find(udplite_data, "OutDatagrams");
322         udplite_RcvbufErrors = netstat_columns_find(udplite_data, "RcvbufErrors");
323         udplite_SndbufErrors = netstat_columns_find(udplite_data, "SndbufErrors");
324         udplite_InCsumErrors = netstat_columns_find(udplite_data, "InCsumErrors");
325         udplite_IgnoredMulti = netstat_columns_find(udplite_data, "IgnoredMulti");
326     }
327
328     if(unlikely(!ff)) {
329         char filename[FILENAME_MAX + 1];
330         snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
331         ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
332     }
333     if(unlikely(!ff)) return 1;
334
335     ff = procfile_readall(ff);
336     if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
337
338     uint32_t lines = procfile_lines(ff), l;
339     uint32_t words;
340
341     RRDSET *st;
342
343     for(l = 0; l < lines ;l++) {
344         char *key = procfile_lineword(ff, l, 0);
345         uint32_t hash = simple_hash(key);
346
347         if(unlikely(hash == hash_ip && strcmp(key, "Ip") == 0)) {
348             uint32_t h = l++;
349
350             if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
351                 error("Cannot read Ip line from /proc/net/snmp.");
352                 break;
353             }
354
355             words = procfile_linewords(ff, l);
356             if(words < 3) {
357                 error("Cannot read /proc/net/snmp Ip line. Expected 3+ params, read %u.", words);
358                 continue;
359             }
360
361             // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
362             parse_line_pair(ff, ip_data, h, l);
363
364             // --------------------------------------------------------------------
365
366             if(do_ip_packets) {
367                 st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
368                 if(!st) {
369                     st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
370
371                     rrddim_add(st, "received",  NULL, 1, 1, RRDDIM_INCREMENTAL);
372                     rrddim_add(st, "sent",      NULL, -1, 1, RRDDIM_INCREMENTAL);
373                     rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
374                     rrddim_add(st, "delivered", NULL, 1, 1, RRDDIM_INCREMENTAL);
375                 }
376                 else rrdset_next(st);
377
378                 rrddim_set(st, "sent",      *ip_OutRequests);
379                 rrddim_set(st, "received",  *ip_InReceives);
380                 rrddim_set(st, "forwarded", *ip_ForwDatagrams);
381                 rrddim_set(st, "delivered", *ip_InDelivers);
382                 rrdset_done(st);
383             }
384
385             // --------------------------------------------------------------------
386
387             if(do_ip_fragsout) {
388                 st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
389                 if(!st) {
390                     st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
391                     st->isdetail = 1;
392
393                     rrddim_add(st, "ok",     NULL, 1, 1, RRDDIM_INCREMENTAL);
394                     rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
395                     rrddim_add(st, "all",    NULL, 1, 1, RRDDIM_INCREMENTAL);
396                 }
397                 else rrdset_next(st);
398
399                 rrddim_set(st, "ok",     *ip_FragOKs);
400                 rrddim_set(st, "failed", *ip_FragFails);
401                 rrddim_set(st, "all",    *ip_FragCreates);
402                 rrdset_done(st);
403             }
404
405             // --------------------------------------------------------------------
406
407             if(do_ip_fragsin) {
408                 st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
409                 if(!st) {
410                     st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
411                     st->isdetail = 1;
412
413                     rrddim_add(st, "ok",     NULL, 1, 1, RRDDIM_INCREMENTAL);
414                     rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
415                     rrddim_add(st, "all",    NULL, 1, 1, RRDDIM_INCREMENTAL);
416                 }
417                 else rrdset_next(st);
418
419                 rrddim_set(st, "ok",     *ip_ReasmOKs);
420                 rrddim_set(st, "failed", *ip_ReasmFails);
421                 rrddim_set(st, "all",    *ip_ReasmReqds);
422                 rrdset_done(st);
423             }
424
425             // --------------------------------------------------------------------
426
427             if(do_ip_errors) {
428                 st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
429                 if(!st) {
430                     st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
431                     st->isdetail = 1;
432
433                     rrddim_add(st, "InDiscards",      NULL, 1, 1, RRDDIM_INCREMENTAL);
434                     rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRDDIM_INCREMENTAL);
435
436                     rrddim_add(st, "InHdrErrors",     NULL, 1, 1, RRDDIM_INCREMENTAL);
437                     rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRDDIM_INCREMENTAL);
438
439                     rrddim_add(st, "InAddrErrors",    NULL, 1, 1, RRDDIM_INCREMENTAL);
440                     rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
441                 }
442                 else rrdset_next(st);
443
444                 rrddim_set(st, "InDiscards",      *ip_InDiscards);
445                 rrddim_set(st, "OutDiscards",     *ip_OutDiscards);
446                 rrddim_set(st, "InHdrErrors",     *ip_InHdrErrors);
447                 rrddim_set(st, "InAddrErrors",    *ip_InAddrErrors);
448                 rrddim_set(st, "InUnknownProtos", *ip_InUnknownProtos);
449                 rrddim_set(st, "OutNoRoutes",     *ip_OutNoRoutes);
450                 rrdset_done(st);
451             }
452         }
453         else if(unlikely(hash == hash_icmp && strcmp(key, "Icmp") == 0)) {
454             uint32_t h = l++;
455
456             if(strcmp(procfile_lineword(ff, l, 0), "Icmp") != 0) {
457                 error("Cannot read Icmp line from /proc/net/snmp.");
458                 break;
459             }
460
461             words = procfile_linewords(ff, l);
462             if(words < 3) {
463                 error("Cannot read /proc/net/snmp Icmp line. Expected 3+ params, read %u.", words);
464                 continue;
465             }
466
467             parse_line_pair(ff, icmp_data, h, l);
468
469             // --------------------------------------------------------------------
470
471             if(do_icmp_packets) {
472                 int i;
473
474                 st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp");
475                 if(!st) {
476                     st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
477
478                     for(i = 0; icmp_data[i].name[0] ;i++)
479                         rrddim_add(st, icmp_data[i].name,  NULL,  icmp_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
480                 }
481                 else rrdset_next(st);
482
483                 for(i = 0; icmp_data[i].name[0] ;i++)
484                     rrddim_set(st, icmp_data[i].name, icmp_data[i].value);
485
486                 rrdset_done(st);
487             }
488         }
489         else if(unlikely(hash == hash_icmpmsg && strcmp(key, "IcmpMsg") == 0)) {
490             uint32_t h = l++;
491
492             if(strcmp(procfile_lineword(ff, l, 0), "IcmpMsg") != 0) {
493                 error("Cannot read IcmpMsg line from /proc/net/snmp.");
494                 break;
495             }
496
497             parse_line_pair(ff, icmpmsg_data, h, l);
498
499             // --------------------------------------------------------------------
500
501             if(do_icmpmsg) {
502                 int i;
503
504                 st = rrdset_find(RRD_TYPE_NET_SNMP ".icmpmsg");
505                 if(!st) {
506                     st = rrdset_create(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
507
508                     for(i = 0; icmpmsg_data[i].name[0] ;i++)
509                         rrddim_add(st, icmpmsg_data[i].name,  NULL,  icmpmsg_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
510                 }
511                 else rrdset_next(st);
512
513                 for(i = 0; icmpmsg_data[i].name[0] ;i++)
514                     rrddim_set(st, icmpmsg_data[i].name, icmpmsg_data[i].value);
515
516                 rrdset_done(st);
517             }
518         }
519         else if(unlikely(hash == hash_tcp && strcmp(key, "Tcp") == 0)) {
520             uint32_t h = l++;
521
522             if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
523                 error("Cannot read Tcp line from /proc/net/snmp.");
524                 break;
525             }
526
527             words = procfile_linewords(ff, l);
528             if(words < 3) {
529                 error("Cannot read /proc/net/snmp Tcp line. Expected 3+ params, read %u.", words);
530                 continue;
531             }
532
533             parse_line_pair(ff, tcp_data, h, l);
534
535             // --------------------------------------------------------------------
536
537             // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
538             if(do_tcp_sockets) {
539                 st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
540                 if(!st) {
541                     st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
542
543                     rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
544                 }
545                 else rrdset_next(st);
546
547                 rrddim_set(st, "connections", *tcp_CurrEstab);
548                 rrdset_done(st);
549             }
550
551             // --------------------------------------------------------------------
552
553             if(do_tcp_packets) {
554                 st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
555                 if(!st) {
556                     st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
557
558                     rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
559                     rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
560                 }
561                 else rrdset_next(st);
562
563                 rrddim_set(st, "received", *tcp_InSegs);
564                 rrddim_set(st, "sent", *tcp_OutSegs);
565                 rrdset_done(st);
566             }
567
568             // --------------------------------------------------------------------
569
570             if(do_tcp_errors) {
571                 st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
572                 if(!st) {
573                     st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
574                     st->isdetail = 1;
575
576                     rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
577                     rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
578                     rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
579                 }
580                 else rrdset_next(st);
581
582                 rrddim_set(st, "InErrs", *tcp_InErrs);
583                 rrddim_set(st, "InCsumErrors", *tcp_InCsumErrors);
584                 rrddim_set(st, "RetransSegs", *tcp_RetransSegs);
585                 rrdset_done(st);
586             }
587
588             // --------------------------------------------------------------------
589
590             if(do_tcp_handshake) {
591                 st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
592                 if(!st) {
593                     st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
594                     st->isdetail = 1;
595
596                     rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
597                     rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
598                     rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
599                     rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
600                     rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
601                 }
602                 else rrdset_next(st);
603
604                 rrddim_set(st, "EstabResets", *tcp_EstabResets);
605                 rrddim_set(st, "OutRsts", *tcp_OutRsts);
606                 rrddim_set(st, "ActiveOpens", *tcp_ActiveOpens);
607                 rrddim_set(st, "PassiveOpens", *tcp_PassiveOpens);
608                 rrddim_set(st, "AttemptFails", *tcp_AttemptFails);
609                 rrdset_done(st);
610             }
611         }
612         else if(unlikely(hash == hash_udp && strcmp(key, "Udp") == 0)) {
613             uint32_t h = l++;
614
615             if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
616                 error("Cannot read Udp line from /proc/net/snmp.");
617                 break;
618             }
619
620             words = procfile_linewords(ff, l);
621             if(words < 3) {
622                 error("Cannot read /proc/net/snmp Udp line. Expected 3+ params, read %u.", words);
623                 continue;
624             }
625
626             parse_line_pair(ff, udp_data, h, l);
627
628             // --------------------------------------------------------------------
629
630             // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
631             if(do_udp_packets) {
632                 st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
633                 if(!st) {
634                     st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
635
636                     rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
637                     rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
638                 }
639                 else rrdset_next(st);
640
641                 rrddim_set(st, "received", *udp_InDatagrams);
642                 rrddim_set(st, "sent", *udp_OutDatagrams);
643                 rrdset_done(st);
644             }
645
646             // --------------------------------------------------------------------
647
648             if(do_udp_errors) {
649                 st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
650                 if(!st) {
651                     st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
652                     st->isdetail = 1;
653
654                     rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
655                     rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
656                     rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
657                     rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
658                     rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
659                     rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
660                 }
661                 else rrdset_next(st);
662
663                 rrddim_set(st, "InErrors", *udp_InErrors);
664                 rrddim_set(st, "NoPorts", *udp_NoPorts);
665                 rrddim_set(st, "RcvbufErrors", *udp_RcvbufErrors);
666                 rrddim_set(st, "SndbufErrors", *udp_SndbufErrors);
667                 rrddim_set(st, "InCsumErrors", *udp_InCsumErrors);
668                 rrddim_set(st, "IgnoredMulti", *udp_IgnoredMulti);
669                 rrdset_done(st);
670             }
671         }
672         else if(unlikely(hash == hash_udplite && strcmp(key, "UdpLite") == 0)) {
673             uint32_t h = l++;
674
675             if(strcmp(procfile_lineword(ff, l, 0), "UdpLite") != 0) {
676                 error("Cannot read UdpLite line from /proc/net/snmp.");
677                 break;
678             }
679
680             words = procfile_linewords(ff, l);
681             if(words < 3) {
682                 error("Cannot read /proc/net/snmp UdpLite line. Expected 3+ params, read %u.", words);
683                 continue;
684             }
685
686             parse_line_pair(ff, udplite_data, h, l);
687
688             // --------------------------------------------------------------------
689
690             if(do_udplite_packets) {
691                 st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite");
692                 if(!st) {
693                     st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite", NULL, "udplite", NULL, "IPv4 UDPLite Packets", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
694
695                     rrddim_add(st, "InDatagrams", NULL, 1, 1, RRDDIM_INCREMENTAL);
696                     rrddim_add(st, "OutDatagrams", NULL, -1, 1, RRDDIM_INCREMENTAL);
697                 }
698                 else rrdset_next(st);
699
700                 rrddim_set(st, "InDatagrams", *udplite_InDatagrams);
701                 rrddim_set(st, "OutDatagrams", *udplite_OutDatagrams);
702                 rrdset_done(st);
703
704                 st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite_errors");
705                 if(!st) {
706                     st = rrdset_create(RRD_TYPE_NET_SNMP, "udplite_errors", NULL, "udplite", NULL, "IPv4 UDPLite Errors", "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
707
708                     rrddim_add(st, "RcvbufErrors", NULL,  1, 1, RRDDIM_INCREMENTAL);
709                     rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
710                     rrddim_add(st, "NoPorts",      NULL,  1, 1, RRDDIM_INCREMENTAL);
711                     rrddim_add(st, "IgnoredMulti", NULL,  1, 1, RRDDIM_INCREMENTAL);
712                     rrddim_add(st, "InErrors",     NULL,  1, 1, RRDDIM_INCREMENTAL);
713                     rrddim_add(st, "InCsumErrors", NULL,  1, 1, RRDDIM_INCREMENTAL);
714                 }
715                 else rrdset_next(st);
716
717                 rrddim_set(st, "NoPorts", *udplite_NoPorts);
718                 rrddim_set(st, "InErrors", *udplite_InErrors);
719                 rrddim_set(st, "InCsumErrors", *udplite_InCsumErrors);
720                 rrddim_set(st, "RcvbufErrors", *udplite_RcvbufErrors);
721                 rrddim_set(st, "SndbufErrors", *udplite_SndbufErrors);
722                 rrddim_set(st, "IgnoredMulti", *udplite_IgnoredMulti);
723                 rrdset_done(st);
724             }
725         }
726     }
727
728     return 0;
729 }
730