]> arthur.barton.de Git - netdata.git/commitdiff
properly parse dynamic columns in /proc/net/snmp; fixes #976
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sun, 18 Sep 2016 00:13:36 +0000 (03:13 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Sun, 18 Sep 2016 00:13:36 +0000 (03:13 +0300)
src/proc_net_snmp.c

index 0d8674983a6df2c7cd5f58f7152f26ec61749619..8b58d85eda85cd13727cd6665be9371cd82136a9 100644 (file)
@@ -3,6 +3,181 @@
 #define RRD_TYPE_NET_SNMP           "ipv4"
 #define RRD_TYPE_NET_SNMP_LEN       strlen(RRD_TYPE_NET_SNMP)
 
+#define NETSTAT_PRESENT 0x00000001
+
+struct netstat_columns {
+    char name[20];
+    uint32_t hash;
+    unsigned long long value;
+    int multiplier;     // not needed everywhere
+    RRDDIM *dimension;  // not currently used
+};
+
+static struct netstat_columns ip_data[] = {
+//    { "Forwarding", 0, 0, 1, NULL },
+//    { "DefaultTTL", 0, 0, 1, NULL },
+    { "InReceives", 0, 0, 1, NULL },
+    { "InHdrErrors", 0, 0, 1, NULL },
+    { "InAddrErrors", 0, 0, 1, NULL },
+    { "ForwDatagrams", 0, 0, 1, NULL },
+    { "InUnknownProtos", 0, 0, 1, NULL },
+    { "InDiscards", 0, 0, 1, NULL },
+    { "InDelivers", 0, 0, 1, NULL },
+    { "OutRequests", 0, 0, 1, NULL },
+    { "OutDiscards", 0, 0, 1, NULL },
+    { "OutNoRoutes", 0, 0, 1, NULL },
+//    { "ReasmTimeout", 0, 0, 1, NULL },
+    { "ReasmReqds", 0, 0, 1, NULL },
+    { "ReasmOKs", 0, 0, 1, NULL },
+    { "ReasmFails", 0, 0, 1, NULL },
+    { "FragOKs", 0, 0, 1, NULL },
+    { "FragFails", 0, 0, 1, NULL },
+    { "FragCreates", 0, 0, 1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static struct netstat_columns icmp_data[] = {
+    { "InMsgs", 0, 0, 1, NULL },
+    { "OutMsgs", 0, 0, -1, NULL },
+    { "InErrors", 0, 0, 1, NULL },
+    { "OutErrors", 0, 0, -1, NULL },
+    { "InDestUnreachs", 0, 0, 1, NULL },
+    { "OutDestUnreachs", 0, 0, -1, NULL },
+    { "InTimeExcds", 0, 0, 1, NULL },
+    { "OutTimeExcds", 0, 0, -1, NULL },
+    { "InParmProbs", 0, 0, 1, NULL },
+    { "OutParmProbs", 0, 0, -1, NULL },
+    { "InSrcQuenchs", 0, 0, 1, NULL },
+    { "OutSrcQuenchs", 0, 0, -1, NULL },
+    { "InRedirects", 0, 0, 1, NULL },
+    { "OutRedirects", 0, 0, -1, NULL },
+    { "InEchos", 0, 0, 1, NULL },
+    { "OutEchos", 0, 0, -1, NULL },
+    { "InEchoReps", 0, 0, 1, NULL },
+    { "OutEchoReps", 0, 0, -1, NULL },
+    { "InTimestamps", 0, 0, 1, NULL },
+    { "OutTimestamps", 0, 0, -1, NULL },
+    { "InTimestampReps", 0, 0, 1, NULL },
+    { "OutTimestampReps", 0, 0, -1, NULL },
+    { "InAddrMasks", 0, 0, 1, NULL },
+    { "OutAddrMasks", 0, 0, -1, NULL },
+    { "InAddrMaskReps", 0, 0, 1, NULL },
+    { "OutAddrMaskReps", 0, 0, -1, NULL },
+    { "InCsumErrors", 0, 0, 1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static struct netstat_columns icmpmsg_data[] = {
+    { "InType0", 0, 0, 1, NULL },
+    { "OutType0", 0, 0, -1, NULL },
+    { "InType1", 0, 0, 1, NULL },
+    { "OutType1", 0, 0, -1, NULL },
+    { "InType2", 0, 0, 1, NULL },
+    { "OutType2", 0, 0, -1, NULL },
+    { "InType3", 0, 0, 1, NULL },
+    { "OutType3", 0, 0, -1, NULL },
+    { "InType4", 0, 0, 1, NULL },
+    { "OutType4", 0, 0, -1, NULL },
+    { "InType5", 0, 0, 1, NULL },
+    { "OutType5", 0, 0, -1, NULL },
+    { "InType6", 0, 0, 1, NULL },
+    { "OutType6", 0, 0, -1, NULL },
+    { "InType7", 0, 0, 1, NULL },
+    { "OutType7", 0, 0, -1, NULL },
+    { "InType8", 0, 0, 1, NULL },
+    { "OutType8", 0, 0, -1, NULL },
+    { "InType9", 0, 0, 1, NULL },
+    { "OutType9", 0, 0, -1, NULL },
+    { "InType10", 0, 0, 1, NULL },
+    { "OutType10", 0, 0, -1, NULL },
+    { "InType11", 0, 0, 1, NULL },
+    { "OutType11", 0, 0, -1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static struct netstat_columns tcp_data[] = {
+//    { "RtoAlgorithm", 0, 0, 1, NULL },
+//    { "RtoMin", 0, 0, 1, NULL },
+//    { "RtoMax", 0, 0, 1, NULL },
+//    { "MaxConn", 0, 0, 1, NULL },
+    { "ActiveOpens", 0, 0, 1, NULL },
+    { "PassiveOpens", 0, 0, 1, NULL },
+    { "AttemptFails", 0, 0, 1, NULL },
+    { "EstabResets", 0, 0, 1, NULL },
+    { "CurrEstab", 0, 0, 1, NULL },
+    { "InSegs", 0, 0, 1, NULL },
+    { "OutSegs", 0, 0, 1, NULL },
+    { "RetransSegs", 0, 0, 1, NULL },
+    { "InErrs", 0, 0, 1, NULL },
+    { "OutRsts", 0, 0, 1, NULL },
+    { "InCsumErrors", 0, 0, 1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static struct netstat_columns udp_data[] = {
+    { "InDatagrams", 0, 0, 1, NULL },
+    { "NoPorts", 0, 0, 1, NULL },
+    { "InErrors", 0, 0, 1, NULL },
+    { "OutDatagrams", 0, 0, 1, NULL },
+    { "RcvbufErrors", 0, 0, 1, NULL },
+    { "SndbufErrors", 0, 0, 1, NULL },
+    { "InCsumErrors", 0, 0, 1, NULL },
+    { "IgnoredMulti", 0, 0, 1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static struct netstat_columns udplite_data[] = {
+    { "InDatagrams", 0, 0, 1, NULL },
+    { "NoPorts", 0, 0, 1, NULL },
+    { "InErrors", 0, 0, 1, NULL },
+    { "OutDatagrams", 0, 0, 1, NULL },
+    { "RcvbufErrors", 0, 0, 1, NULL },
+    { "SndbufErrors", 0, 0, 1, NULL },
+    { "InCsumErrors", 0, 0, 1, NULL },
+    { "IgnoredMulti", 0, 0, 1, NULL },
+    { "", 0, 0, 0, NULL }
+};
+
+static void hash_array(struct netstat_columns *nc) {
+    int i;
+
+    for(i = 0; nc[i].name[0] ;i++)
+        nc[i].hash = simple_hash(nc[i].name);
+}
+
+static unsigned long long *netstat_columns_find(struct netstat_columns *nc, const char *name) {
+    uint32_t i, hash = simple_hash(name);
+
+    for(i = 0; nc[i].name[0] ;i++)
+        if(unlikely(nc[i].hash == hash && !strcmp(nc[i].name, name)))
+            return &nc[i].value;
+
+    fatal("Cannot find key '%s' in /proc/net/snmp internal array.", name);
+}
+
+static void parse_line_pair(procfile *ff, struct netstat_columns *nc, uint32_t header_line, uint32_t values_line) {
+    uint32_t hwords = procfile_linewords(ff, header_line);
+    uint32_t vwords = procfile_linewords(ff, values_line);
+    uint32_t w, i;
+
+    if(unlikely(vwords > hwords)) {
+        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);
+        vwords = hwords;
+    }
+
+    for(w = 1; w < vwords ;w++) {
+        char *key = procfile_lineword(ff, header_line, w);
+        uint32_t hash = simple_hash(key);
+
+        for(i = 0 ; nc[i].name[0] ;i++) {
+            if(unlikely(hash == nc[i].hash && !strcmp(key, nc[i].name))) {
+                nc[i].value = strtoull(procfile_lineword(ff, values_line, w), NULL, 10);
+                break;
+            }
+        }
+    }
+}
+
 int do_proc_net_snmp(int update_every, unsigned long long dt) {
     (void)dt;
 
@@ -12,6 +187,60 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
         do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1, do_udplite_packets = -1;
     static uint32_t hash_ip = 0, hash_icmp = 0, hash_tcp = 0, hash_udp = 0, hash_icmpmsg = 0, hash_udplite = 0;
 
+    //static unsigned long long *ip_Forwarding = NULL;
+    //static unsigned long long *ip_DefaultTTL = NULL;
+    static unsigned long long *ip_InReceives = NULL;
+    static unsigned long long *ip_InHdrErrors = NULL;
+    static unsigned long long *ip_InAddrErrors = NULL;
+    static unsigned long long *ip_ForwDatagrams = NULL;
+    static unsigned long long *ip_InUnknownProtos = NULL;
+    static unsigned long long *ip_InDiscards = NULL;
+    static unsigned long long *ip_InDelivers = NULL;
+    static unsigned long long *ip_OutRequests = NULL;
+    static unsigned long long *ip_OutDiscards = NULL;
+    static unsigned long long *ip_OutNoRoutes = NULL;
+    //static unsigned long long *ip_ReasmTimeout = NULL;
+    static unsigned long long *ip_ReasmReqds = NULL;
+    static unsigned long long *ip_ReasmOKs = NULL;
+    static unsigned long long *ip_ReasmFails = NULL;
+    static unsigned long long *ip_FragOKs = NULL;
+    static unsigned long long *ip_FragFails = NULL;
+    static unsigned long long *ip_FragCreates = NULL;
+
+    //static unsigned long long *tcp_RtoAlgorithm = NULL;
+    //static unsigned long long *tcp_RtoMin = NULL;
+    //static unsigned long long *tcp_RtoMax = NULL;
+    //static unsigned long long *tcp_MaxConn = NULL;
+    static unsigned long long *tcp_ActiveOpens = NULL;
+    static unsigned long long *tcp_PassiveOpens = NULL;
+    static unsigned long long *tcp_AttemptFails = NULL;
+    static unsigned long long *tcp_EstabResets = NULL;
+    static unsigned long long *tcp_CurrEstab = NULL;
+    static unsigned long long *tcp_InSegs = NULL;
+    static unsigned long long *tcp_OutSegs = NULL;
+    static unsigned long long *tcp_RetransSegs = NULL;
+    static unsigned long long *tcp_InErrs = NULL;
+    static unsigned long long *tcp_OutRsts = NULL;
+    static unsigned long long *tcp_InCsumErrors = NULL;
+
+    static unsigned long long *udp_InDatagrams = NULL;
+    static unsigned long long *udp_NoPorts = NULL;
+    static unsigned long long *udp_InErrors = NULL;
+    static unsigned long long *udp_OutDatagrams = NULL;
+    static unsigned long long *udp_RcvbufErrors = NULL;
+    static unsigned long long *udp_SndbufErrors = NULL;
+    static unsigned long long *udp_InCsumErrors = NULL;
+    static unsigned long long *udp_IgnoredMulti = NULL;
+
+    static unsigned long long *udplite_InDatagrams = NULL;
+    static unsigned long long *udplite_NoPorts = NULL;
+    static unsigned long long *udplite_InErrors = NULL;
+    static unsigned long long *udplite_OutDatagrams = NULL;
+    static unsigned long long *udplite_RcvbufErrors = NULL;
+    static unsigned long long *udplite_SndbufErrors = NULL;
+    static unsigned long long *udplite_InCsumErrors = NULL;
+    static unsigned long long *udplite_IgnoredMulti = NULL;
+
     if(unlikely(do_ip_packets == -1)) {
         do_ip_packets       = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
         do_ip_fragsout      = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
@@ -33,6 +262,67 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
         hash_icmp = simple_hash("Icmp");
         hash_icmpmsg = simple_hash("IcmpMsg");
         hash_udplite = simple_hash("UdpLite");
+
+        hash_array(ip_data);
+        hash_array(tcp_data);
+        hash_array(udp_data);
+        hash_array(icmp_data);
+        hash_array(icmpmsg_data);
+        hash_array(udplite_data);
+
+        //ip_Forwarding = netstat_columns_find(ip_data, "Forwarding");
+        //ip_DefaultTTL = netstat_columns_find(ip_data, "DefaultTTL");
+        ip_InReceives = netstat_columns_find(ip_data, "InReceives");
+        ip_InHdrErrors = netstat_columns_find(ip_data, "InHdrErrors");
+        ip_InAddrErrors = netstat_columns_find(ip_data, "InAddrErrors");
+        ip_ForwDatagrams = netstat_columns_find(ip_data, "ForwDatagrams");
+        ip_InUnknownProtos = netstat_columns_find(ip_data, "InUnknownProtos");
+        ip_InDiscards = netstat_columns_find(ip_data, "InDiscards");
+        ip_InDelivers = netstat_columns_find(ip_data, "InDelivers");
+        ip_OutRequests = netstat_columns_find(ip_data, "OutRequests");
+        ip_OutDiscards = netstat_columns_find(ip_data, "OutDiscards");
+        ip_OutNoRoutes = netstat_columns_find(ip_data, "OutNoRoutes");
+        //ip_ReasmTimeout = netstat_columns_find(ip_data, "ReasmTimeout");
+        ip_ReasmReqds = netstat_columns_find(ip_data, "ReasmReqds");
+        ip_ReasmOKs = netstat_columns_find(ip_data, "ReasmOKs");
+        ip_ReasmFails = netstat_columns_find(ip_data, "ReasmFails");
+        ip_FragOKs = netstat_columns_find(ip_data, "FragOKs");
+        ip_FragFails = netstat_columns_find(ip_data, "FragFails");
+        ip_FragCreates = netstat_columns_find(ip_data, "FragCreates");
+
+        //tcp_RtoAlgorithm = netstat_columns_find(tcp_data, "RtoAlgorithm");
+        //tcp_RtoMin = netstat_columns_find(tcp_data, "RtoMin");
+        //tcp_RtoMax = netstat_columns_find(tcp_data, "RtoMax");
+        //tcp_MaxConn = netstat_columns_find(tcp_data, "MaxConn");
+        tcp_ActiveOpens = netstat_columns_find(tcp_data, "ActiveOpens");
+        tcp_PassiveOpens = netstat_columns_find(tcp_data, "PassiveOpens");
+        tcp_AttemptFails = netstat_columns_find(tcp_data, "AttemptFails");
+        tcp_EstabResets = netstat_columns_find(tcp_data, "EstabResets");
+        tcp_CurrEstab = netstat_columns_find(tcp_data, "CurrEstab");
+        tcp_InSegs = netstat_columns_find(tcp_data, "InSegs");
+        tcp_OutSegs = netstat_columns_find(tcp_data, "OutSegs");
+        tcp_RetransSegs = netstat_columns_find(tcp_data, "RetransSegs");
+        tcp_InErrs = netstat_columns_find(tcp_data, "InErrs");
+        tcp_OutRsts = netstat_columns_find(tcp_data, "OutRsts");
+        tcp_InCsumErrors = netstat_columns_find(tcp_data, "InCsumErrors");
+
+        udp_InDatagrams = netstat_columns_find(udp_data, "InDatagrams");
+        udp_NoPorts = netstat_columns_find(udp_data, "NoPorts");
+        udp_InErrors = netstat_columns_find(udp_data, "InErrors");
+        udp_OutDatagrams = netstat_columns_find(udp_data, "OutDatagrams");
+        udp_RcvbufErrors = netstat_columns_find(udp_data, "RcvbufErrors");
+        udp_SndbufErrors = netstat_columns_find(udp_data, "SndbufErrors");
+        udp_InCsumErrors = netstat_columns_find(udp_data, "InCsumErrors");
+        udp_IgnoredMulti = netstat_columns_find(udp_data, "IgnoredMulti");
+
+        udplite_InDatagrams = netstat_columns_find(udplite_data, "InDatagrams");
+        udplite_NoPorts = netstat_columns_find(udplite_data, "NoPorts");
+        udplite_InErrors = netstat_columns_find(udplite_data, "InErrors");
+        udplite_OutDatagrams = netstat_columns_find(udplite_data, "OutDatagrams");
+        udplite_RcvbufErrors = netstat_columns_find(udplite_data, "RcvbufErrors");
+        udplite_SndbufErrors = netstat_columns_find(udplite_data, "SndbufErrors");
+        udplite_InCsumErrors = netstat_columns_find(udplite_data, "InCsumErrors");
+        udplite_IgnoredMulti = netstat_columns_find(udplite_data, "IgnoredMulti");
     }
 
     if(unlikely(!ff)) {
@@ -55,7 +345,7 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
         uint32_t hash = simple_hash(key);
 
         if(unlikely(hash == hash_ip && strcmp(key, "Ip") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
                 error("Cannot read Ip line from /proc/net/snmp.");
@@ -63,39 +353,13 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
             }
 
             words = procfile_linewords(ff, l);
-            if(words < 20) {
-                error("Cannot read /proc/net/snmp Ip line. Expected 20 params, read %u.", words);
+            if(words < 3) {
+                error("Cannot read /proc/net/snmp Ip line. Expected 3+ params, read %u.", words);
                 continue;
             }
 
             // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
-            unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
-                OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
-
-            //Forwarding      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            //DefaultTTL      = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            InReceives      = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            InHdrErrors     = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            InAddrErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            ForwDatagrams   = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-            InUnknownProtos = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-            InDiscards      = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-            InDelivers      = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-            OutRequests     = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-            OutDiscards     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-            OutNoRoutes     = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-            //ReasmTimeout    = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-            ReasmReqds      = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-            ReasmOKs        = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
-            ReasmFails      = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
-            FragOKs         = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
-            FragFails       = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
-            FragCreates     = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
-
-            // these are not counters
-            (void)Forwarding;      // is forwarding enabled?
-            (void)DefaultTTL;      // the default ttl on packets
-            (void)ReasmTimeout;    // Reassembly timeout
+            parse_line_pair(ff, ip_data, h, l);
 
             // --------------------------------------------------------------------
 
@@ -104,17 +368,17 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 if(!st) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "received",  NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent",      NULL, -1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "delivered", NULL, 1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "sent", OutRequests);
-                rrddim_set(st, "received", InReceives);
-                rrddim_set(st, "forwarded", ForwDatagrams);
-                rrddim_set(st, "delivered", InDelivers);
+                rrddim_set(st, "sent",      *ip_OutRequests);
+                rrddim_set(st, "received",  *ip_InReceives);
+                rrddim_set(st, "forwarded", *ip_ForwDatagrams);
+                rrddim_set(st, "delivered", *ip_InDelivers);
                 rrdset_done(st);
             }
 
@@ -126,15 +390,15 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
                     st->isdetail = 1;
 
-                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ok",     NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all",    NULL, 1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "ok", FragOKs);
-                rrddim_set(st, "failed", FragFails);
-                rrddim_set(st, "all", FragCreates);
+                rrddim_set(st, "ok",     *ip_FragOKs);
+                rrddim_set(st, "failed", *ip_FragFails);
+                rrddim_set(st, "all",    *ip_FragCreates);
                 rrdset_done(st);
             }
 
@@ -146,15 +410,15 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
                     st->isdetail = 1;
 
-                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ok",     NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all",    NULL, 1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "ok", ReasmOKs);
-                rrddim_set(st, "failed", ReasmFails);
-                rrddim_set(st, "all", ReasmReqds);
+                rrddim_set(st, "ok",     *ip_ReasmOKs);
+                rrddim_set(st, "failed", *ip_ReasmFails);
+                rrddim_set(st, "all",    *ip_ReasmReqds);
                 rrdset_done(st);
             }
 
@@ -166,28 +430,28 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
                     st->isdetail = 1;
 
-                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InDiscards",      NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRDDIM_INCREMENTAL);
 
-                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InHdrErrors",     NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRDDIM_INCREMENTAL);
 
-                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InAddrErrors",    NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InDiscards", InDiscards);
-                rrddim_set(st, "OutDiscards", OutDiscards);
-                rrddim_set(st, "InHdrErrors", InHdrErrors);
-                rrddim_set(st, "InAddrErrors", InAddrErrors);
-                rrddim_set(st, "InUnknownProtos", InUnknownProtos);
-                rrddim_set(st, "OutNoRoutes", OutNoRoutes);
+                rrddim_set(st, "InDiscards",      *ip_InDiscards);
+                rrddim_set(st, "OutDiscards",     *ip_OutDiscards);
+                rrddim_set(st, "InHdrErrors",     *ip_InHdrErrors);
+                rrddim_set(st, "InAddrErrors",    *ip_InAddrErrors);
+                rrddim_set(st, "InUnknownProtos", *ip_InUnknownProtos);
+                rrddim_set(st, "OutNoRoutes",     *ip_OutNoRoutes);
                 rrdset_done(st);
             }
         }
         else if(unlikely(hash == hash_icmp && strcmp(key, "Icmp") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "Icmp") != 0) {
                 error("Cannot read Icmp line from /proc/net/snmp.");
@@ -195,197 +459,65 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
             }
 
             words = procfile_linewords(ff, l);
-            if(words < 28) {
-                error("Cannot read /proc/net/snmp Icmp line. Expected 28 params, read %u.", words);
+            if(words < 3) {
+                error("Cannot read /proc/net/snmp Icmp line. Expected 3+ params, read %u.", words);
                 continue;
             }
 
-            unsigned long long InMsgs, InErrors, InCsumErrors, InDestUnreachs, InTimeExcds, InParmProbs, InSrcQuenchs, InRedirects, InEchos,
-                InEchoReps, InTimestamps, InTimestampReps, InAddrMasks, InAddrMaskReps, OutMsgs, OutErrors, OutDestUnreachs, OutTimeExcds,
-                OutParmProbs, OutSrcQuenchs, OutRedirects, OutEchos, OutEchoReps, OutTimestamps, OutTimestampReps, OutAddrMasks, OutAddrMaskReps;
-
-            InMsgs           = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            InErrors         = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            InCsumErrors     = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            InDestUnreachs   = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            InTimeExcds      = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            InParmProbs      = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-            InSrcQuenchs     = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-            InRedirects      = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-            InEchos          = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-            InEchoReps       = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-            InTimestamps     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-            InTimestampReps  = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-            InAddrMasks      = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-            InAddrMaskReps   = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-
-            OutMsgs          = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
-            OutErrors        = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
-            OutDestUnreachs  = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
-            OutTimeExcds     = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
-            OutParmProbs     = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
-            OutSrcQuenchs    = strtoull(procfile_lineword(ff, l, 20), NULL, 10);
-            OutRedirects     = strtoull(procfile_lineword(ff, l, 21), NULL, 10);
-            OutEchos         = strtoull(procfile_lineword(ff, l, 22), NULL, 10);
-            OutEchoReps      = strtoull(procfile_lineword(ff, l, 23), NULL, 10);
-            OutTimestamps    = strtoull(procfile_lineword(ff, l, 24), NULL, 10);
-            OutTimestampReps = strtoull(procfile_lineword(ff, l, 25), NULL, 10);
-            OutAddrMasks     = strtoull(procfile_lineword(ff, l, 26), NULL, 10);
-            OutAddrMaskReps  = strtoull(procfile_lineword(ff, l, 27), NULL, 10);
+            parse_line_pair(ff, icmp_data, h, l);
 
             // --------------------------------------------------------------------
 
             if(do_icmp_packets) {
+                int i;
+
                 st = rrdset_find(RRD_TYPE_NET_SNMP ".icmp");
                 if(!st) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s", 2602, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InMsgs",           NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutMsgs",          NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InErrors",         NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutErrors",        NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InDestUnreachs",   NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutDestUnreachs",  NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InTimeExcds",      NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutTimeExcds",     NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InParmProbs",      NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutParmProbs",     NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InSrcQuenchs",     NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutSrcQuenchs",    NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InRedirects",      NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutRedirects",     NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InEchos",          NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutEchos",         NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InEchoReps",       NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutEchoReps",      NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InTimestamps",     NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutTimestamps",    NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InTimestampReps",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutTimestampReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InAddrMasks",      NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutAddrMasks",     NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InAddrMaskReps",   NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutAddrMaskReps",  NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InCsumErrors",     NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    for(i = 0; icmp_data[i].name[0] ;i++)
+                        rrddim_add(st, icmp_data[i].name,  NULL,  icmp_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InMsgs", InMsgs);
-                rrddim_set(st, "InErrors", InErrors);
-                rrddim_set(st, "InCsumErrors", InCsumErrors);
-                rrddim_set(st, "InDestUnreachs", InDestUnreachs);
-                rrddim_set(st, "InTimeExcds", InTimeExcds);
-                rrddim_set(st, "InParmProbs", InParmProbs);
-                rrddim_set(st, "InSrcQuenchs", InSrcQuenchs);
-                rrddim_set(st, "InRedirects", InRedirects);
-                rrddim_set(st, "InEchos", InEchos);
-                rrddim_set(st, "InEchoReps", InEchoReps);
-                rrddim_set(st, "InTimestamps", InTimestamps);
-                rrddim_set(st, "InTimestampReps", InTimestampReps);
-                rrddim_set(st, "InAddrMasks", InAddrMasks);
-                rrddim_set(st, "InAddrMaskReps", InAddrMaskReps);
-
-                rrddim_set(st, "OutMsgs", OutMsgs);
-                rrddim_set(st, "OutErrors", OutErrors);
-                rrddim_set(st, "OutDestUnreachs", OutDestUnreachs);
-                rrddim_set(st, "OutTimeExcds", OutTimeExcds);
-                rrddim_set(st, "OutParmProbs", OutParmProbs);
-                rrddim_set(st, "OutSrcQuenchs", OutSrcQuenchs);
-                rrddim_set(st, "OutRedirects", OutRedirects);
-                rrddim_set(st, "OutEchos", OutEchos);
-                rrddim_set(st, "OutEchoReps", OutEchoReps);
-                rrddim_set(st, "OutTimestamps", OutTimestamps);
-                rrddim_set(st, "OutTimestampReps", OutTimestampReps);
-                rrddim_set(st, "OutAddrMasks", OutAddrMasks);
-                rrddim_set(st, "OutAddrMaskReps", OutAddrMaskReps);
+                for(i = 0; icmp_data[i].name[0] ;i++)
+                    rrddim_set(st, icmp_data[i].name, icmp_data[i].value);
+
                 rrdset_done(st);
             }
         }
         else if(unlikely(hash == hash_icmpmsg && strcmp(key, "IcmpMsg") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "IcmpMsg") != 0) {
                 error("Cannot read IcmpMsg line from /proc/net/snmp.");
                 break;
             }
 
-            words = procfile_linewords(ff, l);
-            if(words < 12) {
-                error("Cannot read /proc/net/snmp IcmpMsg line. Expected 12 params, read %u.", words);
-                continue;
-            }
-
-            unsigned long long InType0, InType3, InType4, InType5, InType8, InType11, OutType0, OutType3, OutType5, OutType8, OutType11;
-
-            InType0   = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            InType3   = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            InType4   = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            InType5   = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            InType8   = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            InType11  = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-
-            OutType0  = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-            OutType3  = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-            OutType5  = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-            OutType8  = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-            OutType11 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+            parse_line_pair(ff, icmpmsg_data, h, l);
 
             // --------------------------------------------------------------------
 
             if(do_icmpmsg) {
+                int i;
+
                 st = rrdset_find(RRD_TYPE_NET_SNMP ".icmpmsg");
                 if(!st) {
                     st = rrdset_create(RRD_TYPE_NET_SNMP, "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages", "packets/s", 2603, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InType0",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutType0", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InType3",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutType3", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InType5",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutType5", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InType8",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutType8", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InType11",  NULL,  1, 1, RRDDIM_INCREMENTAL);
-                    rrddim_add(st, "OutType11", NULL, -1, 1, RRDDIM_INCREMENTAL);
-
-                    rrddim_add(st, "InType4", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    for(i = 0; icmpmsg_data[i].name[0] ;i++)
+                        rrddim_add(st, icmpmsg_data[i].name,  NULL,  icmpmsg_data[i].multiplier, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InType0", InType0);
-                rrddim_set(st, "InType3", InType3);
-                rrddim_set(st, "InType4", InType4);
-                rrddim_set(st, "InType5", InType5);
-                rrddim_set(st, "InType8", InType8);
-                rrddim_set(st, "InType11", InType11);
-
-                rrddim_set(st, "OutType0", OutType0);
-                rrddim_set(st, "OutType3", OutType3);
-                rrddim_set(st, "OutType5", OutType5);
-                rrddim_set(st, "OutType8", OutType8);
-                rrddim_set(st, "OutType11", OutType11);
+                for(i = 0; icmpmsg_data[i].name[0] ;i++)
+                    rrddim_set(st, icmpmsg_data[i].name, icmpmsg_data[i].value);
+
                 rrdset_done(st);
             }
         }
         else if(unlikely(hash == hash_tcp && strcmp(key, "Tcp") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
                 error("Cannot read Tcp line from /proc/net/snmp.");
@@ -393,34 +525,12 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
             }
 
             words = procfile_linewords(ff, l);
-            if(words < 15) {
-                error("Cannot read /proc/net/snmp Tcp line. Expected 15 params, read %u.", words);
+            if(words < 3) {
+                error("Cannot read /proc/net/snmp Tcp line. Expected 3+ params, read %u.", words);
                 continue;
             }
 
-            unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets,
-                CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
-
-            //RtoAlgorithm    = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            //RtoMin          = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            //RtoMax          = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            //MaxConn         = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            ActiveOpens     = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            PassiveOpens    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-            AttemptFails    = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-            EstabResets     = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-            CurrEstab       = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-            InSegs          = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-            OutSegs         = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-            RetransSegs     = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-            InErrs          = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-            OutRsts         = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-
-            // these are not counters
-            (void)RtoAlgorithm;
-            (void)RtoMin;
-            (void)RtoMax;
-            (void)MaxConn;
+            parse_line_pair(ff, tcp_data, h, l);
 
             // --------------------------------------------------------------------
 
@@ -434,7 +544,7 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "connections", CurrEstab);
+                rrddim_set(st, "connections", *tcp_CurrEstab);
                 rrdset_done(st);
             }
 
@@ -450,8 +560,8 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "received", InSegs);
-                rrddim_set(st, "sent", OutSegs);
+                rrddim_set(st, "received", *tcp_InSegs);
+                rrddim_set(st, "sent", *tcp_OutSegs);
                 rrdset_done(st);
             }
 
@@ -464,12 +574,14 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                     st->isdetail = 1;
 
                     rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InErrs", InErrs);
-                rrddim_set(st, "RetransSegs", RetransSegs);
+                rrddim_set(st, "InErrs", *tcp_InErrs);
+                rrddim_set(st, "InCsumErrors", *tcp_InCsumErrors);
+                rrddim_set(st, "RetransSegs", *tcp_RetransSegs);
                 rrdset_done(st);
             }
 
@@ -489,16 +601,16 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "EstabResets", EstabResets);
-                rrddim_set(st, "OutRsts", OutRsts);
-                rrddim_set(st, "ActiveOpens", ActiveOpens);
-                rrddim_set(st, "PassiveOpens", PassiveOpens);
-                rrddim_set(st, "AttemptFails", AttemptFails);
+                rrddim_set(st, "EstabResets", *tcp_EstabResets);
+                rrddim_set(st, "OutRsts", *tcp_OutRsts);
+                rrddim_set(st, "ActiveOpens", *tcp_ActiveOpens);
+                rrddim_set(st, "PassiveOpens", *tcp_PassiveOpens);
+                rrddim_set(st, "AttemptFails", *tcp_AttemptFails);
                 rrdset_done(st);
             }
         }
         else if(unlikely(hash == hash_udp && strcmp(key, "Udp") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
                 error("Cannot read Udp line from /proc/net/snmp.");
@@ -506,19 +618,12 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
             }
 
             words = procfile_linewords(ff, l);
-            if(words < 7) {
-                error("Cannot read /proc/net/snmp Udp line. Expected 7 params, read %u.", words);
+            if(words < 3) {
+                error("Cannot read /proc/net/snmp Udp line. Expected 3+ params, read %u.", words);
                 continue;
             }
 
-            unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
-
-            InDatagrams     = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            NoPorts         = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            InErrors        = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            OutDatagrams    = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            RcvbufErrors    = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            SndbufErrors    = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+            parse_line_pair(ff, udp_data, h, l);
 
             // --------------------------------------------------------------------
 
@@ -533,8 +638,8 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "received", InDatagrams);
-                rrddim_set(st, "sent", OutDatagrams);
+                rrddim_set(st, "received", *udp_InDatagrams);
+                rrddim_set(st, "sent", *udp_OutDatagrams);
                 rrdset_done(st);
             }
 
@@ -550,18 +655,22 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                     rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
                     rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InErrors", InErrors);
-                rrddim_set(st, "NoPorts", NoPorts);
-                rrddim_set(st, "RcvbufErrors", RcvbufErrors);
-                rrddim_set(st, "SndbufErrors", SndbufErrors);
+                rrddim_set(st, "InErrors", *udp_InErrors);
+                rrddim_set(st, "NoPorts", *udp_NoPorts);
+                rrddim_set(st, "RcvbufErrors", *udp_RcvbufErrors);
+                rrddim_set(st, "SndbufErrors", *udp_SndbufErrors);
+                rrddim_set(st, "InCsumErrors", *udp_InCsumErrors);
+                rrddim_set(st, "IgnoredMulti", *udp_IgnoredMulti);
                 rrdset_done(st);
             }
         }
         else if(unlikely(hash == hash_udplite && strcmp(key, "UdpLite") == 0)) {
-            l++;
+            uint32_t h = l++;
 
             if(strcmp(procfile_lineword(ff, l, 0), "UdpLite") != 0) {
                 error("Cannot read UdpLite line from /proc/net/snmp.");
@@ -569,21 +678,12 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
             }
 
             words = procfile_linewords(ff, l);
-            if(words < 9) {
-                error("Cannot read /proc/net/snmp UdpLite line. Expected 9 params, read %u.", words);
+            if(words < 3) {
+                error("Cannot read /proc/net/snmp UdpLite line. Expected 3+ params, read %u.", words);
                 continue;
             }
 
-            unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors, InCsumErrors, IgnoredMulti;
-
-            InDatagrams  = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-            NoPorts      = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-            InErrors     = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-            OutDatagrams = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-            RcvbufErrors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-            SndbufErrors = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-            InCsumErrors = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-            IgnoredMulti = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+            parse_line_pair(ff, udplite_data, h, l);
 
             // --------------------------------------------------------------------
 
@@ -597,8 +697,8 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InDatagrams", InDatagrams);
-                rrddim_set(st, "OutDatagrams", OutDatagrams);
+                rrddim_set(st, "InDatagrams", *udplite_InDatagrams);
+                rrddim_set(st, "OutDatagrams", *udplite_OutDatagrams);
                 rrdset_done(st);
 
                 st = rrdset_find(RRD_TYPE_NET_SNMP ".udplite_errors");
@@ -614,12 +714,12 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "NoPorts", NoPorts);
-                rrddim_set(st, "InErrors", InErrors);
-                rrddim_set(st, "InCsumErrors", InCsumErrors);
-                rrddim_set(st, "RcvbufErrors", RcvbufErrors);
-                rrddim_set(st, "SndbufErrors", SndbufErrors);
-                rrddim_set(st, "IgnoredMulti", IgnoredMulti);
+                rrddim_set(st, "NoPorts", *udplite_NoPorts);
+                rrddim_set(st, "InErrors", *udplite_InErrors);
+                rrddim_set(st, "InCsumErrors", *udplite_InCsumErrors);
+                rrddim_set(st, "RcvbufErrors", *udplite_RcvbufErrors);
+                rrddim_set(st, "SndbufErrors", *udplite_SndbufErrors);
+                rrddim_set(st, "IgnoredMulti", *udplite_IgnoredMulti);
                 rrdset_done(st);
             }
         }