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