Initial revision
[platform/upstream/net-tools.git] / statistics.c
1 /* Copyright '97 by Andi Kleen. Subject to the GPL. */
2
3 #include <ctype.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 int print_static; 
9
10 enum State { number = 0, i_forward, i_inp_icmp, i_outp_icmp, i_rto_alg };
11 #define normal number
12
13 struct entry {
14         char *title;
15         char *out; 
16         enum State type;
17 }; 
18
19 static enum State state;
20 static int indent[] = { 4, 4, 8, 8, 4 };       /* for each state */
21
22 #define I_STATIC (1<<16) /* static configuration option. */
23 #define I_TITLE  (1<<17)
24
25 char *titles[] = { /* for each state */
26         NULL, NULL, 
27         "ICMP input histogram:",
28         "ICMP output histogram:",
29         NULL
30 };
31
32 /* XXX check against the snmp mib rfc.
33  */
34 struct entry Iptab[] = {
35         { "Forwarding", "Forwarding is %s", i_forward|I_STATIC },
36         { "DefaultTTL", "Default TTL is %d", number|I_STATIC },
37         { "InReceives", "%d total packets received", number },
38         { "InHdrErrors", "%d with invalid headers", number },
39         { "InAddrErrors", "%d with invalid addresses", number },
40         { "ForwDatagrams", "%d forwarded", number },
41         { "InUnknownProtos", "%d with unknown protocol", number },
42         { "InDiscards", "%d incoming packets discarded", number },
43         { "InDelivers", "%d incoming packets delivered", number },
44         { "OutRequests", "%d requests sent out", number }, /*?*/
45         { "OutDiscards", "%d outgoing packets dropped", number }, 
46         { "OutNoRoutes", "%d dropped because of missing route", number },
47         { "ReasmTimeout", "%d fragments dropped after timeout", number },
48         { "ReasmReqds", "%d reassemblies required", number }, /* ? */
49         { "ReasmOKs", "%d packets reassembled ok", number }, 
50         { "ReasmFails", "%d packet reassembles failed", number }, 
51         { "FragOKs", "%d fragments received ok", number },
52         { "FragFails", "%d fragments failed", number },
53         { "FragCreates", "%d fragments created", number }
54 };
55
56 struct entry Icmptab[] = {
57         { "InMsgs", "%d ICMP messages received", number },
58         { "InErrors", "%d input ICMP message failed.", number },
59         { "InDestUnreachs", "destination unreachable: %d", i_inp_icmp|I_TITLE },
60         { "InTimeExcds", "timeout in transit: %d", i_inp_icmp|I_TITLE },
61         { "InParmProbs", "wrong parameters: %d", i_inp_icmp|I_TITLE },  /*?*/
62         { "InSrcQuenchs", "source quenchs: %d", i_inp_icmp|I_TITLE },
63         { "InRedirects", "redirects: %d", i_inp_icmp|I_TITLE },
64         { "InEchos", "echo requests: %d", i_inp_icmp|I_TITLE },
65         { "InEchoReps", "echo replies: %d", i_inp_icmp|I_TITLE },
66         { "InTimestamps", "timestamp request: %d", i_inp_icmp|I_TITLE },
67         { "InTimestampReps", "timestamp reply: %d", i_inp_icmp|I_TITLE },
68         { "InAddrMasks", "address mask request: %d", i_inp_icmp|I_TITLE }, /*?*/
69         { "InAddrMaskReps", "address mask replies", i_inp_icmp|I_TITLE }, /*?*/
70         { "OutMsgs", "%d ICMP messages sent", number },
71         { "OutErrors", "%d ICMP messages failed", number },
72         { "OutDestUnreachs", "destination unreachable: %d", i_outp_icmp|I_TITLE },
73         { "OutTimeExcds", "time exceeded: %d", i_outp_icmp|I_TITLE },
74         { "OutParmProbs", "wrong parameters: %d", i_outp_icmp|I_TITLE }, /*?*/
75         { "OutSrcQuenchs", "source quench: %d", i_outp_icmp|I_TITLE },
76         { "OutRedirects", "redirect: %d", i_outp_icmp|I_TITLE },
77         { "OutEchos", "echo request: %d", i_outp_icmp|I_TITLE },
78         { "OutEchoReps", "echo replies: %d", i_outp_icmp|I_TITLE },
79         { "OutTimestamps", "timestamp requests: %d", i_outp_icmp|I_TITLE },
80         { "OutTimestampReps", "timestamp replies: %d", i_outp_icmp|I_TITLE },
81         { "OutAddrMasks", "address mask requests: %d", i_outp_icmp|I_TITLE },
82         { "OutAddrMaskReps", "address mask replies: %d", i_outp_icmp|I_TITLE },
83 };
84
85 struct entry Tcptab[] = {
86         { "RtoAlgorithm", "RTO algorithm is %s", i_rto_alg|I_STATIC },
87         { "RtoMin", "", number },
88         { "RtoMax", "", number },
89         { "MaxConn", "", number },
90         { "ActiveOpens", "%d active opens", number },
91         { "PassiveOpens", "%d passive opens", number },
92         { "AttemptFails", "%d failed connection attempts", number },
93         { "EstabResets", "%d connection resets received", number },
94         { "CurrEstab", "%d connections established", number },
95         { "InSegs", "%d segments received", number },
96         { "OutSegs", "%d segments send out", number },
97         { "RetransSegs", "%d segments retransmited", number },
98 };
99
100 struct entry Udptab[] = {
101         { "InDatagrams", "%d packets received", number },
102         { "NoPorts", "%d packets to unknown port received.", number },
103         { "InErrors", "%d packet receive errors", number },
104         { "OutDatagrams", "%d packets send", number },
105 };
106
107 struct tabtab {
108         char *title; 
109         struct entry *tab; 
110         size_t size; 
111 }; 
112
113 struct tabtab snmptabs[] = { 
114         { "Ip", Iptab, sizeof(Iptab) },
115         { "Icmp", Icmptab, sizeof(Icmptab) },
116         { "Tcp", Tcptab, sizeof(Tcptab) },
117         { "Udp", Udptab, sizeof(Udptab) },
118         { NULL }
119 }; 
120
121 static char *skiptok(char *s)
122 {
123         while (!isspace(*s) && *s != '\0')
124                 s++; 
125         return s;
126 }
127
128
129 /* XXX IGMP */ 
130
131 int cmpentries(const void *a, const void *b)
132 {
133         return strcmp( ((struct entry*)a)->title, ((struct entry*)b)->title);
134 }
135
136 void printval(struct tabtab *tab, char *title, int val) 
137 {
138         struct entry *ent, key; 
139         int type; 
140         char buf[512];
141
142         key.title = title; 
143         ent = bsearch(&key, tab->tab, tab->size/sizeof(struct entry),
144                                   sizeof(struct entry), cmpentries); 
145         if (!ent)  /* XXX warning */ 
146                 return;
147         type = ent->type; 
148         if (type & I_STATIC) {
149                 type &= ~I_STATIC; 
150                 if (!print_static) 
151                         return; 
152         }
153         if (*ent->out == '\0') 
154                 return; 
155
156         if (type & I_TITLE) {
157                 type &= ~I_TITLE;
158                 if (state != type)
159                         printf("%*s%s\n", indent[state], "", titles[type]);
160         }
161
162         buf[0] = '\0';
163         switch (type) {
164         case number:
165                 sprintf(buf, ent->out, val);
166                 break; 
167         case i_forward:
168                 type = normal;
169                 sprintf(buf, ent->out, val == 2 ? "enabled" : "disabled");
170                 break; 
171         case i_outp_icmp:
172         case i_inp_icmp: 
173                 if (val > 0) {
174                         sprintf(buf,ent->out, val); 
175                 }
176                 break; 
177         case i_rto_alg: /* XXXX */
178                 break; 
179         default:
180                 abort(); 
181         }
182         if (buf[0]) 
183                 printf("%*s%s\n",indent[type],"", buf);
184         
185         state = type;
186 }
187
188 struct tabtab *newtable(struct tabtab *tabs, char *title) 
189 {
190         struct tabtab *t; 
191
192         for (t = tabs; t->title; t++) 
193                 if (!strcmp(title, t->title)) {
194                         printf("%s:\n", title); 
195                         state = normal; 
196                         return t; 
197                 }
198         return NULL; 
199 }
200
201 void parsesnmp()
202 {
203         FILE *f; 
204         char buf1[512], buf2[512]; 
205         char *sp, *np, *p; 
206
207         f = fopen("/proc/net/snmp", "r"); 
208         if (!f) {
209                 perror("cannot open /proc/net/snmp");
210                 return;
211         }
212         while (fgets(buf1,sizeof buf1,f)) {
213                 int endflag; 
214                 struct tabtab *tab; 
215
216                 if (!fgets(buf2,sizeof buf2,f)) break; 
217                 sp = strchr(buf1, ':');
218                 np = strchr(buf2, ':'); 
219                 if (!np || !sp) 
220                         goto formaterr; 
221                 *sp = '\0'; 
222                 tab = newtable(snmptabs, buf1); 
223                 if (tab == NULL) /* XXX print warning */  
224                         continue; 
225                 np++; sp++; 
226                 
227                 endflag = 0; 
228                 while (!endflag) {
229                         while(isspace(*sp)) sp++; 
230                         while(isspace(*np)) np++; 
231                         /*if (*np == '\0') goto formaterr;*/ 
232
233                         p = skiptok(sp); 
234                         if (*p == '\0') endflag=1; 
235                         *p = '\0'; 
236                         printval(tab, sp, strtoul(np,&np,10)); 
237                         sp = p+1; 
238                 }
239         }
240         if (ferror(f)) 
241                 perror("/proc/net/snmp"); 
242         fclose(f); 
243         return; 
244
245 formaterr: 
246         perror("error parsing /proc/net/snmp"); 
247         return; 
248 }
249
250 void inittab()
251 {
252         struct tabtab *t;
253  
254         /* we sort at runtime because I'm lazy ;) */ 
255         for (t = snmptabs; t->title; t++)  
256                 qsort(t->tab, t->size/sizeof(struct entry), 
257                           sizeof(struct entry), cmpentries); 
258 }