1/* $NetBSD: pppstats.c,v 1.5 2021/01/09 16:39:28 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 43static 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.5 2021/01/09 16:39:28 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 93int vflag, rflag, zflag; /* select type of display */ 94int aflag; /* print absolute values, not deltas */ 95int dflag; /* print data rates, not bytes */ 96int interval, count; 97int infinite; 98int s; /* socket or /dev/ppp file descriptor */ 99int signalled; /* set if alarm goes off "early" */ 100char *progname; 101char *interface; 102char *fmt; 103 104#if defined(SUNOS4) || defined(ULTRIX) || defined(NeXT) 105extern int optind; 106extern char *optarg; 107#endif 108 109/* 110 * If PPP_DRV_NAME is not defined, use the legacy "ppp" as the 111 * device name. 112 */ 113#if !defined(PPP_DRV_NAME) 114#define PPP_DRV_NAME "ppp" 115#endif /* !defined(PPP_DRV_NAME) */ 116#if !defined(SL_DRV_NAME) 117#define SL_DRV_NAME "sl" 118#endif /* !defined(SL_DRV_NAME) */ 119 120static void usage(void); 121static void catchalarm(int); 122static void get_ppp_stats(struct ppp_stats *); 123static void get_ppp_cstats(struct ppp_comp_stats *); 124static void intpr(void); 125 126int main(int, char *argv[]); 127 128static void 129usage(void) 130{ 131 fprintf(stderr, "Usage: %s [-a|-d] [-v|-r|-z] [-c count] [-w wait] [interface]\n", 132 progname); 133 exit(1); 134} 135 136/* 137 * Called if an interval expires before intpr has completed a loop. 138 * Sets a flag to not wait for the alarm. 139 */ 140static void 141catchalarm(int arg) 142{ 143 signalled = 1; 144} 145 146 147#ifndef STREAMS 148static void 149get_ppp_stats(struct ppp_stats *curp) 150{ 151 struct ifpppstatsreq req; 152 153 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, IFNAMSIZ); 162 req.ifr_name[IFNAMSIZ - 1] = 0; 163 if (ioctl(s, SIOCGPPPSTATS, &req) < 0) { 164 fprintf(stderr, "%s: ", progname); 165 if (errno == ENOTTY) 166 fprintf(stderr, "kernel support missing\n"); 167 else 168 perror("couldn't get PPP statistics"); 169 exit(1); 170 } 171 *curp = req.stats; 172} 173 174static void 175get_ppp_cstats(struct ppp_comp_stats *csp) 176{ 177 struct ifpppcstatsreq creq; 178 179 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, IFNAMSIZ); 188 creq.ifr_name[IFNAMSIZ - 1] = 0; 189 if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) { 190 fprintf(stderr, "%s: ", progname); 191 if (errno == ENOTTY) { 192 fprintf(stderr, "no kernel compression support\n"); 193 if (zflag) 194 exit(1); 195 rflag = 0; 196 } else { 197 perror("couldn't get PPP compression stats"); 198 exit(1); 199 } 200 } 201 202#ifdef __linux__ 203 if (creq.stats.c.bytes_out == 0) { 204 creq.stats.c.bytes_out = creq.stats.c.comp_bytes + creq.stats.c.inc_bytes; 205 creq.stats.c.in_count = creq.stats.c.unc_bytes; 206 } 207 if (creq.stats.c.bytes_out == 0) 208 creq.stats.c.ratio = 0.0; 209 else 210 creq.stats.c.ratio = 256.0 * creq.stats.c.in_count / 211 creq.stats.c.bytes_out; 212 213 if (creq.stats.d.bytes_out == 0) { 214 creq.stats.d.bytes_out = creq.stats.d.comp_bytes + creq.stats.d.inc_bytes; 215 creq.stats.d.in_count = creq.stats.d.unc_bytes; 216 } 217 if (creq.stats.d.bytes_out == 0) 218 creq.stats.d.ratio = 0.0; 219 else 220 creq.stats.d.ratio = 256.0 * creq.stats.d.in_count / 221 creq.stats.d.bytes_out; 222#endif 223 224 *csp = creq.stats; 225} 226 227#else /* STREAMS */ 228 229int 230strioctl(int fd, int cmd, char *ptr, int ilen, int olen) 231{ 232 struct strioctl str; 233 234 str.ic_cmd = cmd; 235 str.ic_timout = 0; 236 str.ic_len = ilen; 237 str.ic_dp = ptr; 238 if (ioctl(fd, I_STR, &str) == -1) 239 return -1; 240 if (str.ic_len != olen) 241 fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n", 242 olen, str.ic_len, cmd); 243 return 0; 244} 245 246static void 247get_ppp_stats(struct ppp_stats *curp) 248{ 249 if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) { 250 fprintf(stderr, "%s: ", progname); 251 if (errno == EINVAL) 252 fprintf(stderr, "kernel support missing\n"); 253 else 254 perror("couldn't get PPP statistics"); 255 exit(1); 256 } 257} 258 259static void 260get_ppp_cstats(struct ppp_comp_stats *csp) 261{ 262 if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) { 263 fprintf(stderr, "%s: ", progname); 264 if (errno == ENOTTY) { 265 fprintf(stderr, "no kernel compression support\n"); 266 if (zflag) 267 exit(1); 268 rflag = 0; 269 } else { 270 perror("couldn't get PPP compression statistics"); 271 exit(1); 272 } 273 } 274} 275 276#endif /* STREAMS */ 277 278#define MAX0(a) ((int)(a) > 0? (a): 0) 279#define V(offset) MAX0(cur.offset - old.offset) 280#define W(offset) MAX0(ccs.offset - ocs.offset) 281 282#define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i))) 283#define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes)) 284 285#define KBPS(n) ((n) / (interval * 1000.0)) 286 287/* 288 * Print a running summary of interface statistics. 289 * Repeat display every interval seconds, showing statistics 290 * collected over that interval. Assumes that interval is non-zero. 291 * First line printed is cumulative. 292 */ 293static void 294intpr(void) 295{ 296 register int line = 0; 297 sigset_t oldmask, mask; 298 char *bunit; 299 int ratef = 0; 300 struct ppp_stats cur, old; 301 struct ppp_comp_stats ccs, ocs; 302 303 memset(&ccs, 0, sizeof(ccs)); 304 memset(&old, 0, sizeof(old)); 305 memset(&ocs, 0, sizeof(ocs)); 306 307 interface = PPP_DRV_NAME "0"; 308 while (1) { 309 get_ppp_stats(&cur); 310 if (zflag || rflag) 311 get_ppp_cstats(&ccs); 312 313 (void)signal(SIGALRM, catchalarm); 314 signalled = 0; 315 (void)alarm(interval); 316 317 if ((line % 20) == 0) { 318 if (zflag) { 319 printf("IN: COMPRESSED INCOMPRESSIBLE COMP | "); 320 printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n"); 321 bunit = dflag? "KB/S": "BYTE"; 322 printf(" %s PACK %s PACK RATIO | ", bunit, bunit); 323 printf(" %s PACK %s PACK RATIO", bunit, bunit); 324 } else { 325 printf("%8.8s %6.6s %6.6s", 326 "IN", "PACK", "VJCOMP"); 327 328 if (!rflag) 329 printf(" %6.6s %6.6s", "VJUNC", "VJERR"); 330 if (vflag) 331 printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ"); 332 if (rflag) 333 printf(" %6.6s %6.6s", "RATIO", "UBYTE"); 334 printf(" | %8.8s %6.6s %6.6s", 335 "OUT", "PACK", "VJCOMP"); 336 337 if (!rflag) 338 printf(" %6.6s %6.6s", "VJUNC", "NON-VJ"); 339 if (vflag) 340 printf(" %6.6s %6.6s", "VJSRCH", "VJMISS"); 341 if (rflag) 342 printf(" %6.6s %6.6s", "RATIO", "UBYTE"); 343 } 344 putchar('\n'); 345 } 346 347 if (zflag) { 348 if (ratef) { 349 printf("%8.3f %6u %8.3f %6u %6.2f", 350 KBPS(W(d.comp_bytes)), 351 W(d.comp_packets), 352 KBPS(W(d.inc_bytes)), 353 W(d.inc_packets), 354 ccs.d.ratio / 256.0); 355 printf(" | %8.3f %6u %8.3f %6u %6.2f", 356 KBPS(W(c.comp_bytes)), 357 W(c.comp_packets), 358 KBPS(W(c.inc_bytes)), 359 W(c.inc_packets), 360 ccs.c.ratio / 256.0); 361 } else { 362 printf("%8u %6u %8u %6u %6.2f", 363 W(d.comp_bytes), 364 W(d.comp_packets), 365 W(d.inc_bytes), 366 W(d.inc_packets), 367 ccs.d.ratio / 256.0); 368 printf(" | %8u %6u %8u %6u %6.2f", 369 W(c.comp_bytes), 370 W(c.comp_packets), 371 W(c.inc_bytes), 372 W(c.inc_packets), 373 ccs.c.ratio / 256.0); 374 } 375 376 } else { 377 if (ratef) 378 printf("%8.3f", KBPS(V(p.ppp_ibytes))); 379 else 380 printf("%8u", V(p.ppp_ibytes)); 381 printf(" %6u %6u", 382 V(p.ppp_ipackets), 383 V(vj.vjs_compressedin)); 384 if (!rflag) 385 printf(" %6u %6u", 386 V(vj.vjs_uncompressedin), 387 V(vj.vjs_errorin)); 388 if (vflag) 389 printf(" %6u %6u", 390 V(vj.vjs_tossed), 391 V(p.ppp_ipackets) - V(vj.vjs_compressedin) 392 - V(vj.vjs_uncompressedin) - V(vj.vjs_errorin)); 393 if (rflag) { 394 printf(" %6.2f ", CRATE(d)); 395 if (ratef) 396 printf("%6.2f", KBPS(W(d.unc_bytes))); 397 else 398 printf("%6u", W(d.unc_bytes)); 399 } 400 if (ratef) 401 printf(" | %8.3f", KBPS(V(p.ppp_obytes))); 402 else 403 printf(" | %8u", V(p.ppp_obytes)); 404 printf(" %6u %6u", 405 V(p.ppp_opackets), 406 V(vj.vjs_compressed)); 407 if (!rflag) 408 printf(" %6u %6u", 409 V(vj.vjs_packets) - V(vj.vjs_compressed), 410 V(p.ppp_opackets) - V(vj.vjs_packets)); 411 if (vflag) 412 printf(" %6u %6u", 413 V(vj.vjs_searches), 414 V(vj.vjs_misses)); 415 if (rflag) { 416 printf(" %6.2f ", CRATE(c)); 417 if (ratef) 418 printf("%6.2f", KBPS(W(c.unc_bytes))); 419 else 420 printf("%6u", W(c.unc_bytes)); 421 } 422 423 } 424 425 putchar('\n'); 426 fflush(stdout); 427 line++; 428 429 count--; 430 if (!infinite && !count) 431 break; 432 433 sigemptyset(&mask); 434 sigaddset(&mask, SIGALRM); 435 sigprocmask(SIG_BLOCK, &mask, &oldmask); 436 if (!signalled) { 437 sigemptyset(&mask); 438 sigsuspend(&mask); 439 } 440 sigprocmask(SIG_SETMASK, &oldmask, NULL); 441 signalled = 0; 442 (void)alarm(interval); 443 444 if (!aflag) { 445 old = cur; 446 ocs = ccs; 447 ratef = dflag; 448 } 449 } 450} 451 452int 453main(int argc, char *argv[]) 454{ 455 int c; 456#ifdef STREAMS 457 int unit; 458 char *dev; 459#endif 460 461 interface = PPP_DRV_NAME "0"; 462 if ((progname = strrchr(argv[0], '/')) == NULL) 463 progname = argv[0]; 464 else 465 ++progname; 466 467 if (strncmp(progname, SL_DRV_NAME, sizeof(SL_DRV_NAME) - 1) == 0) { 468 interface = SL_DRV_NAME "0"; 469 fmt = SL_DRV_NAME "%d"; 470 } else { 471 interface = PPP_DRV_NAME "0"; 472 fmt = PPP_DRV_NAME "%d"; 473 } 474 while ((c = getopt(argc, argv, "advrzc:w:")) != -1) { 475 switch (c) { 476 case 'a': 477 ++aflag; 478 break; 479 case 'd': 480 ++dflag; 481 break; 482 case 'v': 483 ++vflag; 484 break; 485 case 'r': 486 ++rflag; 487 break; 488 case 'z': 489 ++zflag; 490 break; 491 case 'c': 492 count = atoi(optarg); 493 if (count <= 0) 494 usage(); 495 break; 496 case 'w': 497 interval = atoi(optarg); 498 if (interval <= 0) 499 usage(); 500 break; 501 default: 502 usage(); 503 } 504 } 505 argc -= optind; 506 argv += optind; 507 508 if (!interval && count) 509 interval = 5; 510 if (interval && !count) 511 infinite = 1; 512 if (!interval && !count) 513 count = 1; 514 if (aflag) 515 dflag = 0; 516 517 if (argc > 1) 518 usage(); 519 if (argc > 0) 520 interface = argv[0]; 521 522#ifndef STREAMS 523 { 524 struct ifreq ifr; 525 526 s = socket(AF_INET, SOCK_DGRAM, 0); 527 if (s < 0) { 528 fprintf(stderr, "%s: ", progname); 529 perror("couldn't create IP socket"); 530 exit(1); 531 } 532 533#ifdef __linux__ 534#undef ifr_name 535#define ifr_name ifr_ifrn.ifrn_name 536#endif 537 strncpy(ifr.ifr_name, interface, IFNAMSIZ); 538 ifr.ifr_name[IFNAMSIZ - 1] = 0; 539 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { 540 fprintf(stderr, "%s: nonexistent interface '%s' specified\n", 541 progname, interface); 542 exit(1); 543 } 544 } 545 546#else /* STREAMS */ 547 if (sscanf(interface, PPP_DRV_NAME "%d", &unit) != 1) { 548 fprintf(stderr, "%s: invalid interface '%s' specified\n", 549 progname, interface); 550 } 551 552#ifdef __osf__ 553 dev = "/dev/streams/ppp"; 554#else 555 dev = "/dev/" PPP_DRV_NAME; 556#endif 557 if ((s = open(dev, O_RDONLY)) < 0) { 558 fprintf(stderr, "%s: couldn't open ", progname); 559 perror(dev); 560 exit(1); 561 } 562 if (strioctl(s, PPPIO_ATTACH, &unit, sizeof(int), 0) < 0) { 563 fprintf(stderr, "%s: ppp%d is not available\n", progname, unit); 564 exit(1); 565 } 566 567#endif /* STREAMS */ 568 569 intpr(); 570 exit(0); 571} 572