]> git.ozlabs.org Git - ppp.git/blob - pppstats/pppstats.c
config: Include some extra files in the tarball
[ppp.git] / pppstats / pppstats.c
1 /*
2  * print PPP statistics:
3  *      pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
4  *
5  *   -a Show absolute values rather than deltas
6  *   -d Show data rate (kB/s) rather than bytes
7  *   -v Show more stats for VJ TCP header compression
8  *   -r Show compression ratio
9  *   -z Show compression statistics instead of default display
10  *
11  * History:
12  *      perkins@cps.msu.edu: Added compression statistics and alternate 
13  *                display. 11/94
14  *      Brad Parker (brad@cayman.com) 6/92
15  *
16  * from the original "slstats" by Van Jacobson
17  *
18  * Copyright (c) 1989 Regents of the University of California.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that the above copyright notice and this paragraph are
23  * duplicated in all such forms and that any documentation,
24  * advertising materials, and other materials related to such
25  * distribution and use acknowledge that the software was developed
26  * by the University of California, Berkeley.  The name of the
27  * University may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  */
33
34 #ifndef __STDC__
35 #define const
36 #endif
37
38 #include <stdio.h>
39 #include <stddef.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <sys/ioctl.h>
50
51 #ifndef STREAMS
52 #if defined(__linux__) && defined(__powerpc__) \
53     && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
54 /* kludge alert! */
55 #undef __GLIBC__
56 #endif
57 #include <sys/socket.h>         /* *BSD, Linux, NeXT, Ultrix etc. */
58 #ifndef __linux__
59 #include <net/if.h>
60 #include <net/ppp_defs.h>
61 #else
62 /* Linux */
63 #if __GLIBC__ >= 2
64 #include <asm/types.h>          /* glibc 2 conflicts with linux/types.h */
65 #include <net/if.h>
66 #else
67 #include <linux/types.h>
68 #include <linux/if.h>
69 #endif
70 #include <linux/ppp_defs.h>
71 #include <linux/ppp-ioctl.h>
72
73 #endif /* __linux__ */
74
75 #else   /* STREAMS */
76 #include <sys/stropts.h>        /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
77 #include <net/ppp_defs.h>
78 #include <net/pppio.h>
79
80 #endif  /* STREAMS */
81
82 int     vflag, rflag, zflag;    /* select type of display */
83 int     aflag;                  /* print absolute values, not deltas */
84 int     dflag;                  /* print data rates, not bytes */
85 int     interval, count;
86 int     infinite;
87 int     s;                      /* socket or /dev/ppp file descriptor */
88 int     signalled;              /* set if alarm goes off "early" */
89 char    *progname;
90 char    *interface;
91
92 #if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
93 extern int optind;
94 extern char *optarg;
95 #endif
96
97 /*
98  * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the
99  * device name.
100  */
101 #if !defined(PPP_DRV_NAME)
102 #define PPP_DRV_NAME    "ppp"
103 #endif /* !defined(PPP_DRV_NAME) */
104
105 static void usage(void);
106 static void catchalarm(int);
107 static void get_ppp_stats(struct ppp_stats *);
108 static void get_ppp_cstats(struct ppp_comp_stats *);
109 static void intpr(void);
110
111 int main(int, char *argv[]);
112
113 static void
114 usage(void)
115 {
116     fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
117             progname);
118     exit(1);
119 }
120
121 /*
122  * Called if an interval expires before intpr has completed a loop.
123  * Sets a flag to not wait for the alarm.
124  */
125 static void
126 catchalarm(int arg)
127 {
128     signalled = 1;
129 }
130
131
132 #ifndef STREAMS
133 static void
134 get_ppp_stats(struct ppp_stats *curp)
135 {
136     struct ifreq req;
137
138     memset (&req, 0, sizeof (req));
139
140     req.ifr_data = (caddr_t) curp;
141
142     strncpy(req.ifr_name, interface, IFNAMSIZ);
143     req.ifr_name[IFNAMSIZ - 1] = 0;
144     if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
145         fprintf(stderr, "%s: ", progname);
146         if (errno == ENOTTY)
147             fprintf(stderr, "kernel support missing\n");
148         else
149             perror("couldn't get PPP statistics");
150         exit(1);
151     }
152 }
153
154 static void
155 get_ppp_cstats(struct ppp_comp_stats *csp)
156 {
157     struct ifreq req;
158     struct ppp_comp_stats stats;
159
160     memset (&req, 0, sizeof (req));
161
162     req.ifr_data = (caddr_t) &stats;
163
164     strncpy(req.ifr_name, interface, IFNAMSIZ);
165     req.ifr_name[IFNAMSIZ - 1] = 0;
166     if (ioctl(s, SIOCGPPPCSTATS, &req) < 0) {
167         fprintf(stderr, "%s: ", progname);
168         if (errno == ENOTTY) {
169             fprintf(stderr, "no kernel compression support\n");
170             if (zflag)
171                 exit(1);
172             rflag = 0;
173         } else {
174             perror("couldn't get PPP compression stats");
175             exit(1);
176         }
177     }
178
179 #ifdef __linux__
180     if (stats.c.bytes_out == 0) {
181         stats.c.bytes_out = stats.c.comp_bytes + stats.c.inc_bytes;
182         stats.c.in_count = stats.c.unc_bytes;
183     }
184     if (stats.c.bytes_out == 0)
185         stats.c.ratio = 0.0;
186     else
187         stats.c.ratio = 256.0 * stats.c.in_count / stats.c.bytes_out;
188
189     if (stats.d.bytes_out == 0) {
190         stats.d.bytes_out = stats.d.comp_bytes + stats.d.inc_bytes;
191         stats.d.in_count = stats.d.unc_bytes;
192     }
193     if (stats.d.bytes_out == 0)
194         stats.d.ratio = 0.0;
195     else
196         stats.d.ratio = 256.0 * stats.d.in_count / stats.d.bytes_out;
197 #endif
198
199     *csp = stats;
200 }
201
202 #else   /* STREAMS */
203
204 int
205 strioctl(int fd, int cmd, char *ptr, int ilen, int olen)
206 {
207     struct strioctl str;
208
209     str.ic_cmd = cmd;
210     str.ic_timout = 0;
211     str.ic_len = ilen;
212     str.ic_dp = ptr;
213     if (ioctl(fd, I_STR, &str) == -1)
214         return -1;
215     if (str.ic_len != olen)
216         fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
217                olen, str.ic_len, cmd);
218     return 0;
219 }
220
221 static void
222 get_ppp_stats(struct ppp_stats *curp)
223 {
224     if (strioctl(s, PPPIO_GETSTAT, (char*) curp, 0, sizeof(*curp)) < 0) {
225         fprintf(stderr, "%s: ", progname);
226         if (errno == EINVAL)
227             fprintf(stderr, "kernel support missing\n");
228         else
229             perror("couldn't get PPP statistics");
230         exit(1);
231     }
232 }
233
234 static void
235 get_ppp_cstats(struct ppp_comp_stats *csp)
236 {
237     if (strioctl(s, PPPIO_GETCSTAT, (char*) csp, 0, sizeof(*csp)) < 0) {
238         fprintf(stderr, "%s: ", progname);
239         if (errno == ENOTTY) {
240             fprintf(stderr, "no kernel compression support\n");
241             if (zflag)
242                 exit(1);
243             rflag = 0;
244         } else {
245             perror("couldn't get PPP compression statistics");
246             exit(1);
247         }
248     }
249 }
250
251 #endif /* STREAMS */
252
253 #define MAX0(a)         ((int)(a) > 0? (a): 0)
254 #define V(offset)       MAX0(cur.offset - old.offset)
255 #define W(offset)       MAX0(ccs.offset - ocs.offset)
256
257 #define RATIO(c, i, u)  ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
258 #define CRATE(x)        RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
259
260 #define KBPS(n)         ((n) / (interval * 1000.0))
261
262 /*
263  * Print a running summary of interface statistics.
264  * Repeat display every interval seconds, showing statistics
265  * collected over that interval.  Assumes that interval is non-zero.
266  * First line printed is cumulative.
267  */
268 static void
269 intpr(void)
270 {
271     register int line = 0;
272     sigset_t oldmask, mask;
273     char *bunit;
274     int ratef = 0;
275     struct ppp_stats cur, old;
276     struct ppp_comp_stats ccs, ocs;
277
278     memset(&old, 0, sizeof(old));
279     memset(&ocs, 0, sizeof(ocs));
280
281     while (1) {
282         get_ppp_stats(&cur);
283         if (zflag || rflag)
284             get_ppp_cstats(&ccs);
285
286         (void)signal(SIGALRM, catchalarm);
287         signalled = 0;
288         (void)alarm(interval);
289
290         if ((line % 20) == 0) {
291             if (zflag) {
292                 printf("IN:  COMPRESSED  INCOMPRESSIBLE   COMP | ");
293                 printf("OUT: COMPRESSED  INCOMPRESSIBLE   COMP\n");
294                 bunit = dflag? "KB/S": "BYTE";
295                 printf("    %s   PACK     %s   PACK  RATIO | ", bunit, bunit);
296                 printf("    %s   PACK     %s   PACK  RATIO", bunit, bunit);
297             } else {
298                 printf("%8.8s %6.6s %6.6s",
299                        "IN", "PACK", "VJCOMP");
300
301                 if (!rflag)
302                     printf(" %6.6s %6.6s", "VJUNC", "VJERR");
303                 if (vflag)
304                     printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
305                 if (rflag)
306                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
307                 printf("  | %8.8s %6.6s %6.6s",
308                        "OUT", "PACK", "VJCOMP");
309
310                 if (!rflag)
311                     printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
312                 if (vflag)
313                     printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
314                 if (rflag)
315                     printf(" %6.6s %6.6s", "RATIO", "UBYTE");
316             }
317             putchar('\n');
318         }
319
320         if (zflag) {
321             if (ratef) {
322                 printf("%8.3f %6u %8.3f %6u %6.2f",
323                        KBPS(W(d.comp_bytes)),
324                        W(d.comp_packets),
325                        KBPS(W(d.inc_bytes)),
326                        W(d.inc_packets),
327                        ccs.d.ratio / 256.0);
328                 printf(" | %8.3f %6u %8.3f %6u %6.2f",
329                        KBPS(W(c.comp_bytes)),
330                        W(c.comp_packets),
331                        KBPS(W(c.inc_bytes)),
332                        W(c.inc_packets),
333                        ccs.c.ratio / 256.0);
334             } else {
335                 printf("%8u %6u %8u %6u %6.2f",
336                        W(d.comp_bytes),
337                        W(d.comp_packets),
338                        W(d.inc_bytes),
339                        W(d.inc_packets),
340                        ccs.d.ratio / 256.0);
341                 printf(" | %8u %6u %8u %6u %6.2f",
342                        W(c.comp_bytes),
343                        W(c.comp_packets),
344                        W(c.inc_bytes),
345                        W(c.inc_packets),
346                        ccs.c.ratio / 256.0);
347             }
348         
349         } else {
350             if (ratef)
351                 printf("%8.3f", KBPS(V(p.ppp_ibytes)));
352             else
353                 printf("%8u", V(p.ppp_ibytes));
354             printf(" %6u %6u",
355                    V(p.ppp_ipackets),
356                    V(vj.vjs_compressedin));
357             if (!rflag)
358                 printf(" %6u %6u",
359                        V(vj.vjs_uncompressedin),
360                        V(vj.vjs_errorin));
361             if (vflag)
362                 printf(" %6u %6u",
363                        V(vj.vjs_tossed),
364                        V(p.ppp_ipackets) - V(vj.vjs_compressedin)
365                        - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
366             if (rflag) {
367                 printf(" %6.2f ", CRATE(d));
368                 if (ratef)
369                     printf("%6.2f", KBPS(W(d.unc_bytes)));
370                 else
371                     printf("%6u", W(d.unc_bytes));
372             }
373             if (ratef)
374                 printf("  | %8.3f", KBPS(V(p.ppp_obytes)));
375             else
376                 printf("  | %8u", V(p.ppp_obytes));
377             printf(" %6u %6u",
378                    V(p.ppp_opackets),
379                    V(vj.vjs_compressed));
380             if (!rflag)
381                 printf(" %6u %6u",
382                        V(vj.vjs_packets) - V(vj.vjs_compressed),
383                        V(p.ppp_opackets) - V(vj.vjs_packets));
384             if (vflag)
385                 printf(" %6u %6u",
386                        V(vj.vjs_searches),
387                        V(vj.vjs_misses));
388             if (rflag) {
389                 printf(" %6.2f ", CRATE(c));
390                 if (ratef)
391                     printf("%6.2f", KBPS(W(c.unc_bytes)));
392                 else
393                     printf("%6u", W(c.unc_bytes));
394             }
395
396         }
397
398         putchar('\n');
399         fflush(stdout);
400         line++;
401
402         count--;
403         if (!infinite && !count)
404             break;
405
406         sigemptyset(&mask);
407         sigaddset(&mask, SIGALRM);
408         sigprocmask(SIG_BLOCK, &mask, &oldmask);
409         if (!signalled) {
410             sigemptyset(&mask);
411             sigsuspend(&mask);
412         }
413         sigprocmask(SIG_SETMASK, &oldmask, NULL);
414         signalled = 0;
415         (void)alarm(interval);
416
417         if (!aflag) {
418             old = cur;
419             ocs = ccs;
420             ratef = dflag;
421         }
422     }
423 }
424
425 int
426 main(int argc, char *argv[])
427 {
428     int c;
429 #ifdef STREAMS
430     int unit;
431     char *dev;
432 #endif
433
434     interface = PPP_DRV_NAME "0";
435     if ((progname = strrchr(argv[0], '/')) == NULL)
436         progname = argv[0];
437     else
438         ++progname;
439
440     while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
441         switch (c) {
442         case 'a':
443             ++aflag;
444             break;
445         case 'd':
446             ++dflag;
447             break;
448         case 'v':
449             ++vflag;
450             break;
451         case 'r':
452             ++rflag;
453             break;
454         case 'z':
455             ++zflag;
456             break;
457         case 'c':
458             count = atoi(optarg);
459             if (count <= 0)
460                 usage();
461             break;
462         case 'w':
463             interval = atoi(optarg);
464             if (interval <= 0)
465                 usage();
466             break;
467         default:
468             usage();
469         }
470     }
471     argc -= optind;
472     argv += optind;
473
474     if (!interval && count)
475         interval = 5;
476     if (interval && !count)
477         infinite = 1;
478     if (!interval && !count)
479         count = 1;
480     if (aflag)
481         dflag = 0;
482
483     if (argc > 1)
484         usage();
485     if (argc > 0)
486         interface = argv[0];
487
488 #ifndef STREAMS
489     {
490         struct ifreq ifr;
491
492         s = socket(AF_INET, SOCK_DGRAM, 0);
493         if (s < 0) {
494             fprintf(stderr, "%s: ", progname);
495             perror("couldn't create IP socket");
496             exit(1);
497         }
498
499 #ifdef __linux__
500 #undef  ifr_name
501 #define ifr_name ifr_ifrn.ifrn_name
502 #endif
503         strncpy(ifr.ifr_name, interface, IFNAMSIZ);
504         ifr.ifr_name[IFNAMSIZ - 1] = 0;
505         if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
506             fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
507                     progname, interface);
508             exit(1);
509         }
510     }
511
512 #else   /* STREAMS */
513     if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
514         fprintf(stderr, "%s: invalid interface '%s' specified\n",
515                 progname, interface);
516     }
517
518 #ifdef __osf__
519     dev = "/dev/streams/ppp";
520 #else
521     dev = "/dev/" PPP_DRV_NAME;
522 #endif
523     if ((s = open(dev, O_RDONLY)) < 0) {
524         fprintf(stderr, "%s: couldn't open ", progname);
525         perror(dev);
526         exit(1);
527     }
528     if (strioctl(s, PPPIO_ATTACH, (char*) &unit, sizeof(int), 0) < 0) {
529         fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
530         exit(1);
531     }
532
533 #endif  /* STREAMS */
534
535     intpr();
536     exit(0);
537 }