if.c revision 1.58
1/* $NetBSD: if.c,v 1.58 2004/11/16 05:59:32 itojun 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.58 2004/11/16 05:59:32 itojun 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 <netns/ns.h> 52#include <netns/ns_if.h> 53#include <netiso/iso.h> 54#include <netiso/iso_var.h> 55#include <arpa/inet.h> 56 57#include <signal.h> 58#include <stdio.h> 59#include <stdlib.h> 60#include <string.h> 61#include <unistd.h> 62#include <netdb.h> 63 64#include "netstat.h" 65 66#define YES 1 67#define NO 0 68 69static void sidewaysintpr __P((u_int, u_long)); 70static void catchalarm __P((int)); 71 72/* 73 * Print a description of the network interfaces. 74 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 75 * which is a TAILQ_HEAD. 76 */ 77void 78intpr(interval, ifnetaddr, pfunc) 79 int interval; 80 u_long ifnetaddr; 81 void (*pfunc)(char *); 82{ 83 struct ifnet ifnet; 84 union { 85 struct ifaddr ifa; 86 struct in_ifaddr in; 87#ifdef INET6 88 struct in6_ifaddr in6; 89#endif /* INET6 */ 90 struct ns_ifaddr ns; 91 struct iso_ifaddr iso; 92 } ifaddr; 93 u_long ifaddraddr; 94 struct sockaddr *sa; 95 struct ifnet_head ifhead; /* TAILQ_HEAD */ 96 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 97 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 98#ifdef INET6 99 const int niflag = NI_NUMERICHOST; 100#endif 101 102 if (ifnetaddr == 0) { 103 printf("ifnet: symbol not defined\n"); 104 return; 105 } 106 if (interval) { 107 sidewaysintpr((unsigned)interval, ifnetaddr); 108 return; 109 } 110 111 /* 112 * Find the pointer to the first ifnet structure. Replace 113 * the pointer to the TAILQ_HEAD with the actual pointer 114 * to the first list element. 115 */ 116 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 117 return; 118 ifnetaddr = (u_long)ifhead.tqh_first; 119 120 if (!sflag & !pflag) { 121 if (bflag) { 122 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 123 "%10.10s %10.10s", 124 "Name", "Mtu", "Network", "Address", 125 "Ibytes", "Obytes"); 126 } else { 127 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 128 "%8.8s %5.5s %8.8s %5.5s %5.5s", 129 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 130 "Opkts", "Oerrs", "Colls"); 131 } 132 if (tflag) 133 printf(" %4.4s", "Time"); 134 if (dflag) 135 printf(" %5.5s", "Drops"); 136 putchar('\n'); 137 } 138 ifaddraddr = 0; 139 while (ifnetaddr || ifaddraddr) { 140 struct sockaddr_in *sin; 141#ifdef INET6 142 struct sockaddr_in6 *sin6; 143#endif /* INET6 */ 144 char *cp; 145 int n, m; 146 147 if (ifaddraddr == 0) { 148 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 149 return; 150 memmove(name, ifnet.if_xname, IFNAMSIZ); 151 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 152 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 153 if (interface != 0 && strcmp(name, interface) != 0) 154 continue; 155 cp = strchr(name, '\0'); 156 157 if (pfunc) { 158 (*pfunc)(name); 159 continue; 160 } 161 162 if ((ifnet.if_flags & IFF_UP) == 0) 163 *cp++ = '*'; 164 *cp = '\0'; 165 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 166 } 167 if (vflag) 168 n = strlen(name) < 5 ? 5 : strlen(name); 169 else 170 n = 5; 171 printf("%-*.*s %-5llu ", n, n, name, 172 (unsigned long long)ifnet.if_mtu); 173 if (ifaddraddr == 0) { 174 printf("%-13.13s ", "none"); 175 printf("%-17.17s ", "none"); 176 } else { 177 char hexsep = '.'; /* for hexprint */ 178 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 179 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 180 ifaddraddr = 0; 181 continue; 182 } 183#define CP(x) ((char *)(x)) 184 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 185 CP(&ifaddr); 186 sa = (struct sockaddr *)cp; 187 switch (sa->sa_family) { 188 case AF_UNSPEC: 189 printf("%-13.13s ", "none"); 190 printf("%-17.17s ", "none"); 191 break; 192 case AF_INET: 193 sin = (struct sockaddr_in *)sa; 194#ifdef notdef 195 /* 196 * can't use inet_makeaddr because kernel 197 * keeps nets unshifted. 198 */ 199 in = inet_makeaddr(ifaddr.in.ia_subnet, 200 INADDR_ANY); 201 cp = netname(in.s_addr, 202 ifaddr.in.ia_subnetmask); 203#else 204 cp = netname(ifaddr.in.ia_subnet, 205 ifaddr.in.ia_subnetmask); 206#endif 207 if (vflag) 208 n = strlen(cp) < 13 ? 13 : strlen(cp); 209 else 210 n = 13; 211 printf("%-*.*s ", n, n, cp); 212 cp = routename(sin->sin_addr.s_addr); 213 if (vflag) 214 n = strlen(cp) < 17 ? 17 : strlen(cp); 215 else 216 n = 17; 217 printf("%-*.*s ", n, n, cp); 218 if (aflag) { 219 u_long multiaddr; 220 struct in_multi inm; 221 222 multiaddr = (u_long) 223 ifaddr.in.ia_multiaddrs.lh_first; 224 while (multiaddr != 0) { 225 kread(multiaddr, (char *)&inm, 226 sizeof inm); 227 printf("\n%25s %-17.17s ", "", 228 routename( 229 inm.inm_addr.s_addr)); 230 multiaddr = 231 (u_long)inm.inm_list.le_next; 232 } 233 } 234 break; 235#ifdef INET6 236 case AF_INET6: 237 sin6 = (struct sockaddr_in6 *)sa; 238#ifdef __KAME__ 239 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 240 sin6->sin6_scope_id = 241 ntohs(*(u_int16_t *) 242 &sin6->sin6_addr.s6_addr[2]); 243 /* too little width */ 244 if (!vflag) 245 sin6->sin6_scope_id = 0; 246 sin6->sin6_addr.s6_addr[2] = 0; 247 sin6->sin6_addr.s6_addr[3] = 0; 248 } 249#endif 250 cp = netname6(&ifaddr.in6.ia_addr, 251 &ifaddr.in6.ia_prefixmask.sin6_addr); 252 if (vflag) 253 n = strlen(cp) < 13 ? 13 : strlen(cp); 254 else 255 n = 13; 256 printf("%-*.*s ", n, n, cp); 257 if (getnameinfo((struct sockaddr *)sin6, 258 sin6->sin6_len, 259 hbuf, sizeof(hbuf), NULL, 0, 260 niflag) != 0) { 261 cp = "?"; 262 } else 263 cp = hbuf; 264 if (vflag) 265 n = strlen(cp) < 17 ? 17 : strlen(cp); 266 else 267 n = 17; 268 printf("%-*.*s ", n, n, cp); 269 if (aflag) { 270 u_long multiaddr; 271 struct in6_multi inm; 272 struct sockaddr_in6 sin6; 273 274 multiaddr = (u_long) 275 ifaddr.in6.ia6_multiaddrs.lh_first; 276 while (multiaddr != 0) { 277 kread(multiaddr, (char *)&inm, 278 sizeof inm); 279 memset(&sin6, 0, sizeof(sin6)); 280 sin6.sin6_len = sizeof(struct sockaddr_in6); 281 sin6.sin6_family = AF_INET6; 282 sin6.sin6_addr = inm.in6m_addr; 283#ifdef __KAME__ 284 if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) { 285 sin6.sin6_scope_id = 286 ntohs(*(u_int16_t *) 287 &sin6.sin6_addr.s6_addr[2]); 288 sin6.sin6_addr.s6_addr[2] = 0; 289 sin6.sin6_addr.s6_addr[3] = 0; 290 } 291#endif 292 if (getnameinfo((struct sockaddr *)&sin6, 293 sin6.sin6_len, hbuf, 294 sizeof(hbuf), NULL, 0, 295 niflag) != 0) { 296 strlcpy(hbuf, "??", 297 sizeof(hbuf)); 298 } 299 cp = hbuf; 300 if (vflag) 301 n = strlen(cp) < 17 302 ? 17 : strlen(cp); 303 else 304 n = 17; 305 printf("\n%25s %-*.*s ", "", 306 n, n, cp); 307 multiaddr = 308 (u_long)inm.in6m_entry.le_next; 309 } 310 } 311 break; 312#endif /*INET6*/ 313#ifndef SMALL 314 case AF_APPLETALK: 315 printf("atalk:%-7.7s ", 316 atalk_print(sa,0x10)); 317 printf("%-17.17s ", atalk_print(sa,0x0b)); 318 break; 319 case AF_NS: 320 { 321 struct sockaddr_ns *sns = 322 (struct sockaddr_ns *)sa; 323 u_long net; 324 char netnum[10]; 325 326 *(union ns_net *)&net = sns->sns_addr.x_net; 327 (void)snprintf(netnum, sizeof(netnum), "%xH", 328 (u_int32_t)ntohl(net)); 329 upHex(netnum); 330 printf("ns:%-10s ", netnum); 331 printf("%-17.17s ", 332 ns_phost((struct sockaddr *)sns)); 333 } 334 break; 335#endif 336 case AF_LINK: 337 printf("%-13.13s ", "<Link>"); 338 if (getnameinfo(sa, sa->sa_len, 339 hbuf, sizeof(hbuf), NULL, 0, 340 NI_NUMERICHOST) != 0) { 341 cp = "?"; 342 } else 343 cp = hbuf; 344 if (vflag) 345 n = strlen(cp) < 17 ? 17 : strlen(cp); 346 else 347 n = 17; 348 printf("%-*.*s ", n, n, cp); 349 break; 350 351 default: 352 m = printf("(%d)", sa->sa_family); 353 for (cp = sa->sa_len + (char *)sa; 354 --cp > sa->sa_data && (*cp == 0);) {} 355 n = cp - sa->sa_data + 1; 356 cp = sa->sa_data; 357 while (--n >= 0) 358 m += printf(hexfmt, *cp++ & 0xff, 359 n > 0 ? hexsep : ' '); 360 m = 32 - m; 361 while (m-- > 0) 362 putchar(' '); 363 break; 364 } 365 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 366 } 367 if (bflag) { 368 printf("%10llu %10llu", 369 (unsigned long long)ifnet.if_ibytes, 370 (unsigned long long)ifnet.if_obytes); 371 } else { 372 printf("%8llu %5llu %8llu %5llu %5llu", 373 (unsigned long long)ifnet.if_ipackets, 374 (unsigned long long)ifnet.if_ierrors, 375 (unsigned long long)ifnet.if_opackets, 376 (unsigned long long)ifnet.if_oerrors, 377 (unsigned long long)ifnet.if_collisions); 378 } 379 if (tflag) 380 printf(" %4d", ifnet.if_timer); 381 if (dflag) 382 printf(" %5d", ifnet.if_snd.ifq_drops); 383 putchar('\n'); 384 } 385} 386 387#define MAXIF 100 388struct iftot { 389 char ift_name[IFNAMSIZ]; /* interface name */ 390 u_quad_t ift_ip; /* input packets */ 391 u_quad_t ift_ib; /* input bytes */ 392 u_quad_t ift_ie; /* input errors */ 393 u_quad_t ift_op; /* output packets */ 394 u_quad_t ift_ob; /* output bytes */ 395 u_quad_t ift_oe; /* output errors */ 396 u_quad_t ift_co; /* collisions */ 397 int ift_dr; /* drops */ 398} iftot[MAXIF]; 399 400u_char signalled; /* set if alarm goes off "early" */ 401 402/* 403 * Print a running summary of interface statistics. 404 * Repeat display every interval seconds, showing statistics 405 * collected over that interval. Assumes that interval is non-zero. 406 * First line printed at top of screen is always cumulative. 407 */ 408static void 409sidewaysintpr(interval, off) 410 unsigned interval; 411 u_long off; 412{ 413 struct itimerval it; 414 struct ifnet ifnet; 415 u_long firstifnet; 416 struct iftot *ip, *total; 417 int line; 418 struct iftot *lastif, *sum, *interesting; 419 struct ifnet_head ifhead; /* TAILQ_HEAD */ 420 int oldmask; 421 422 /* 423 * Find the pointer to the first ifnet structure. Replace 424 * the pointer to the TAILQ_HEAD with the actual pointer 425 * to the first list element. 426 */ 427 if (kread(off, (char *)&ifhead, sizeof ifhead)) 428 return; 429 firstifnet = (u_long)ifhead.tqh_first; 430 431 lastif = iftot; 432 sum = iftot + MAXIF - 1; 433 total = sum - 1; 434 interesting = (interface == NULL) ? iftot : NULL; 435 for (off = firstifnet, ip = iftot; off;) { 436 if (kread(off, (char *)&ifnet, sizeof ifnet)) 437 break; 438 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 439 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 440 if (interface && strcmp(ifnet.if_xname, interface) == 0) 441 interesting = ip; 442 ip++; 443 if (ip >= iftot + MAXIF - 2) 444 break; 445 off = (u_long)ifnet.if_list.tqe_next; 446 } 447 if (interesting == NULL) { 448 fprintf(stderr, "%s: %s: unknown interface\n", 449 getprogname(), interface); 450 exit(1); 451 } 452 lastif = ip; 453 454 (void)signal(SIGALRM, catchalarm); 455 signalled = NO; 456 457 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 458 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 459 setitimer(ITIMER_REAL, &it, NULL); 460 461banner: 462 if (bflag) 463 printf("%7.7s in %8.8s %6.6s out %5.5s", 464 interesting->ift_name, " ", 465 interesting->ift_name, " "); 466 else 467 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 468 interesting->ift_name, " ", 469 interesting->ift_name, " ", " "); 470 if (dflag) 471 printf(" %5.5s", " "); 472 if (lastif - iftot > 0) { 473 if (bflag) 474 printf(" %7.7s in %8.8s %6.6s out %5.5s", 475 "total", " ", "total", " "); 476 else 477 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 478 "total", " ", "total", " ", " "); 479 if (dflag) 480 printf(" %5.5s", " "); 481 } 482 for (ip = iftot; ip < iftot + MAXIF; ip++) { 483 ip->ift_ip = 0; 484 ip->ift_ib = 0; 485 ip->ift_ie = 0; 486 ip->ift_op = 0; 487 ip->ift_ob = 0; 488 ip->ift_oe = 0; 489 ip->ift_co = 0; 490 ip->ift_dr = 0; 491 } 492 putchar('\n'); 493 if (bflag) 494 printf("%10.10s %8.8s %10.10s %5.5s", 495 "bytes", " ", "bytes", " "); 496 else 497 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 498 "packets", "errs", "packets", "errs", "colls"); 499 if (dflag) 500 printf(" %5.5s", "drops"); 501 if (lastif - iftot > 0) { 502 if (bflag) 503 printf(" %10.10s %8.8s %10.10s %5.5s", 504 "bytes", " ", "bytes", " "); 505 else 506 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 507 "packets", "errs", "packets", "errs", "colls"); 508 if (dflag) 509 printf(" %5.5s", "drops"); 510 } 511 putchar('\n'); 512 fflush(stdout); 513 line = 0; 514loop: 515 sum->ift_ip = 0; 516 sum->ift_ib = 0; 517 sum->ift_ie = 0; 518 sum->ift_op = 0; 519 sum->ift_ob = 0; 520 sum->ift_oe = 0; 521 sum->ift_co = 0; 522 sum->ift_dr = 0; 523 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 524 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 525 off = 0; 526 continue; 527 } 528 if (ip == interesting) { 529 if (bflag) { 530 printf("%10llu %8.8s %10llu %5.5s", 531 (unsigned long long)(ifnet.if_ibytes - 532 ip->ift_ib), " ", 533 (unsigned long long)(ifnet.if_obytes - 534 ip->ift_ob), " "); 535 } else { 536 printf("%8llu %5llu %8llu %5llu %5llu", 537 (unsigned long long) 538 (ifnet.if_ipackets - ip->ift_ip), 539 (unsigned long long) 540 (ifnet.if_ierrors - ip->ift_ie), 541 (unsigned long long) 542 (ifnet.if_opackets - ip->ift_op), 543 (unsigned long long) 544 (ifnet.if_oerrors - ip->ift_oe), 545 (unsigned long long) 546 (ifnet.if_collisions - ip->ift_co)); 547 } 548 if (dflag) 549 printf(" %5llu", 550 (unsigned long long) 551 (ifnet.if_snd.ifq_drops - ip->ift_dr)); 552 } 553 ip->ift_ip = ifnet.if_ipackets; 554 ip->ift_ib = ifnet.if_ibytes; 555 ip->ift_ie = ifnet.if_ierrors; 556 ip->ift_op = ifnet.if_opackets; 557 ip->ift_ob = ifnet.if_obytes; 558 ip->ift_oe = ifnet.if_oerrors; 559 ip->ift_co = ifnet.if_collisions; 560 ip->ift_dr = ifnet.if_snd.ifq_drops; 561 sum->ift_ip += ip->ift_ip; 562 sum->ift_ib += ip->ift_ib; 563 sum->ift_ie += ip->ift_ie; 564 sum->ift_op += ip->ift_op; 565 sum->ift_ob += ip->ift_ob; 566 sum->ift_oe += ip->ift_oe; 567 sum->ift_co += ip->ift_co; 568 sum->ift_dr += ip->ift_dr; 569 off = (u_long)ifnet.if_list.tqe_next; 570 } 571 if (lastif - iftot > 0) { 572 if (bflag) { 573 printf(" %10llu %8.8s %10llu %5.5s", 574 (unsigned long long) 575 (sum->ift_ib - total->ift_ib), " ", 576 (unsigned long long) 577 (sum->ift_ob - total->ift_ob), " "); 578 } else { 579 printf(" %8llu %5llu %8llu %5llu %5llu", 580 (unsigned long long) 581 (sum->ift_ip - total->ift_ip), 582 (unsigned long long) 583 (sum->ift_ie - total->ift_ie), 584 (unsigned long long) 585 (sum->ift_op - total->ift_op), 586 (unsigned long long) 587 (sum->ift_oe - total->ift_oe), 588 (unsigned long long) 589 (sum->ift_co - total->ift_co)); 590 } 591 if (dflag) 592 printf(" %5llu", 593 (unsigned long long)(sum->ift_dr - total->ift_dr)); 594 } 595 *total = *sum; 596 putchar('\n'); 597 fflush(stdout); 598 line++; 599 oldmask = sigblock(sigmask(SIGALRM)); 600 if (! signalled) { 601 sigpause(0); 602 } 603 sigsetmask(oldmask); 604 signalled = NO; 605 if (line == 21) 606 goto banner; 607 goto loop; 608 /*NOTREACHED*/ 609} 610 611/* 612 * Called if an interval expires before sidewaysintpr has completed a loop. 613 * Sets a flag to not wait for the alarm. 614 */ 615static void 616catchalarm(signo) 617 int signo; 618{ 619 620 signalled = YES; 621} 622