Add text for two new TCP statistics and fix some existing descriptions
[platform/upstream/net-tools.git] / statistics.c
1 /*
2  * Copyright 1997,1999,2000 Andi Kleen. Subject to the GPL. 
3  * $Id: statistics.c,v 1.18 2003/02/12 03:30:57 ak Exp $
4  * 19980630 - i18n - Arnaldo Carvalho de Melo <acme@conectiva.com.br> 
5  * 19981113 - i18n fixes - Arnaldo Carvalho de Melo <acme@conectiva.com.br> 
6  * 19990101 - added net/netstat, -t, -u, -w supprt - Bernd Eckenfels 
7  */
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "config.h"
13 #include "intl.h"
14
15 /* #define WARN 1 */
16
17 #ifdef WARN
18 #define UFWARN(x) x
19 #else
20 #define UFWARN(x)
21 #endif
22
23 int print_static,f_raw,f_tcp,f_udp,f_unknown = 1;
24
25 enum State {
26     number = 0, opt_number, i_forward, i_inp_icmp, i_outp_icmp, i_rto_alg,
27     MaxState
28 };
29
30 #define normal number
31
32 struct entry {
33     char *title;
34     char *out;
35     enum State type;
36 };
37
38 struct statedesc { 
39     int indent;
40     char *title; 
41 }; 
42
43 struct statedesc states[] = { 
44     [number] = { 4, NULL },
45     [opt_number] = { 4, NULL }, 
46     [i_forward] = { 4, NULL },
47     [i_inp_icmp] = { 8, N_("ICMP input histogram:") },
48     [i_outp_icmp] = { 8, N_("ICMP output histogram:") },
49     [MaxState] = {0},
50 }; 
51
52 static enum State state;
53
54 #define I_STATIC (1<<16)        /* static configuration option. */
55 #define I_TITLE  (1<<17)
56
57 /* 
58  * XXX check against the snmp mib rfc.
59  *
60  * Don't mark the first field as translatable! It's a snmp MIB standard.
61  * - acme
62  */
63 struct entry Iptab[] =
64 {
65     {"Forwarding", N_("Forwarding is %s"), i_forward | I_STATIC},
66     {"DefaultTTL", N_("Default TTL is %u"), number | I_STATIC},
67     {"InReceives", N_("%u total packets received"), number},
68     {"InHdrErrors", N_("%u with invalid headers"), opt_number},
69     {"InAddrErrors", N_("%u with invalid addresses"), opt_number},
70     {"ForwDatagrams", N_("%u forwarded"), number},
71     {"InUnknownProtos", N_("%u with unknown protocol"), opt_number},
72     {"InDiscards", N_("%u incoming packets discarded"), number},
73     {"InDelivers", N_("%u incoming packets delivered"), number},
74     {"OutRequests", N_("%u requests sent out"), number},        /*? */
75     {"OutDiscards", N_("%u outgoing packets dropped"), opt_number},
76     {"OutNoRoutes", N_("%u dropped because of missing route"), opt_number},
77     {"ReasmTimeout", N_("%u fragments dropped after timeout"), opt_number},
78     {"ReasmReqds", N_("%u reassemblies required"), opt_number}, /* ? */
79     {"ReasmOKs", N_("%u packets reassembled ok"), opt_number},
80     {"ReasmFails", N_("%u packet reassembles failed"), opt_number},
81     {"FragOKs", N_("%u fragments received ok"), opt_number},
82     {"FragFails", N_("%u fragments failed"), opt_number},
83     {"FragCreates", N_("%u fragments created"), opt_number}
84 };
85
86 struct entry Icmptab[] =
87 {
88     {"InMsgs", N_("%u ICMP messages received"), number},
89     {"InErrors", N_("%u input ICMP message failed."), number},
90     {"InDestUnreachs", N_("destination unreachable: %u"), i_inp_icmp | I_TITLE},
91     {"InTimeExcds", N_("timeout in transit: %u"), i_inp_icmp | I_TITLE},
92     {"InParmProbs", N_("wrong parameters: %u"), i_inp_icmp | I_TITLE},  /*? */
93     {"InSrcQuenchs", N_("source quenches: %u"), i_inp_icmp | I_TITLE},
94     {"InRedirects", N_("redirects: %u"), i_inp_icmp | I_TITLE},
95     {"InEchos", N_("echo requests: %u"), i_inp_icmp | I_TITLE},
96     {"InEchoReps", N_("echo replies: %u"), i_inp_icmp | I_TITLE},
97     {"InTimestamps", N_("timestamp request: %u"), i_inp_icmp | I_TITLE},
98     {"InTimestampReps", N_("timestamp reply: %u"), i_inp_icmp | I_TITLE},
99     {"InAddrMasks", N_("address mask request: %u"), i_inp_icmp | I_TITLE},      /*? */
100     {"InAddrMaskReps", N_("address mask replies: %u"), i_inp_icmp | I_TITLE},   /*? */
101     {"OutMsgs", N_("%u ICMP messages sent"), number},
102     {"OutErrors", N_("%u ICMP messages failed"), number},
103     {"OutDestUnreachs", N_("destination unreachable: %u"), i_outp_icmp | I_TITLE},
104     {"OutTimeExcds", N_("time exceeded: %u"), i_outp_icmp | I_TITLE},
105     {"OutParmProbs", N_("wrong parameters: %u"), i_outp_icmp | I_TITLE},        /*? */
106     {"OutSrcQuenchs", N_("source quench: %u"), i_outp_icmp | I_TITLE},
107     {"OutRedirects", N_("redirect: %u"), i_outp_icmp | I_TITLE},
108     {"OutEchos", N_("echo request: %u"), i_outp_icmp | I_TITLE},
109     {"OutEchoReps", N_("echo replies: %u"), i_outp_icmp | I_TITLE},
110     {"OutTimestamps", N_("timestamp requests: %u"), i_outp_icmp | I_TITLE},
111     {"OutTimestampReps", N_("timestamp replies: %u"), i_outp_icmp | I_TITLE},
112     {"OutAddrMasks", N_("address mask requests: %u"), i_outp_icmp | I_TITLE},
113     {"OutAddrMaskReps", N_("address mask replies: %u"), i_outp_icmp | I_TITLE},
114 };
115
116 struct entry Tcptab[] =
117 {
118     {"RtoAlgorithm", N_("RTO algorithm is %s"), i_rto_alg | I_STATIC},
119     {"RtoMin", "", number},
120     {"RtoMax", "", number},
121     {"MaxConn", "", number},
122     {"ActiveOpens", N_("%u active connections openings"), number},
123     {"PassiveOpens", N_("%u passive connection openings"), number},
124     {"AttemptFails", N_("%u failed connection attempts"), number},
125     {"EstabResets", N_("%u connection resets received"), number},
126     {"CurrEstab", N_("%u connections established"), number},
127     {"InSegs", N_("%u segments received"), number},
128     {"OutSegs", N_("%u segments send out"), number},
129     {"RetransSegs", N_("%u segments retransmited"), number},
130     {"InErrs", N_("%u bad segments received."), number},
131     {"OutRsts", N_("%u resets sent"), number},
132 };
133
134 struct entry Udptab[] =
135 {
136     {"InDatagrams", N_("%u packets received"), number},
137     {"NoPorts", N_("%u packets to unknown port received."), number},
138     {"InErrors", N_("%u packet receive errors"), number},
139     {"OutDatagrams", N_("%u packets sent"), number},
140 };
141
142 struct entry Tcpexttab[] =
143 {
144     {"SyncookiesSent", N_("%u SYN cookies sent"), opt_number},
145     {"SyncookiesRecv", N_("%u SYN cookies received"), opt_number},
146     {"SyncookiesFailed", N_("%u invalid SYN cookies received"), opt_number},
147
148     { "EmbryonicRsts", N_("%u resets received for embryonic SYN_RECV sockets"),
149       opt_number },  
150     { "PruneCalled", N_("%u packets pruned from receive queue because of socket"
151                         " buffer overrun"), opt_number },  
152     /* obsolete: 2.2.0 doesn't do that anymore */
153     { "RcvPruned", N_("%u packets pruned from receive queue"), opt_number },
154     { "OfoPruned", N_("%u packets dropped from out-of-order queue because of"
155                       " socket buffer overrun"), opt_number }, 
156     { "OutOfWindowIcmps", N_("%u ICMP packets dropped because they were "
157                              "out-of-window"), opt_number }, 
158     { "LockDroppedIcmps", N_("%u ICMP packets dropped because"
159                              " socket was locked"), opt_number },
160     { "TW", N_("%u TCP sockets finished time wait in fast timer"), opt_number },
161     { "TWRecycled", N_("%u time wait sockets recycled by time stamp"), opt_number }, 
162     { "TWKilled", N_("%u TCP sockets finished time wait in slow timer"), opt_number },
163     { "PAWSPassive", N_("%u passive connections rejected because of"
164                         " time stamp"), opt_number },
165     { "PAWSActive", N_("%u active connections rejected because of "
166                        "time stamp"), opt_number },
167     { "PAWSEstab", N_("%u packets rejects in established connections because of"
168                       " timestamp"), opt_number },
169     { "DelayedACKs", N_("%u delayed acks sent"), opt_number },
170     { "DelayedACKLocked", N_("%u delayed acks further delayed because of"
171                              " locked socket"), opt_number },
172     { "DelayedACKLost", N_("Quick ack mode was activated %u times"), opt_number },
173     { "ListenOverflows", N_("%u times the listen queue of a socket overflowed"),
174       opt_number },
175     { "ListenDrops", N_("%u SYNs to LISTEN sockets dropped"), opt_number },
176     { "TCPPrequeued", N_("%u packets directly queued to recvmsg prequeue."), 
177       opt_number },
178     { "TCPDirectCopyFromBacklog", N_("%u bytes directly in process context from backlog"), opt_number },
179     { "TCPDirectCopyFromPrequeue", N_("%u bytes directly received in process context from prequeue"),
180                                       opt_number },
181     { "TCPPrequeueDropped", N_("%u packets dropped from prequeue"), opt_number },
182     { "TCPHPHits", N_("%u packet headers predicted"), number },
183     { "TCPHPHitsToUser", N_("%u packets header predicted and "
184                             "directly queued to user"), opt_number },
185     { "SockMallocOOM", N_("Ran %u times out of system memory during " 
186                           "packet sending"), opt_number }, 
187     { "TCPPureAcks", N_("%u acknowledgments not containing data payload received"), opt_number },
188     { "TCPHPAcks", N_("%u predicted acknowledgments"), opt_number },
189     { "TCPRenoRecovery", N_("%u times recovered from packet loss due to fast retransmit"), opt_number },
190     { "TCPSackRecovery", N_("%u times recovered from packet loss by selective acknowledgements"), opt_number },
191     { "TCPSACKReneging", N_("%u bad SACK blocks received"), opt_number },
192     { "TCPFACKReorder", N_("Detected reordering %u times using FACK"), opt_number },
193     { "TCPSACKReorder", N_("Detected reordering %u times using SACK"), opt_number },
194     { "TCPTSReorder", N_("Detected reordering %u times using time stamp"), opt_number },
195     { "TCPRenoReorder", N_("Detected reordering %u times using reno fast retransmit"), opt_number },
196     { "TCPFullUndo", N_("%u congestion windows fully recovered without slow start"), opt_number }, 
197     { "TCPPartialUndo", N_("%u congestion windows partially recovered using Hoe heuristic"), opt_number },
198     { "TCPDSackUndo", N_("%u congestion window recovered without slow start using DSACK"), opt_number },
199     { "TCPLossUndo", N_("%u congestion windows recovered without slow start after partial ack"), opt_number },
200     { "TCPLostRetransmits", N_("%u retransmits lost"), opt_number },
201     { "TCPRenoFailures",  N_("%u timeouts after reno fast retransmit"), opt_number },
202     { "TCPSackFailures",  N_("%u timeouts after SACK recovery"), opt_number },
203     { "TCPLossFailures",  N_("%u timeouts in loss state"), opt_number },
204     { "TCPFastRetrans", N_("%u fast retransmits"), opt_number },
205     { "TCPForwardRetrans", N_("%u forward retransmits"), opt_number }, 
206     { "TCPSlowStartRetrans", N_("%u retransmits in slow start"), opt_number },
207     { "TCPTimeouts", N_("%u other TCP timeouts"), opt_number },
208     { "TCPRenoRecoveryFailed", N_("%u reno fast retransmits failed"), opt_number },
209     { "TCPSackRecoveryFail", N_("%u SACK retransmits failed"), opt_number },
210     { "TCPSchedulerFailed", N_("%u times receiver scheduled too late for direct processing"), opt_number },
211     { "TCPRcvCollapsed", N_("%u packets collapsed in receive queue due to low socket buffer"), opt_number },
212     { "TCPDSACKOldSent", N_("%u DSACKs sent for old packets"), opt_number },
213     { "TCPDSACKOfoSent", N_("%u DSACKs sent for out of order packets"), opt_number },
214     { "TCPDSACKRecv", N_("%u DSACKs received"), opt_number },
215     { "TCPDSACKOfoRecv", N_("%u DSACKs for out of order packets received"), opt_number },
216     { "TCPAbortOnSyn", N_("%u connections reset due to unexpected SYN"), opt_number },
217     { "TCPAbortOnData", N_("%u connections reset due to unexpected data"), opt_number },
218     { "TCPAbortOnClose", N_("%u connections reset due to early user close"), opt_number },
219     { "TCPAbortOnMemory", N_("%u connections aborted due to memory pressure"), opt_number },
220     { "TCPAbortOnTimeout", N_("%u connections aborted due to timeout"), opt_number },
221     { "TCPAbortOnLinger", N_("%u connections aborted after user close in linger timeout"), opt_number },
222     { "TCPAbortFailed", N_("%u times unabled to send RST due to no memory"), opt_number }, 
223     { "TCPMemoryPressures", N_("TCP ran low on memory %u times"), opt_number }, 
224     { "TCPLoss", N_("%u TCP data loss events"), opt_number },
225     { "TCPDSACKUndo", N_("%u congestion windows recovered without slow start by DSACK"), 
226         opt_number },
227     { "TCPRenoRecoveryFail", N_("%u classic Reno fast retransmits failed"), opt_number },
228 };
229
230 struct tabtab {
231     char *title;
232     struct entry *tab;
233     size_t size;
234     int *flag; 
235 };
236
237 struct tabtab snmptabs[] =
238 {
239     {"Ip", Iptab, sizeof(Iptab), &f_raw},
240     {"Icmp", Icmptab, sizeof(Icmptab), &f_raw},
241     {"Tcp", Tcptab, sizeof(Tcptab), &f_tcp},
242     {"Udp", Udptab, sizeof(Udptab), &f_udp},
243     {"TcpExt", Tcpexttab, sizeof(Tcpexttab), &f_tcp},
244     {NULL}
245 };
246
247 /* XXX IGMP */
248
249 int cmpentries(const void *a, const void *b)
250 {
251     return strcmp(((struct entry *) a)->title, ((struct entry *) b)->title);
252 }
253
254 void printval(struct tabtab *tab, char *title, int val)
255 {
256     struct entry *ent = NULL, key;
257     int type;
258     char buf[512];
259
260     key.title = title;
261         if (tab->tab) 
262             ent = bsearch(&key, tab->tab, tab->size / sizeof(struct entry),
263                           sizeof(struct entry), cmpentries);
264     if (!ent) {                 /* try our best */
265         if (val) 
266                 printf("%*s%s: %d\n", states[state].indent, "", title, val);
267         return;
268     }
269     type = ent->type;
270     if (type & I_STATIC) {
271         type &= ~I_STATIC;
272         if (!print_static)
273             return;
274     }
275     if (*ent->out == '\0')
276         return;
277
278     if (type & I_TITLE) {
279         type &= ~I_TITLE;
280         if (state != type)
281             printf("%*s%s\n", states[state].indent, "", _(states[type].title));
282     }
283     buf[0] = '\0';
284     switch (type) {
285     case opt_number:
286         if (val == 0) 
287             break;
288         /*FALL THOUGH*/
289     case number:
290         snprintf(buf, sizeof(buf), _(ent->out), val);
291         break;
292     case i_forward:
293         type = normal;
294         snprintf(buf, sizeof(buf), _(ent->out), val == 2 ? _("enabled") : _("disabled"));
295         break;
296     case i_outp_icmp:
297     case i_inp_icmp:
298         if (val > 0)
299             snprintf(buf, sizeof(buf), _(ent->out), val);
300         break;
301     case i_rto_alg:             /* XXXX */
302         break;
303     default:
304         abort();
305     }
306     if (buf[0])
307         printf("%*s%s\n", states[type].indent, "", buf);
308
309     state = type;
310 }
311
312 struct tabtab *newtable(struct tabtab *tabs, char *title)
313 {
314     struct tabtab *t;
315         static struct tabtab dummytab;
316         
317     for (t = tabs; t->title; t++) {
318                 if (!strcmp(title, t->title)) {
319                 if (*(t->flag))
320                                 printf("%s:\n", _(title));
321                     state = normal;
322                         return t;
323                 }
324         }
325         if (!f_unknown) 
326                 return NULL; 
327         printf("%s:\n", _(title));
328         dummytab.title = title;
329         dummytab.flag = &f_unknown; 
330         return &dummytab;
331 }
332
333 void process_fd(FILE *f)
334 {
335     char buf1[1024], buf2[1024];
336     char *sp, *np, *p;
337     while (fgets(buf1, sizeof buf1, f)) {
338         int endflag;
339         struct tabtab *tab;
340
341         if (!fgets(buf2, sizeof buf2, f))
342             break;
343         sp = strchr(buf1, ':');
344         np = strchr(buf2, ':');
345         if (!np || !sp)
346             goto formaterr;
347         *sp = '\0';
348
349         tab = newtable(snmptabs, buf1);
350         if (tab == NULL) {
351                 printf("unknown %s\n", buf1);
352                 continue;
353         }
354         np++;
355         sp++;
356
357         endflag = 0;
358         while (!endflag) {
359             sp += strspn(sp, " \t\n"); 
360             np += strspn(np, " \t\n"); 
361             /*if (*np == '\0') goto formaterr; */
362
363             p = sp+strcspn(sp, " \t\n");
364             if (*p == '\0')
365                 endflag = 1;
366             *p = '\0';
367
368             if (*sp != '\0' && *(tab->flag))    
369                 printval(tab, sp, strtoul(np, &np, 10));
370
371             sp = p + 1;
372         }
373     }
374   return;
375   
376 formaterr:
377   perror(_("error parsing /proc/net/snmp"));
378   return;
379 }
380
381
382 void parsesnmp(int flag_raw, int flag_tcp, int flag_udp)
383 {
384     FILE *f;
385
386     f_raw = flag_raw; f_tcp = flag_tcp; f_udp = flag_udp;
387     
388     f = fopen("/proc/net/snmp", "r");
389     if (!f) {
390         perror(_("cannot open /proc/net/snmp"));
391         return;
392     }
393     process_fd(f);
394
395     if (ferror(f))
396         perror("/proc/net/snmp");
397
398     fclose(f);
399
400     f = fopen("/proc/net/netstat", "r");
401
402     if (f) {
403         process_fd(f);
404
405         if (ferror(f))
406             perror("/proc/net/netstat");
407     
408         fclose(f);
409     }
410     return;
411 }
412     
413
414 void inittab(void)
415 {
416     struct tabtab *t;
417
418     /* we sort at runtime because I'm lazy ;) */
419     for (t = snmptabs; t->title; t++)
420         qsort(t->tab, t->size / sizeof(struct entry),
421               sizeof(struct entry), cmpentries);
422 }