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) 1989 Regents of the University of California. 19 * All rights reserved. 20 * 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. 32 */ 33 34#ifndef __STDC__ 35#define const 36#endif 37 38#ifndef lint 39static const char rcsid[] = "$Id: pppstats.c,v 1.29 2002/10/27 12:56:26 fcusack Exp $"; 40#endif 41 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> 54 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__ */ 78 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> 83 84#endif /* STREAMS */ 85 86int vflag, rflag, zflag; /* select type of display */ 87int aflag; /* print absolute values, not deltas */ 88int dflag; /* print data rates, not bytes */ 89int interval, count; 90int infinite; 91int unit; 92int s; /* socket or /dev/ppp file descriptor */ 93int signalled; /* set if alarm goes off "early" */ 94char *progname; 95char *interface; 96 97#if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT) 98extern int optind; 99extern char *optarg; 100#endif 101 102/* 103 * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the 104 * device name. 105 */ 106#if !defined(PPP_DRV_NAME) 107#define PPP_DRV_NAME "ppp" 108#endif /* !defined(PPP_DRV_NAME) */ 109 110static void usage __P((void)); 111static void catchalarm __P((int)); 112static void get_ppp_stats __P((struct ppp_stats *)); 113static void get_ppp_cstats __P((struct ppp_comp_stats *)); 114static void intpr __P((void)); 115 116int main __P((int, char *argv[])); 117 118static void 119usage() 120{ 121 fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n", 122 progname); 123 exit(1); 124} 125 126/* 127 * Called if an interval expires before intpr has completed a loop. 128 * Sets a flag to not wait for the alarm. 129 */ 130static void 131catchalarm(arg) 132 int arg; 133{ 134 signalled = 1; 135} 136 137 138#ifndef STREAMS 139static void 140get_ppp_stats(curp) 141 struct ppp_stats *curp; 142{ 143 struct ifpppstatsreq req; 144 145 memset (&req, 0, sizeof (req)); 146 147#ifdef __linux__ 148 req.stats_ptr = (caddr_t) &req.stats; 149#undef ifr_name 150#define ifr_name ifr__name 151#endif 152 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); 161 } 162 *curp = req.stats; 163} 164 165static void 166get_ppp_cstats(csp) 167 struct ppp_comp_stats *csp; 168{ 169 struct ifpppcstatsreq creq; 170 171 memset (&creq, 0, sizeof (creq)); 172 173#ifdef __linux__ 174 creq.stats_ptr = (caddr_t) &creq.stats; 175#undef ifr_name 176#define ifr_name ifr__name 177#endif 178 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); 190 } 191 } 192 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; 197 } 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; 203 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; 207 } 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 214 215 *csp = creq.stats; 216} 217 218#else /* STREAMS */ 219 220int 221strioctl(fd, cmd, ptr, ilen, olen) 222 int fd, cmd, ilen, olen; 223 char *ptr; 224{ 225 struct strioctl str; 226 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; 237} 238 239static void 240get_ppp_stats(curp) 241 struct ppp_stats *curp; 242{ 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); 250 } 251} 252 253static void 254get_ppp_cstats(csp) 255 struct ppp_comp_stats *csp; 256{ 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); 267 } 268 } 269} 270 271#endif /* STREAMS */ 272 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) 276 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)) 279 280#define KBPS(n) ((n) / (interval * 1000.0)) 281 282/* 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. 287 */ 288static void 289intpr() 290{ 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; 297 298 memset(&old, 0, sizeof(old)); 299 memset(&ocs, 0, sizeof(ocs)); 300 301 while (1) { 302 get_ppp_stats(&cur); 303 if (zflag || rflag) 304 get_ppp_cstats(&ccs); 305 306 (void)signal(SIGALRM, catchalarm); 307 signalled = 0; 308 (void)alarm(interval); 309 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"); 320 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"); 329 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"); 336 } 337 putchar('\n'); 338 } 339 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); 367 } 368 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)); 392 } 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)); 414 } 415 416 } 417 418 putchar('\n'); 419 fflush(stdout); 420 line++; 421 422 count--; 423 if (!infinite && !count) 424 break; 425 426 sigemptyset(&mask); 427 sigaddset(&mask, SIGALRM); 428 sigprocmask(SIG_BLOCK, &mask, &oldmask); 429 if (!signalled) { 430 sigemptyset(&mask); 431 sigsuspend(&mask); 432 } 433 sigprocmask(SIG_SETMASK, &oldmask, NULL); 434 signalled = 0; 435 (void)alarm(interval); 436 437 if (!aflag) { 438 old = cur; 439 ocs = ccs; 440 ratef = dflag; 441 } 442 } 443} 444 445int 446main(argc, argv) 447 int argc; 448 char *argv[]; 449{ 450 int c; 451#ifdef STREAMS 452 char *dev; 453#endif 454 455 interface = PPP_DRV_NAME "0"; 456 if ((progname = strrchr(argv[0], '/')) == NULL) 457 progname = argv[0]; 458 else 459 ++progname; 460 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(); 490 } 491 } 492 argc -= optind; 493 argv += optind; 494 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; 503 504 if (argc > 1) 505 usage(); 506 if (argc > 0) 507 interface = argv[0]; 508 509 if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) { 510 fprintf(stderr, "%s: invalid interface '%s' specified\n", 511 progname, interface); 512 } 513 514#ifndef STREAMS 515 { 516 struct ifreq ifr; 517 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); 523 } 524 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); 534 } 535 } 536 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); 547 } 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); 551 } 552 553#endif /* STREAMS */ 554 555 intpr(); 556 exit(0); 557} 558