[Bug #17645] Add netstat(8) support for RcvbufErrors, SndbufErrors.
[platform/upstream/net-tools.git] / statistics.c
index 4f76dc3..df31d68 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 1997,1999,2000 Andi Kleen. Subject to the GPL. 
- * $Id: statistics.c,v 1.15 2001/10/19 09:28:01 ak Exp $
+ * $Id: statistics.c,v 1.23 2010-10-29 19:24:36 ecki Exp $
  * 19980630 - i18n - Arnaldo Carvalho de Melo <acme@conectiva.com.br> 
  * 19981113 - i18n fixes - Arnaldo Carvalho de Melo <acme@conectiva.com.br> 
  * 19990101 - added net/netstat, -t, -u, -w supprt - Bernd Eckenfels 
@@ -11,6 +11,7 @@
 #include <string.h>
 #include "config.h"
 #include "intl.h"
+#include "proc.h"
 
 /* #define WARN 1 */
 
@@ -83,6 +84,32 @@ struct entry Iptab[] =
     {"FragCreates", N_("%u fragments created"), opt_number}
 };
 
+struct entry Ip6tab[] =
+{
+    {"Ip6InReceives", N_("%u total packets received"), number},
+    {"Ip6InHdrErrors", N_("%u with invalid headers"), opt_number},
+    {"Ip6InTooBigErrors", N_("%u with packets too big"), opt_number},
+    {"Ip6InNoRoutes", N_("%u incoming packets with no route"), opt_number},
+    {"Ip6InAddrErrors", N_("%u with invalid addresses"), opt_number},
+    {"Ip6InUnknownProtos", N_("%u with unknown protocol"), opt_number},
+    {"Ip6InTruncatedPkts", N_("%u with truncated packets"), opt_number},
+    {"Ip6InDiscards", N_("%u incoming packets discarded"), number},
+    {"Ip6InDelivers", N_("%u incoming packets delivered"), number},
+    {"Ip6OutForwDatagrams", N_("%u forwarded"), number},
+    {"Ip6OutRequests", N_("%u requests sent out"), number},     /*? */
+    {"Ip6OutDiscards", N_("%u outgoing packets dropped"), opt_number},
+    {"Ip6OutNoRoutes", N_("%u dropped because of missing route"), opt_number},
+    {"Ip6ReasmTimeout", N_("%u fragments dropped after timeout"), opt_number},
+    {"Ip6ReasmReqds", N_("%u reassemblies required"), opt_number}, /* ? */
+    {"Ip6ReasmOKs", N_("%u packets reassembled ok"), opt_number},
+    {"Ip6ReasmFails", N_("%u packet reassembles failed"), opt_number},
+    {"Ip6FragOKs", N_("%u fragments received ok"), opt_number},
+    {"Ip6FragFails", N_("%u fragments failed"), opt_number},
+    {"Ip6FragCreates", N_("%u fragments created"), opt_number},
+    {"Ip6InMcastPkts", N_("%u incoming multicast packets"), opt_number},
+    {"Ip6OutMcastPkts", N_("%u outgoing multicast packets"), opt_number}
+};
+
 struct entry Icmptab[] =
 {
     {"InMsgs", N_("%u ICMP messages received"), number},
@@ -113,6 +140,41 @@ struct entry Icmptab[] =
     {"OutAddrMaskReps", N_("address mask replies: %u"), i_outp_icmp | I_TITLE},
 };
 
+struct entry Icmp6tab[] =
+{
+    {"Icmp6InMsgs", N_("%u ICMP messages received"), number},
+    {"Icmp6InErrors", N_("%u input ICMP message failed."), number},
+    {"Icmp6InDestUnreachs", N_("destination unreachable: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InPktTooBigs", N_("packets too big: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InTimeExcds", N_("received ICMPv6 time exceeded: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InParmProblems", N_("parameter problem: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InEchos", N_("echo requests: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InEchoReplies", N_("echo replies: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InGroupMembQueries", N_("group member queries: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InGroupMembResponses", N_("group member responses: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InGroupMembReductions", N_("group member reductions: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InRouterSolicits", N_("router solicits: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InRouterAdvertisements", N_("router advertisement: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InNeighborSolicits", N_("neighbour solicits: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InNeighborAdvertisements", N_("neighbour advertisement: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6InRedirects", N_("redirects: %u"), i_inp_icmp | I_TITLE},
+    {"Icmp6OutMsgs", N_("%u ICMP messages sent"), number},
+    {"Icmp6OutDestUnreachs", N_("destination unreachable: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutPktTooBigs", N_("packets too big: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutTimeExcds", N_("sent ICMPv6 time exceeded: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutParmProblems", N_("parameter problem: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutEchos", N_("echo requests: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutEchoReplies", N_("echo replies: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutGroupMembQueries", N_("group member queries: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutGroupMembResponses", N_("group member responses: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutGroupMembReductions", N_("group member reductions: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutRouterSolicits", N_("router solicits: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutRouterAdvertisements ", N_("router advertisement: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutNeighborSolicits", N_("neighbor solicits: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutNeighborAdvertisements", N_("neighbor advertisements: %u"), i_outp_icmp | I_TITLE},
+    {"Icmp6OutRedirects", N_("redirects: %u"), i_outp_icmp | I_TITLE},
+};
+
 struct entry Tcptab[] =
 {
     {"RtoAlgorithm", N_("RTO algorithm is %s"), i_rto_alg | I_STATIC},
@@ -137,6 +199,16 @@ struct entry Udptab[] =
     {"NoPorts", N_("%u packets to unknown port received."), number},
     {"InErrors", N_("%u packet receive errors"), number},
     {"OutDatagrams", N_("%u packets sent"), number},
+    {"RcvbufErrors", N_("%u receive buffer errors"), number},
+    {"SndbufErrors", N_("%u send buffer errors"), number},
+ };
+
+struct entry Udp6tab[] =
+{
+    {"Udp6InDatagrams", N_("%u packets received"), number},
+    {"Udp6NoPorts", N_("%u packets to unknown port received."), number},
+    {"Udp6InErrors", N_("%u packet receive errors"), number},
+    {"Udp6OutDatagrams", N_("%u packets sent"), number},
 };
 
 struct entry Tcpexttab[] =
@@ -172,19 +244,59 @@ struct entry Tcpexttab[] =
     { "DelayedACKLost", N_("Quick ack mode was activated %u times"), opt_number },
     { "ListenOverflows", N_("%u times the listen queue of a socket overflowed"),
       opt_number },
-    { "ListenDrops", N_("%u SYNs to LISTEN sockets ignored"), opt_number },
+    { "ListenDrops", N_("%u SYNs to LISTEN sockets dropped"), opt_number },
     { "TCPPrequeued", N_("%u packets directly queued to recvmsg prequeue."), 
       opt_number },
-    { "TCPDirectCopyFromBacklog", N_("%u packets directly received"
-                                    " from backlog"), opt_number },
-    { "TCPDirectCopyFromPrequeue", N_("%u packets directly received"
-                                     " from prequeue"), opt_number },
+    { "TCPDirectCopyFromBacklog", N_("%u bytes directly in process context from backlog"), opt_number },
+    { "TCPDirectCopyFromPrequeue", N_("%u bytes directly received in process context from prequeue"),
+                                     opt_number },
     { "TCPPrequeueDropped", N_("%u packets dropped from prequeue"), opt_number },
-    { "TCPHPHits", N_("%u packets header predicted"), number },
+    { "TCPHPHits", N_("%u packet headers predicted"), number },
     { "TCPHPHitsToUser", N_("%u packets header predicted and "
                            "directly queued to user"), opt_number },
     { "SockMallocOOM", N_("Ran %u times out of system memory during " 
                          "packet sending"), opt_number }, 
+    { "TCPPureAcks", N_("%u acknowledgments not containing data payload received"), opt_number },
+    { "TCPHPAcks", N_("%u predicted acknowledgments"), opt_number },
+    { "TCPRenoRecovery", N_("%u times recovered from packet loss due to fast retransmit"), opt_number },
+    { "TCPSackRecovery", N_("%u times recovered from packet loss by selective acknowledgements"), opt_number },
+    { "TCPSACKReneging", N_("%u bad SACK blocks received"), opt_number },
+    { "TCPFACKReorder", N_("Detected reordering %u times using FACK"), opt_number },
+    { "TCPSACKReorder", N_("Detected reordering %u times using SACK"), opt_number },
+    { "TCPTSReorder", N_("Detected reordering %u times using time stamp"), opt_number },
+    { "TCPRenoReorder", N_("Detected reordering %u times using reno fast retransmit"), opt_number },
+    { "TCPFullUndo", N_("%u congestion windows fully recovered without slow start"), opt_number }, 
+    { "TCPPartialUndo", N_("%u congestion windows partially recovered using Hoe heuristic"), opt_number },
+    { "TCPDSackUndo", N_("%u congestion window recovered without slow start using DSACK"), opt_number },
+    { "TCPLossUndo", N_("%u congestion windows recovered without slow start after partial ack"), opt_number },
+    { "TCPLostRetransmits", N_("%u retransmits lost"), opt_number },
+    { "TCPRenoFailures",  N_("%u timeouts after reno fast retransmit"), opt_number },
+    { "TCPSackFailures",  N_("%u timeouts after SACK recovery"), opt_number },
+    { "TCPLossFailures",  N_("%u timeouts in loss state"), opt_number },
+    { "TCPFastRetrans", N_("%u fast retransmits"), opt_number },
+    { "TCPForwardRetrans", N_("%u forward retransmits"), opt_number }, 
+    { "TCPSlowStartRetrans", N_("%u retransmits in slow start"), opt_number },
+    { "TCPTimeouts", N_("%u other TCP timeouts"), opt_number },
+    { "TCPRenoRecoveryFailed", N_("%u reno fast retransmits failed"), opt_number },
+    { "TCPSackRecoveryFail", N_("%u SACK retransmits failed"), opt_number },
+    { "TCPSchedulerFailed", N_("%u times receiver scheduled too late for direct processing"), opt_number },
+    { "TCPRcvCollapsed", N_("%u packets collapsed in receive queue due to low socket buffer"), opt_number },
+    { "TCPDSACKOldSent", N_("%u DSACKs sent for old packets"), opt_number },
+    { "TCPDSACKOfoSent", N_("%u DSACKs sent for out of order packets"), opt_number },
+    { "TCPDSACKRecv", N_("%u DSACKs received"), opt_number },
+    { "TCPDSACKOfoRecv", N_("%u DSACKs for out of order packets received"), opt_number },
+    { "TCPAbortOnSyn", N_("%u connections reset due to unexpected SYN"), opt_number },
+    { "TCPAbortOnData", N_("%u connections reset due to unexpected data"), opt_number },
+    { "TCPAbortOnClose", N_("%u connections reset due to early user close"), opt_number },
+    { "TCPAbortOnMemory", N_("%u connections aborted due to memory pressure"), opt_number },
+    { "TCPAbortOnTimeout", N_("%u connections aborted due to timeout"), opt_number },
+    { "TCPAbortOnLinger", N_("%u connections aborted after user close in linger timeout"), opt_number },
+    { "TCPAbortFailed", N_("%u times unabled to send RST due to no memory"), opt_number }, 
+    { "TCPMemoryPressures", N_("TCP ran low on memory %u times"), opt_number }, 
+    { "TCPLoss", N_("%u TCP data loss events"), opt_number },
+    { "TCPDSACKUndo", N_("%u congestion windows recovered without slow start by DSACK"), 
+       opt_number },
+    { "TCPRenoRecoveryFail", N_("%u classic Reno fast retransmits failed"), opt_number },
 };
 
 struct tabtab {
@@ -204,6 +316,15 @@ struct tabtab snmptabs[] =
     {NULL}
 };
 
+struct tabtab snmp6tabs[] =
+{
+    {"Ip6", Ip6tab, sizeof(Ip6tab), &f_raw},
+    {"Icmp6", Icmp6tab, sizeof(Icmp6tab), &f_raw},
+    {"Udp6", Udp6tab, sizeof(Udp6tab), &f_udp},
+    {"Tcp6", Tcptab, sizeof(Tcptab), &f_tcp},
+    {NULL}
+};
+
 /* XXX IGMP */
 
 int cmpentries(const void *a, const void *b)
@@ -290,14 +411,17 @@ struct tabtab *newtable(struct tabtab *tabs, char *title)
        return &dummytab;
 }
 
-void process_fd(FILE *f)
+int process_fd(FILE *f, int all, char *filter)
 {
-    char buf1[1024], buf2[1024];
+    char buf1[2048], buf2[2048];
     char *sp, *np, *p;
     while (fgets(buf1, sizeof buf1, f)) {
        int endflag;
        struct tabtab *tab;
 
+        if (buf1[0] == '\n') // skip empty first line in 2.6 kernels
+            continue;
+            
        if (!fgets(buf2, sizeof buf2, f))
            break;
        sp = strchr(buf1, ':');
@@ -306,6 +430,10 @@ void process_fd(FILE *f)
            goto formaterr;
        *sp = '\0';
 
+        if (!all)
+           if (strncmp(buf1, filter, strlen(filter)))
+               continue;
+
        tab = newtable(snmptabs, buf1);
        if (tab == NULL) {
                printf("unknown %s\n", buf1);
@@ -331,13 +459,48 @@ void process_fd(FILE *f)
            sp = p + 1;
        }
     }
-  return;
+  return 0;
   
 formaterr:
-  perror(_("error parsing /proc/net/snmp"));
-  return;
+  return -1;
+}
+
+void cpytitle(char *original, char *new)
+{
+     char *ptr = original;
+     while(*ptr != '6' && *ptr != '\0') {
+           *new = *ptr;
+            new++;
+            ptr++;
+     }
+    *new = *ptr;
+    new++;
+    *new = '\0';
 }
 
+void process6_fd(FILE *f)
+{
+   char buf1[1024],buf2[50],buf3[1024];
+   unsigned long val;
+   struct tabtab *tab = NULL;
+   int cpflg = 0;
+
+   while (fgets(buf1, sizeof buf1, f)) {
+          sscanf(buf1, "%s %lu", buf2, &val);
+          if(!cpflg) {
+             cpytitle(buf2, buf3);
+             tab = newtable(snmp6tabs, buf3);
+             cpflg = 1;
+          }
+          if(!strstr(buf2, buf3)) {
+             cpytitle(buf2, buf3);
+             tab = newtable(snmp6tabs, buf3);
+          }
+          if (*(tab->flag))
+             printval(tab, buf2, val);
+   }
+
+}
 
 void parsesnmp(int flag_raw, int flag_tcp, int flag_udp)
 {
@@ -345,22 +508,25 @@ void parsesnmp(int flag_raw, int flag_tcp, int flag_udp)
 
     f_raw = flag_raw; f_tcp = flag_tcp; f_udp = flag_udp;
     
-    f = fopen("/proc/net/snmp", "r");
+    f = proc_fopen("/proc/net/snmp");
     if (!f) {
        perror(_("cannot open /proc/net/snmp"));
        return;
     }
-    process_fd(f);
+
+    if (process_fd(f, 1, NULL) < 0)
+      fprintf(stderr, _("Problem while parsing /proc/net/snmp\n"));
 
     if (ferror(f))
        perror("/proc/net/snmp");
 
     fclose(f);
 
-    f = fopen("/proc/net/netstat", "r");
+    f = proc_fopen("/proc/net/netstat");
 
     if (f) {
-       process_fd(f);
+       if (process_fd(f, 1, NULL) <0)
+          fprintf(stderr, _("Problem while parsing /proc/net/netstat\n"));
 
         if (ferror(f))
            perror("/proc/net/netstat");
@@ -370,6 +536,33 @@ void parsesnmp(int flag_raw, int flag_tcp, int flag_udp)
     return;
 }
     
+void parsesnmp6(int flag_raw, int flag_tcp, int flag_udp)
+{
+    FILE *f;
+
+    f_raw = flag_raw; f_tcp = flag_tcp; f_udp = flag_udp;
+
+    f = fopen("/proc/net/snmp6", "r");
+    if (!f) {
+        perror(_("cannot open /proc/net/snmp6"));
+        return;
+    }
+    process6_fd(f);
+    if (ferror(f))
+        perror("/proc/net/snmp6");
+
+    fclose(f);
+    f = fopen("/proc/net/snmp", "r");
+    if (!f) {
+        perror(_("cannot open /proc/net/snmp"));
+        return;
+    }
+    process_fd(f, 0, "Tcp");
+    if (ferror(f))
+        perror("/proc/net/snmp");
+
+    fclose(f);
+}
 
 void inittab(void)
 {
@@ -380,3 +573,13 @@ void inittab(void)
        qsort(t->tab, t->size / sizeof(struct entry),
              sizeof(struct entry), cmpentries);
 }
+
+void inittab6(void)
+{
+    struct tabtab *t;
+
+    for (t = snmp6tabs; t->title; t++)
+        qsort(t->tab, t->size / sizeof(struct entry),
+              sizeof(struct entry), cmpentries);
+}
+