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