if.c revision 1.62
1/* $NetBSD: if.c,v 1.62 2008/04/23 15:35:37 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36#else 37__RCSID("$NetBSD: if.c,v 1.62 2008/04/23 15:35:37 thorpej Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/types.h> 42#include <sys/protosw.h> 43#include <sys/socket.h> 44#include <sys/time.h> 45 46#include <net/if.h> 47#include <net/if_dl.h> 48#include <net/if_types.h> 49#include <netinet/in.h> 50#include <netinet/in_var.h> 51#include <netiso/iso.h> 52#include <netiso/iso_var.h> 53#include <arpa/inet.h> 54 55#include <kvm.h> 56#include <signal.h> 57#include <stdio.h> 58#include <stdlib.h> 59#include <string.h> 60#include <unistd.h> 61#include <netdb.h> 62 63#include "netstat.h" 64 65#define YES 1 66#define NO 0 67 68static void sidewaysintpr __P((u_int, u_long)); 69static void catchalarm __P((int)); 70 71/* 72 * Print a description of the network interfaces. 73 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 74 * which is a TAILQ_HEAD. 75 */ 76void 77intpr(interval, ifnetaddr, pfunc) 78 int interval; 79 u_long ifnetaddr; 80 void (*pfunc)(char *); 81{ 82 struct ifnet ifnet; 83 union { 84 struct ifaddr ifa; 85 struct in_ifaddr in; 86#ifdef INET6 87 struct in6_ifaddr in6; 88#endif /* INET6 */ 89 struct iso_ifaddr iso; 90 } ifaddr; 91 u_long ifaddraddr; 92 struct sockaddr *sa; 93 struct ifnet_head ifhead; /* TAILQ_HEAD */ 94 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 95 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 96#ifdef INET6 97 const int niflag = NI_NUMERICHOST; 98#endif 99 100 if (ifnetaddr == 0) { 101 printf("ifnet: symbol not defined\n"); 102 return; 103 } 104 if (interval) { 105 sidewaysintpr((unsigned)interval, ifnetaddr); 106 return; 107 } 108 109 /* 110 * Find the pointer to the first ifnet structure. Replace 111 * the pointer to the TAILQ_HEAD with the actual pointer 112 * to the first list element. 113 */ 114 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 115 return; 116 ifnetaddr = (u_long)ifhead.tqh_first; 117 118 if (!sflag & !pflag) { 119 if (bflag) { 120 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 121 "%10.10s %10.10s", 122 "Name", "Mtu", "Network", "Address", 123 "Ibytes", "Obytes"); 124 } else { 125 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 126 "%8.8s %5.5s %8.8s %5.5s %5.5s", 127 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 128 "Opkts", "Oerrs", "Colls"); 129 } 130 if (tflag) 131 printf(" %4.4s", "Time"); 132 if (dflag) 133 printf(" %5.5s", "Drops"); 134 putchar('\n'); 135 } 136 ifaddraddr = 0; 137 while (ifnetaddr || ifaddraddr) { 138 struct sockaddr_in *sin; 139#ifdef INET6 140 struct sockaddr_in6 *sin6; 141#endif /* INET6 */ 142 char *cp; 143 int n, m; 144 145 if (ifaddraddr == 0) { 146 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 147 return; 148 memmove(name, ifnet.if_xname, IFNAMSIZ); 149 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 150 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 151 if (interface != 0 && strcmp(name, interface) != 0) 152 continue; 153 cp = strchr(name, '\0'); 154 155 if (pfunc) { 156 (*pfunc)(name); 157 continue; 158 } 159 160 if ((ifnet.if_flags & IFF_UP) == 0) 161 *cp++ = '*'; 162 *cp = '\0'; 163 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 164 } 165 if (vflag) 166 n = strlen(name) < 5 ? 5 : strlen(name); 167 else 168 n = 5; 169 printf("%-*.*s %-5llu ", n, n, name, 170 (unsigned long long)ifnet.if_mtu); 171 if (ifaddraddr == 0) { 172 printf("%-13.13s ", "none"); 173 printf("%-17.17s ", "none"); 174 } else { 175 char hexsep = '.'; /* for hexprint */ 176 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 177 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 178 ifaddraddr = 0; 179 continue; 180 } 181#define CP(x) ((char *)(x)) 182 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 183 CP(&ifaddr); 184 sa = (struct sockaddr *)cp; 185 switch (sa->sa_family) { 186 case AF_UNSPEC: 187 printf("%-13.13s ", "none"); 188 printf("%-17.17s ", "none"); 189 break; 190 case AF_INET: 191 sin = (struct sockaddr_in *)sa; 192#ifdef notdef 193 /* 194 * can't use inet_makeaddr because kernel 195 * keeps nets unshifted. 196 */ 197 in = inet_makeaddr(ifaddr.in.ia_subnet, 198 INADDR_ANY); 199 cp = netname4(in.s_addr, 200 ifaddr.in.ia_subnetmask); 201#else 202 cp = netname4(ifaddr.in.ia_subnet, 203 ifaddr.in.ia_subnetmask); 204#endif 205 if (vflag) 206 n = strlen(cp) < 13 ? 13 : strlen(cp); 207 else 208 n = 13; 209 printf("%-*.*s ", n, n, cp); 210 cp = routename4(sin->sin_addr.s_addr); 211 if (vflag) 212 n = strlen(cp) < 17 ? 17 : strlen(cp); 213 else 214 n = 17; 215 printf("%-*.*s ", n, n, cp); 216 if (aflag) { 217 u_long multiaddr; 218 struct in_multi inm; 219 220 multiaddr = (u_long) 221 ifaddr.in.ia_multiaddrs.lh_first; 222 while (multiaddr != 0) { 223 kread(multiaddr, (char *)&inm, 224 sizeof inm); 225 printf("\n%25s %-17.17s ", "", 226 routename4( 227 inm.inm_addr.s_addr)); 228 multiaddr = 229 (u_long)inm.inm_list.le_next; 230 } 231 } 232 break; 233#ifdef INET6 234 case AF_INET6: 235 sin6 = (struct sockaddr_in6 *)sa; 236#ifdef __KAME__ 237 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 238 sin6->sin6_scope_id = 239 ntohs(*(u_int16_t *) 240 &sin6->sin6_addr.s6_addr[2]); 241 /* too little width */ 242 if (!vflag) 243 sin6->sin6_scope_id = 0; 244 sin6->sin6_addr.s6_addr[2] = 0; 245 sin6->sin6_addr.s6_addr[3] = 0; 246 } 247#endif 248 cp = netname6(&ifaddr.in6.ia_addr, 249 &ifaddr.in6.ia_prefixmask); 250 if (vflag) 251 n = strlen(cp) < 13 ? 13 : strlen(cp); 252 else 253 n = 13; 254 printf("%-*.*s ", n, n, cp); 255 if (getnameinfo((struct sockaddr *)sin6, 256 sin6->sin6_len, 257 hbuf, sizeof(hbuf), NULL, 0, 258 niflag) != 0) { 259 cp = "?"; 260 } else 261 cp = hbuf; 262 if (vflag) 263 n = strlen(cp) < 17 ? 17 : strlen(cp); 264 else 265 n = 17; 266 printf("%-*.*s ", n, n, cp); 267 if (aflag) { 268 u_long multiaddr; 269 struct in6_multi inm; 270 struct sockaddr_in6 sin6; 271 272 multiaddr = (u_long) 273 ifaddr.in6.ia6_multiaddrs.lh_first; 274 while (multiaddr != 0) { 275 kread(multiaddr, (char *)&inm, 276 sizeof inm); 277 memset(&sin6, 0, sizeof(sin6)); 278 sin6.sin6_len = sizeof(struct sockaddr_in6); 279 sin6.sin6_family = AF_INET6; 280 sin6.sin6_addr = inm.in6m_addr; 281#ifdef __KAME__ 282 if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) { 283 sin6.sin6_scope_id = 284 ntohs(*(u_int16_t *) 285 &sin6.sin6_addr.s6_addr[2]); 286 sin6.sin6_addr.s6_addr[2] = 0; 287 sin6.sin6_addr.s6_addr[3] = 0; 288 } 289#endif 290 if (getnameinfo((struct sockaddr *)&sin6, 291 sin6.sin6_len, hbuf, 292 sizeof(hbuf), NULL, 0, 293 niflag) != 0) { 294 strlcpy(hbuf, "??", 295 sizeof(hbuf)); 296 } 297 cp = hbuf; 298 if (vflag) 299 n = strlen(cp) < 17 300 ? 17 : strlen(cp); 301 else 302 n = 17; 303 printf("\n%25s %-*.*s ", "", 304 n, n, cp); 305 multiaddr = 306 (u_long)inm.in6m_entry.le_next; 307 } 308 } 309 break; 310#endif /*INET6*/ 311#ifndef SMALL 312 case AF_APPLETALK: 313 printf("atalk:%-7.7s ", 314 atalk_print(sa,0x10)); 315 printf("%-17.17s ", atalk_print(sa,0x0b)); 316 break; 317#endif 318 case AF_LINK: 319 printf("%-13.13s ", "<Link>"); 320 if (getnameinfo(sa, sa->sa_len, 321 hbuf, sizeof(hbuf), NULL, 0, 322 NI_NUMERICHOST) != 0) { 323 cp = "?"; 324 } else 325 cp = hbuf; 326 if (vflag) 327 n = strlen(cp) < 17 ? 17 : strlen(cp); 328 else 329 n = 17; 330 printf("%-*.*s ", n, n, cp); 331 break; 332 333 default: 334 m = printf("(%d)", sa->sa_family); 335 for (cp = sa->sa_len + (char *)sa; 336 --cp > sa->sa_data && (*cp == 0);) {} 337 n = cp - sa->sa_data + 1; 338 cp = sa->sa_data; 339 while (--n >= 0) 340 m += printf(hexfmt, *cp++ & 0xff, 341 n > 0 ? hexsep : ' '); 342 m = 32 - m; 343 while (m-- > 0) 344 putchar(' '); 345 break; 346 } 347 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 348 } 349 if (bflag) { 350 printf("%10llu %10llu", 351 (unsigned long long)ifnet.if_ibytes, 352 (unsigned long long)ifnet.if_obytes); 353 } else { 354 printf("%8llu %5llu %8llu %5llu %5llu", 355 (unsigned long long)ifnet.if_ipackets, 356 (unsigned long long)ifnet.if_ierrors, 357 (unsigned long long)ifnet.if_opackets, 358 (unsigned long long)ifnet.if_oerrors, 359 (unsigned long long)ifnet.if_collisions); 360 } 361 if (tflag) 362 printf(" %4d", ifnet.if_timer); 363 if (dflag) 364 printf(" %5d", ifnet.if_snd.ifq_drops); 365 putchar('\n'); 366 } 367} 368 369#define MAXIF 100 370struct iftot { 371 char ift_name[IFNAMSIZ]; /* interface name */ 372 u_quad_t ift_ip; /* input packets */ 373 u_quad_t ift_ib; /* input bytes */ 374 u_quad_t ift_ie; /* input errors */ 375 u_quad_t ift_op; /* output packets */ 376 u_quad_t ift_ob; /* output bytes */ 377 u_quad_t ift_oe; /* output errors */ 378 u_quad_t ift_co; /* collisions */ 379 int ift_dr; /* drops */ 380} iftot[MAXIF]; 381 382u_char signalled; /* set if alarm goes off "early" */ 383 384/* 385 * Print a running summary of interface statistics. 386 * Repeat display every interval seconds, showing statistics 387 * collected over that interval. Assumes that interval is non-zero. 388 * First line printed at top of screen is always cumulative. 389 */ 390static void 391sidewaysintpr(interval, off) 392 unsigned interval; 393 u_long off; 394{ 395 struct itimerval it; 396 struct ifnet ifnet; 397 u_long firstifnet; 398 struct iftot *ip, *total; 399 int line; 400 struct iftot *lastif, *sum, *interesting; 401 struct ifnet_head ifhead; /* TAILQ_HEAD */ 402 int oldmask; 403 404 /* 405 * Find the pointer to the first ifnet structure. Replace 406 * the pointer to the TAILQ_HEAD with the actual pointer 407 * to the first list element. 408 */ 409 if (kread(off, (char *)&ifhead, sizeof ifhead)) 410 return; 411 firstifnet = (u_long)ifhead.tqh_first; 412 413 lastif = iftot; 414 sum = iftot + MAXIF - 1; 415 total = sum - 1; 416 interesting = (interface == NULL) ? iftot : NULL; 417 for (off = firstifnet, ip = iftot; off;) { 418 if (kread(off, (char *)&ifnet, sizeof ifnet)) 419 break; 420 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 421 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 422 if (interface && strcmp(ifnet.if_xname, interface) == 0) 423 interesting = ip; 424 ip++; 425 if (ip >= iftot + MAXIF - 2) 426 break; 427 off = (u_long)ifnet.if_list.tqe_next; 428 } 429 if (interesting == NULL) { 430 fprintf(stderr, "%s: %s: unknown interface\n", 431 getprogname(), interface); 432 exit(1); 433 } 434 lastif = ip; 435 436 (void)signal(SIGALRM, catchalarm); 437 signalled = NO; 438 439 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 440 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 441 setitimer(ITIMER_REAL, &it, NULL); 442 443banner: 444 if (bflag) 445 printf("%7.7s in %8.8s %6.6s out %5.5s", 446 interesting->ift_name, " ", 447 interesting->ift_name, " "); 448 else 449 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 450 interesting->ift_name, " ", 451 interesting->ift_name, " ", " "); 452 if (dflag) 453 printf(" %5.5s", " "); 454 if (lastif - iftot > 0) { 455 if (bflag) 456 printf(" %7.7s in %8.8s %6.6s out %5.5s", 457 "total", " ", "total", " "); 458 else 459 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 460 "total", " ", "total", " ", " "); 461 if (dflag) 462 printf(" %5.5s", " "); 463 } 464 for (ip = iftot; ip < iftot + MAXIF; ip++) { 465 ip->ift_ip = 0; 466 ip->ift_ib = 0; 467 ip->ift_ie = 0; 468 ip->ift_op = 0; 469 ip->ift_ob = 0; 470 ip->ift_oe = 0; 471 ip->ift_co = 0; 472 ip->ift_dr = 0; 473 } 474 putchar('\n'); 475 if (bflag) 476 printf("%10.10s %8.8s %10.10s %5.5s", 477 "bytes", " ", "bytes", " "); 478 else 479 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 480 "packets", "errs", "packets", "errs", "colls"); 481 if (dflag) 482 printf(" %5.5s", "drops"); 483 if (lastif - iftot > 0) { 484 if (bflag) 485 printf(" %10.10s %8.8s %10.10s %5.5s", 486 "bytes", " ", "bytes", " "); 487 else 488 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 489 "packets", "errs", "packets", "errs", "colls"); 490 if (dflag) 491 printf(" %5.5s", "drops"); 492 } 493 putchar('\n'); 494 fflush(stdout); 495 line = 0; 496loop: 497 sum->ift_ip = 0; 498 sum->ift_ib = 0; 499 sum->ift_ie = 0; 500 sum->ift_op = 0; 501 sum->ift_ob = 0; 502 sum->ift_oe = 0; 503 sum->ift_co = 0; 504 sum->ift_dr = 0; 505 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 506 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 507 off = 0; 508 continue; 509 } 510 if (ip == interesting) { 511 if (bflag) { 512 printf("%10llu %8.8s %10llu %5.5s", 513 (unsigned long long)(ifnet.if_ibytes - 514 ip->ift_ib), " ", 515 (unsigned long long)(ifnet.if_obytes - 516 ip->ift_ob), " "); 517 } else { 518 printf("%8llu %5llu %8llu %5llu %5llu", 519 (unsigned long long) 520 (ifnet.if_ipackets - ip->ift_ip), 521 (unsigned long long) 522 (ifnet.if_ierrors - ip->ift_ie), 523 (unsigned long long) 524 (ifnet.if_opackets - ip->ift_op), 525 (unsigned long long) 526 (ifnet.if_oerrors - ip->ift_oe), 527 (unsigned long long) 528 (ifnet.if_collisions - ip->ift_co)); 529 } 530 if (dflag) 531 printf(" %5llu", 532 (unsigned long long) 533 (ifnet.if_snd.ifq_drops - ip->ift_dr)); 534 } 535 ip->ift_ip = ifnet.if_ipackets; 536 ip->ift_ib = ifnet.if_ibytes; 537 ip->ift_ie = ifnet.if_ierrors; 538 ip->ift_op = ifnet.if_opackets; 539 ip->ift_ob = ifnet.if_obytes; 540 ip->ift_oe = ifnet.if_oerrors; 541 ip->ift_co = ifnet.if_collisions; 542 ip->ift_dr = ifnet.if_snd.ifq_drops; 543 sum->ift_ip += ip->ift_ip; 544 sum->ift_ib += ip->ift_ib; 545 sum->ift_ie += ip->ift_ie; 546 sum->ift_op += ip->ift_op; 547 sum->ift_ob += ip->ift_ob; 548 sum->ift_oe += ip->ift_oe; 549 sum->ift_co += ip->ift_co; 550 sum->ift_dr += ip->ift_dr; 551 off = (u_long)ifnet.if_list.tqe_next; 552 } 553 if (lastif - iftot > 0) { 554 if (bflag) { 555 printf(" %10llu %8.8s %10llu %5.5s", 556 (unsigned long long) 557 (sum->ift_ib - total->ift_ib), " ", 558 (unsigned long long) 559 (sum->ift_ob - total->ift_ob), " "); 560 } else { 561 printf(" %8llu %5llu %8llu %5llu %5llu", 562 (unsigned long long) 563 (sum->ift_ip - total->ift_ip), 564 (unsigned long long) 565 (sum->ift_ie - total->ift_ie), 566 (unsigned long long) 567 (sum->ift_op - total->ift_op), 568 (unsigned long long) 569 (sum->ift_oe - total->ift_oe), 570 (unsigned long long) 571 (sum->ift_co - total->ift_co)); 572 } 573 if (dflag) 574 printf(" %5llu", 575 (unsigned long long)(sum->ift_dr - total->ift_dr)); 576 } 577 *total = *sum; 578 putchar('\n'); 579 fflush(stdout); 580 line++; 581 oldmask = sigblock(sigmask(SIGALRM)); 582 if (! signalled) { 583 sigpause(0); 584 } 585 sigsetmask(oldmask); 586 signalled = NO; 587 if (line == 21) 588 goto banner; 589 goto loop; 590 /*NOTREACHED*/ 591} 592 593/* 594 * Called if an interval expires before sidewaysintpr has completed a loop. 595 * Sets a flag to not wait for the alarm. 596 */ 597static void 598catchalarm(signo) 599 int signo; 600{ 601 602 signalled = YES; 603} 604