1 /* $OpenBSD: pppstats.c,v 1.15 2024/11/04 11:12:52 deraadt 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 * Contributed by Van Jacobson (van@ee.lbl.gov), Dec 31, 1989. 21 * 22 * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of 23 * California. All rights reserved. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 3. Neither the name of the University nor the names of its contributors 34 * may be used to endorse or promote products derived from this software 35 * without specific prior written permission. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 */ 49 50 #include <sys/types.h> 51 #include <sys/ioctl.h> 52 #include <sys/socket.h> 53 #include <net/ppp_defs.h> 54 #include <net/if.h> 55 #include <net/if_ppp.h> 56 #include <stdio.h> 57 #include <stddef.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <ctype.h> 61 #include <errno.h> 62 #include <signal.h> 63 #include <fcntl.h> 64 #include <err.h> 65 #include <unistd.h> 66 67 int vflag, rflag, zflag; /* select type of display */ 68 int aflag; /* print absolute values, not deltas */ 69 int dflag; /* print data rates, not bytes */ 70 int interval, count; 71 int infinite; 72 int unit; 73 int s; /* socket file descriptor */ 74 int signalled; /* set if alarm goes off "early" */ 75 char interface[IFNAMSIZ]; 76 77 void usage(void); 78 void catchalarm(int); 79 void get_ppp_stats(struct ppp_stats *); 80 void get_ppp_cstats(struct ppp_comp_stats *); 81 void intpr(void); 82 int main(int, char *argv[]); 83 84 void 85 usage(void) 86 { 87 extern char *__progname; 88 89 fprintf(stderr, 90 "usage: %s [-adrvz] [-c count] [-w wait] [interface]\n", 91 __progname); 92 exit(1); 93 } 94 95 /* 96 * Called if an interval expires before intpr has completed a loop. 97 * Sets a flag to not wait for the alarm. 98 */ 99 void 100 catchalarm(int arg) 101 { 102 signalled = 1; 103 } 104 105 void 106 get_ppp_stats(struct ppp_stats *curp) 107 { 108 struct ifpppstatsreq req; 109 110 memset(&req, 0, sizeof(req)); 111 (void)strlcpy(req.ifr_name, interface, sizeof(req.ifr_name)); 112 113 if (ioctl(s, SIOCGPPPSTATS, &req) < 0) { 114 if (errno == ENOTTY) 115 errx(1, "kernel support missing"); 116 else 117 err(1, "couldn't get PPP statistics"); 118 } 119 *curp = req.stats; 120 } 121 122 void 123 get_ppp_cstats(struct ppp_comp_stats *csp) 124 { 125 struct ifpppcstatsreq creq; 126 127 memset(&creq, 0, sizeof(creq)); 128 (void)strlcpy(creq.ifr_name, interface, sizeof(creq.ifr_name)); 129 130 if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) { 131 if (errno == ENOTTY) { 132 warnx("no kernel compression support"); 133 if (zflag) 134 exit(1); 135 rflag = 0; 136 } else 137 err(1, "couldn't get PPP compression stats"); 138 } 139 *csp = creq.stats; 140 } 141 142 #define MAX0(a) ((int)(a) > 0? (a): 0) 143 #define V(offset) MAX0(cur.offset - old.offset) 144 #define W(offset) MAX0(ccs.offset - ocs.offset) 145 146 #define RATIO(c, i, u) ((c) == 0? 1.0: (u) / ((double)(c) + (i))) 147 #define CRATE(x) RATIO(W(x.comp_bytes), W(x.inc_bytes), W(x.unc_bytes)) 148 149 #define KBPS(n) ((n) / (interval * 1000.0)) 150 151 /* 152 * Print a running summary of interface statistics. 153 * Repeat display every interval seconds, showing statistics 154 * collected over that interval. Assumes that interval is non-zero. 155 * First line printed is cumulative. 156 */ 157 void 158 intpr(void) 159 { 160 register int line = 0; 161 sigset_t oldmask, mask; 162 char *bunit; 163 int ratef = 0; 164 struct ppp_stats cur, old; 165 struct ppp_comp_stats ccs, ocs; 166 167 memset(&old, 0, sizeof(old)); 168 memset(&ocs, 0, sizeof(ocs)); 169 170 for (;;) { 171 get_ppp_stats(&cur); 172 if (zflag || rflag) 173 get_ppp_cstats(&ccs); 174 175 (void)signal(SIGALRM, catchalarm); 176 signalled = 0; 177 (void)alarm(interval); 178 179 if ((line % 20) == 0) { 180 if (zflag) { 181 printf("IN: COMPRESSED INCOMPRESSIBLE COMP | "); 182 printf("OUT: COMPRESSED INCOMPRESSIBLE COMP\n"); 183 bunit = dflag? "KB/S": "BYTE"; 184 printf(" %s PACK %s PACK RATIO | ", 185 bunit, bunit); 186 printf(" %s PACK %s PACK RATIO", 187 bunit, bunit); 188 } else { 189 printf("%8.8s %6.6s %6.6s", 190 "IN", "PACK", "VJCOMP"); 191 192 if (!rflag) 193 printf(" %6.6s %6.6s", "VJUNC", "VJERR"); 194 if (vflag) 195 printf(" %6.6s %6.6s", "VJTOSS", "NON-VJ"); 196 if (rflag) 197 printf(" %6.6s %6.6s", "RATIO", "UBYTE"); 198 printf(" | %8.8s %6.6s %6.6s", 199 "OUT", "PACK", "VJCOMP"); 200 201 if (!rflag) 202 printf(" %6.6s %6.6s", "VJUNC", "NON-VJ"); 203 if (vflag) 204 printf(" %6.6s %6.6s", "VJSRCH", "VJMISS"); 205 if (rflag) 206 printf(" %6.6s %6.6s", "RATIO", "UBYTE"); 207 } 208 putchar('\n'); 209 } 210 211 if (zflag) { 212 if (ratef) { 213 printf("%8.3f %6u %8.3f %6u %6.2f", 214 KBPS(W(d.comp_bytes)), W(d.comp_packets), 215 KBPS(W(d.inc_bytes)), W(d.inc_packets), 216 ccs.d.ratio * 256.0); 217 218 printf(" | %8.3f %6u %8.3f %6u %6.2f", 219 KBPS(W(c.comp_bytes)), W(c.comp_packets), 220 KBPS(W(c.inc_bytes)), W(c.inc_packets), 221 ccs.c.ratio * 256.0); 222 } else { 223 printf("%8u %6u %8u %6u %6.2f", 224 W(d.comp_bytes), W(d.comp_packets), 225 W(d.inc_bytes), W(d.inc_packets), 226 ccs.d.ratio * 256.0); 227 228 printf(" | %8u %6u %8u %6u %6.2f", 229 W(c.comp_bytes), W(c.comp_packets), 230 W(c.inc_bytes), W(c.inc_packets), 231 ccs.c.ratio * 256.0); 232 } 233 } else { 234 if (ratef) 235 printf("%8.3f", KBPS(V(p.ppp_ibytes))); 236 else 237 printf("%8u", V(p.ppp_ibytes)); 238 printf(" %6u %6u", V(p.ppp_ipackets), 239 V(vj.vjs_compressedin)); 240 if (!rflag) 241 printf(" %6u %6u", V(vj.vjs_uncompressedin), 242 V(vj.vjs_errorin)); 243 if (vflag) 244 printf(" %6u %6u", V(vj.vjs_tossed), 245 V(p.ppp_ipackets) - 246 V(vj.vjs_compressedin) - 247 V(vj.vjs_uncompressedin) - 248 V(vj.vjs_errorin)); 249 if (rflag) { 250 printf(" %6.2f ", CRATE(d)); 251 if (ratef) 252 printf("%6.2f", KBPS(W(d.unc_bytes))); 253 else 254 printf("%6u", W(d.unc_bytes)); 255 } 256 if (ratef) 257 printf(" | %8.3f", KBPS(V(p.ppp_obytes))); 258 else 259 printf(" | %8u", V(p.ppp_obytes)); 260 261 printf(" %6u %6u", V(p.ppp_opackets), 262 V(vj.vjs_compressed)); 263 if (!rflag) 264 printf(" %6u %6u", 265 V(vj.vjs_packets) - V(vj.vjs_compressed), 266 V(p.ppp_opackets) - V(vj.vjs_packets)); 267 if (vflag) 268 printf(" %6u %6u", V(vj.vjs_searches), 269 V(vj.vjs_misses)); 270 if (rflag) { 271 printf(" %6.2f ", CRATE(c)); 272 if (ratef) 273 printf("%6.2f", KBPS(W(c.unc_bytes))); 274 else 275 printf("%6u", W(c.unc_bytes)); 276 } 277 } 278 279 putchar('\n'); 280 fflush(stdout); 281 line++; 282 283 count--; 284 if (!infinite && !count) 285 break; 286 287 sigemptyset(&mask); 288 sigaddset(&mask, SIGALRM); 289 sigprocmask(SIG_BLOCK, &mask, &oldmask); 290 if (signalled == 0) { 291 sigemptyset(&mask); 292 sigsuspend(&mask); 293 } 294 sigprocmask(SIG_SETMASK, &oldmask, NULL); 295 signalled = 0; 296 (void)alarm(interval); 297 if (!aflag) { 298 old = cur; 299 ocs = ccs; 300 ratef = dflag; 301 } 302 } 303 } 304 305 int 306 main(int argc, char *argv[]) 307 { 308 const char *errstr; 309 int c; 310 struct ifreq ifr; 311 312 (void)strlcpy(interface, "ppp0", sizeof(interface)); 313 314 while ((c = getopt(argc, argv, "advrzc:w:")) != -1) { 315 switch (c) { 316 case 'a': 317 aflag = 1; 318 break; 319 case 'd': 320 dflag = 1; 321 break; 322 case 'v': 323 vflag = 1; 324 break; 325 case 'r': 326 rflag = 1; 327 break; 328 case 'z': 329 zflag = 1; 330 break; 331 case 'c': 332 count = strtonum(optarg, 1, 1000, &errstr); 333 if (errstr) 334 usage(); 335 break; 336 case 'w': 337 interval = strtonum(optarg, 1, 1000, &errstr); 338 if (errstr) 339 usage(); 340 break; 341 default: 342 usage(); 343 } 344 } 345 argc -= optind; 346 argv += optind; 347 348 if (!interval && count) 349 interval = 5; 350 if (interval && !count) 351 infinite = 1; 352 if (!interval && !count) 353 count = 1; 354 if (aflag) 355 dflag = 0; 356 357 if (argc > 1) 358 usage(); 359 if (argc > 0) 360 (void)strlcpy(interface, argv[0], sizeof(interface)); 361 362 if (sscanf(interface, "ppp%d", &unit) != 1 || unit < 0) 363 errx(1, "invalid interface '%s' specified", interface); 364 365 s = socket(AF_INET, SOCK_DGRAM, 0); 366 if (s < 0) 367 err(1, "couldn't create IP socket"); 368 (void)strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); 369 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 370 errx(1, "nonexistent interface '%s' specified", interface); 371 372 intpr(); 373 exit(0); 374 } 375