Update for 2.4.4 release
[mpls-ppp.git] / pppstats / pppstats.c
blob6367988eb96bf03c588b6228ee0c0fdf115f0fbb
1 /*
2 * print PPP statistics:
3 * pppstats [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]
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
11 * History:
12 * perkins@cps.msu.edu: Added compression statistics and alternate
13 * display. 11/94
14 * Brad Parker (brad@cayman.com) 6/92
16 * from the original "slstats" by Van Jacobson
18 * Copyright (c) 1989 Regents of the University of California.
19 * All rights reserved.
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.
34 #ifndef __STDC__
35 #define const
36 #endif
38 #ifndef lint
39 static const char rcsid[] = "$Id: pppstats.c,v 1.29 2002/10/27 12:56:26 fcusack Exp $";
40 #endif
42 #include <stdio.h>
43 #include <stddef.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <signal.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/ioctl.h>
55 #ifndef STREAMS
56 #if defined(__linux__) && defined(__powerpc__) \
57 && (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
58 /* kludge alert! */
59 #undef __GLIBC__
60 #endif
61 #include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */
62 #ifndef __linux__
63 #include <net/if.h>
64 #include <net/ppp_defs.h>
65 #include <net/if_ppp.h>
66 #else
67 /* Linux */
68 #if __GLIBC__ >= 2
69 #include <asm/types.h> /* glibc 2 conflicts with linux/types.h */
70 #include <net/if.h>
71 #else
72 #include <linux/types.h>
73 #include <linux/if.h>
74 #endif
75 #include <linux/ppp_defs.h>
76 #include <linux/if_ppp.h>
77 #endif /* __linux__ */
79 #else /* STREAMS */
80 #include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
81 #include <net/ppp_defs.h>
82 #include <net/pppio.h>
84 #endif /* STREAMS */
86 int vflag, rflag, zflag; /* select type of display */
87 int aflag; /* print absolute values, not deltas */
88 int dflag; /* print data rates, not bytes */
89 int interval, count;
90 int infinite;
91 int unit;
92 int s; /* socket or /dev/ppp file descriptor */
93 int signalled; /* set if alarm goes off "early" */
94 char *progname;
95 char *interface;
97 #if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT)
98 extern int optind;
99 extern char *optarg;
100 #endif
103 * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the
104 * device name.
106 #if !defined(PPP_DRV_NAME)
107 #define PPP_DRV_NAME "ppp"
108 #endif /* !defined(PPP_DRV_NAME) */
110 static void usage __P((void));
111 static void catchalarm __P((int));
112 static void get_ppp_stats __P((struct ppp_stats *));
113 static void get_ppp_cstats __P((struct ppp_comp_stats *));
114 static void intpr __P((void));
116 int main __P((int, char *argv[]));
118 static void
119 usage()
121 fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n",
122 progname);
123 exit(1);
127 * Called if an interval expires before intpr has completed a loop.
128 * Sets a flag to not wait for the alarm.
130 static void
131 catchalarm(arg)
132 int arg;
134 signalled = 1;
138 #ifndef STREAMS
139 static void
140 get_ppp_stats(curp)
141 struct ppp_stats *curp;
143 struct ifpppstatsreq req;
145 memset (&req, 0, sizeof (req));
147 #ifdef __linux__
148 req.stats_ptr = (caddr_t) &req.stats;
149 #undef ifr_name
150 #define ifr_name ifr__name
151 #endif
153 strncpy(req.ifr_name, interface, sizeof(req.ifr_name));
154 if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
155 fprintf(stderr, "%s: ", progname);
156 if (errno == ENOTTY)
157 fprintf(stderr, "kernel support missing\n");
158 else
159 perror("couldn't get PPP statistics");
160 exit(1);
162 *curp = req.stats;
165 static void
166 get_ppp_cstats(csp)
167 struct ppp_comp_stats *csp;
169 struct ifpppcstatsreq creq;
171 memset (&creq, 0, sizeof (creq));
173 #ifdef __linux__
174 creq.stats_ptr = (caddr_t) &creq.stats;
175 #undef ifr_name
176 #define ifr_name ifr__name
177 #endif
179 strncpy(creq.ifr_name, interface, sizeof(creq.ifr_name));
180 if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
181 fprintf(stderr, "%s: ", progname);
182 if (errno == ENOTTY) {
183 fprintf(stderr, "no kernel compression support\n");
184 if (zflag)
185 exit(1);
186 rflag = 0;
187 } else {
188 perror("couldn't get PPP compression stats");
189 exit(1);
193 #ifdef __linux__
194 if (creq.stats.c.bytes_out == 0) {
195 creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes;
196 creq.stats.c.in_count = creq.stats.c.unc_bytes;
198 if (creq.stats.c.bytes_out == 0)
199 creq.stats.c.ratio = 0.0;
200 else
201 creq.stats.c.ratio = 256.0 * creq.stats.c.in_count /
202 creq.stats.c.bytes_out;
204 if (creq.stats.d.bytes_out == 0) {
205 creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes;
206 creq.stats.d.in_count = creq.stats.d.unc_bytes;
208 if (creq.stats.d.bytes_out == 0)
209 creq.stats.d.ratio = 0.0;
210 else
211 creq.stats.d.ratio = 256.0 * creq.stats.d.in_count /
212 creq.stats.d.bytes_out;
213 #endif
215 *csp = creq.stats;
218 #else /* STREAMS */
221 strioctl(fd, cmd, ptr, ilen, olen)
222 int fd, cmd, ilen, olen;
223 char *ptr;
225 struct strioctl str;
227 str.ic_cmd = cmd;
228 str.ic_timout = 0;
229 str.ic_len = ilen;
230 str.ic_dp = ptr;
231 if (ioctl(fd, I_STR, &str) == -1)
232 return -1;
233 if (str.ic_len != olen)
234 fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
235 olen, str.ic_len, cmd);
236 return 0;
239 static void
240 get_ppp_stats(curp)
241 struct ppp_stats *curp;
243 if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
244 fprintf(stderr, "%s: ", progname);
245 if (errno == EINVAL)
246 fprintf(stderr, "kernel support missing\n");
247 else
248 perror("couldn't get PPP statistics");
249 exit(1);
253 static void
254 get_ppp_cstats(csp)
255 struct ppp_comp_stats *csp;
257 if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
258 fprintf(stderr, "%s: ", progname);
259 if (errno == ENOTTY) {
260 fprintf(stderr, "no kernel compression support\n");
261 if (zflag)
262 exit(1);
263 rflag = 0;
264 } else {
265 perror("couldn't get PPP compression statistics");
266 exit(1);
271 #endif /* STREAMS */
273 #define MAX0(a) ((int)(a) > 0? (a): 0)
274 #define V(offset) MAX0(cur.offset - old.offset)
275 #define W(offset) MAX0(ccs.offset - ocs.offset)
277 #define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i)))
278 #define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes))
280 #define KBPS(n) ((n) / (interval * 1000.0))
283 * Print a running summary of interface statistics.
284 * Repeat display every interval seconds, showing statistics
285 * collected over that interval. Assumes that interval is non-zero.
286 * First line printed is cumulative.
288 static void
289 intpr()
291 register int line = 0;
292 sigset_t oldmask, mask;
293 char *bunit;
294 int ratef = 0;
295 struct ppp_stats cur, old;
296 struct ppp_comp_stats ccs, ocs;
298 memset(&old, 0, sizeof(old));
299 memset(&ocs, 0, sizeof(ocs));
301 while (1) {
302 get_ppp_stats(&cur);
303 if (zflag || rflag)
304 get_ppp_cstats(&ccs);
306 (void)signal(SIGALRM, catchalarm);
307 signalled = 0;
308 (void)alarm(interval);
310 if ((line % 20) == 0) {
311 if (zflag) {
312 printf("IN: COMPRESSED INCOMPRESSIBLE COMP | ");
313 printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n");
314 bunit = dflag? "KB/S": "BYTE";
315 printf(" %s PACK %s PACK RATIO | ", bunit, bunit);
316 printf(" %s PACK %s PACK RATIO", bunit, bunit);
317 } else {
318 printf("%8.8s %6.6s %6.6s",
319 "IN", "PACK", "VJCOMP");
321 if (!rflag)
322 printf(" %6.6s %6.6s", "VJUNC", "VJERR");
323 if (vflag)
324 printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ");
325 if (rflag)
326 printf(" %6.6s %6.6s", "RATIO", "UBYTE");
327 printf(" | %8.8s %6.6s %6.6s",
328 "OUT", "PACK", "VJCOMP");
330 if (!rflag)
331 printf(" %6.6s %6.6s", "VJUNC", "NON-VJ");
332 if (vflag)
333 printf(" %6.6s %6.6s", "VJSRCH", "VJMISS");
334 if (rflag)
335 printf(" %6.6s %6.6s", "RATIO", "UBYTE");
337 putchar('\n');
340 if (zflag) {
341 if (ratef) {
342 printf("%8.3f %6u %8.3f %6u %6.2f",
343 KBPS(W(d.comp_bytes)),
344 W(d.comp_packets),
345 KBPS(W(d.inc_bytes)),
346 W(d.inc_packets),
347 ccs.d.ratio / 256.0);
348 printf(" | %8.3f %6u %8.3f %6u %6.2f",
349 KBPS(W(c.comp_bytes)),
350 W(c.comp_packets),
351 KBPS(W(c.inc_bytes)),
352 W(c.inc_packets),
353 ccs.c.ratio / 256.0);
354 } else {
355 printf("%8u %6u %8u %6u %6.2f",
356 W(d.comp_bytes),
357 W(d.comp_packets),
358 W(d.inc_bytes),
359 W(d.inc_packets),
360 ccs.d.ratio / 256.0);
361 printf(" | %8u %6u %8u %6u %6.2f",
362 W(c.comp_bytes),
363 W(c.comp_packets),
364 W(c.inc_bytes),
365 W(c.inc_packets),
366 ccs.c.ratio / 256.0);
369 } else {
370 if (ratef)
371 printf("%8.3f", KBPS(V(p.ppp_ibytes)));
372 else
373 printf("%8u", V(p.ppp_ibytes));
374 printf(" %6u %6u",
375 V(p.ppp_ipackets),
376 V(vj.vjs_compressedin));
377 if (!rflag)
378 printf(" %6u %6u",
379 V(vj.vjs_uncompressedin),
380 V(vj.vjs_errorin));
381 if (vflag)
382 printf(" %6u %6u",
383 V(vj.vjs_tossed),
384 V(p.ppp_ipackets) - V(vj.vjs_compressedin)
385 - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin));
386 if (rflag) {
387 printf(" %6.2f ", CRATE(d));
388 if (ratef)
389 printf("%6.2f", KBPS(W(d.unc_bytes)));
390 else
391 printf("%6u", W(d.unc_bytes));
393 if (ratef)
394 printf(" | %8.3f", KBPS(V(p.ppp_obytes)));
395 else
396 printf(" | %8u", V(p.ppp_obytes));
397 printf(" %6u %6u",
398 V(p.ppp_opackets),
399 V(vj.vjs_compressed));
400 if (!rflag)
401 printf(" %6u %6u",
402 V(vj.vjs_packets) - V(vj.vjs_compressed),
403 V(p.ppp_opackets) - V(vj.vjs_packets));
404 if (vflag)
405 printf(" %6u %6u",
406 V(vj.vjs_searches),
407 V(vj.vjs_misses));
408 if (rflag) {
409 printf(" %6.2f ", CRATE(c));
410 if (ratef)
411 printf("%6.2f", KBPS(W(c.unc_bytes)));
412 else
413 printf("%6u", W(c.unc_bytes));
418 putchar('\n');
419 fflush(stdout);
420 line++;
422 count--;
423 if (!infinite && !count)
424 break;
426 sigemptyset(&mask);
427 sigaddset(&mask, SIGALRM);
428 sigprocmask(SIG_BLOCK, &mask, &oldmask);
429 if (!signalled) {
430 sigemptyset(&mask);
431 sigsuspend(&mask);
433 sigprocmask(SIG_SETMASK, &oldmask, NULL);
434 signalled = 0;
435 (void)alarm(interval);
437 if (!aflag) {
438 old = cur;
439 ocs = ccs;
440 ratef = dflag;
446 main(argc, argv)
447 int argc;
448 char *argv[];
450 int c;
451 #ifdef STREAMS
452 char *dev;
453 #endif
455 interface = PPP_DRV_NAME "0";
456 if ((progname = strrchr(argv[0], '/')) == NULL)
457 progname = argv[0];
458 else
459 ++progname;
461 while ((c = getopt(argc, argv, "advrzc:w:")) != -1) {
462 switch (c) {
463 case 'a':
464 ++aflag;
465 break;
466 case 'd':
467 ++dflag;
468 break;
469 case 'v':
470 ++vflag;
471 break;
472 case 'r':
473 ++rflag;
474 break;
475 case 'z':
476 ++zflag;
477 break;
478 case 'c':
479 count = atoi(optarg);
480 if (count <= 0)
481 usage();
482 break;
483 case 'w':
484 interval = atoi(optarg);
485 if (interval <= 0)
486 usage();
487 break;
488 default:
489 usage();
492 argc -= optind;
493 argv += optind;
495 if (!interval && count)
496 interval = 5;
497 if (interval && !count)
498 infinite = 1;
499 if (!interval && !count)
500 count = 1;
501 if (aflag)
502 dflag = 0;
504 if (argc > 1)
505 usage();
506 if (argc > 0)
507 interface = argv[0];
509 if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) {
510 fprintf(stderr, "%s: invalid interface '%s' specified\n",
511 progname, interface);
514 #ifndef STREAMS
516 struct ifreq ifr;
518 s = socket(AF_INET, SOCK_DGRAM, 0);
519 if (s < 0) {
520 fprintf(stderr, "%s: ", progname);
521 perror("couldn't create IP socket");
522 exit(1);
525 #ifdef __linux__
526 #undef ifr_name
527 #define ifr_name ifr_ifrn.ifrn_name
528 #endif
529 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
530 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
531 fprintf(stderr, "%s: nonexistent interface '%s' specified\n",
532 progname, interface);
533 exit(1);
537 #else /* STREAMS */
538 #ifdef __osf__
539 dev = "/dev/streams/ppp";
540 #else
541 dev = "/dev/" PPP_DRV_NAME;
542 #endif
543 if ((s = open(dev, O_RDONLY)) < 0) {
544 fprintf(stderr, "%s: couldn't open ", progname);
545 perror(dev);
546 exit(1);
548 if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) {
549 fprintf(stderr, "%s: ppp%d is not available\n", progname, unit);
550 exit(1);
553 #endif /* STREAMS */
555 intpr();
556 exit(0);