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