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