if.c revision 1.109
1/* $NetBSD: if.c,v 1.109 2022/12/28 18:34:33 mrg 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.109 2022/12/28 18:34:33 mrg Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/param.h> 42#include <sys/types.h> 43#include <sys/protosw.h> 44#include <sys/socket.h> 45#include <sys/time.h> 46#include <sys/sysctl.h> 47#include <sys/ioctl.h> 48 49#include <net/if.h> 50#include <net/if_dl.h> 51#include <net/if_types.h> 52#include <net/route.h> 53#include <netinet/in.h> 54#include <netinet/in_var.h> 55#include <arpa/inet.h> 56 57#include <kvm.h> 58#include <signal.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <unistd.h> 63#include <netdb.h> 64#include <err.h> 65 66#include "netstat.h" 67#include "rtutil.h" 68#include "prog_ops.h" 69 70#define MAXIF 100 71 72#define HUMBUF_SIZE 7 73 74struct iftot { 75 char ift_name[IFNAMSIZ]; /* interface name */ 76 uint64_t ift_ip; /* input packets */ 77 uint64_t ift_ib; /* input bytes */ 78 uint64_t ift_ie; /* input errors */ 79 uint64_t ift_iq; /* input drops */ 80 uint64_t ift_op; /* output packets */ 81 uint64_t ift_ob; /* output bytes */ 82 uint64_t ift_oe; /* output errors */ 83 uint64_t ift_oq; /* output drops */ 84 uint64_t ift_co; /* collisions */ 85}; 86 87struct if_data_ext { 88 uint64_t ifi_oqdrops; 89}; 90 91static void set_lines(void); 92static void print_addr(const int, struct sockaddr *, struct sockaddr **, 93 struct if_data *, struct ifnet *, struct if_data_ext *); 94static void sidewaysintpr(u_int, u_long); 95 96static void iftot_banner(struct iftot *); 97static void iftot_print_sum(struct iftot *, struct iftot *); 98static void iftot_print(struct iftot *, struct iftot *); 99 100static void catchalarm(int); 101static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 102static void fetchifs(void); 103 104static int if_data_ext_get(const char *, struct if_data_ext *); 105static void intpr_sysctl(void); 106static void intpr_kvm(u_long, void (*)(const char *)); 107 108struct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old; 109static sig_atomic_t signalled; /* set when alarm goes off */ 110 111static unsigned redraw_lines = 21; 112 113static void 114set_lines(void) 115{ 116 static bool first = true; 117 struct ttysize ts; 118 119 if (!first) 120 return; 121 first = false; 122 if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1 && ts.ts_lines) 123 redraw_lines = ts.ts_lines - 3; 124} 125 126 127/* 128 * Print a description of the network interfaces. 129 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 130 * which is a TAILQ_HEAD. 131 */ 132void 133intpr(int interval, u_long ifnetaddr, void (*pfunc)(const char *)) 134{ 135 136 if (interval) { 137 sidewaysintpr((unsigned)interval, ifnetaddr); 138 return; 139 } 140 141 if (use_sysctl) 142 intpr_sysctl(); 143 else 144 intpr_kvm(ifnetaddr, pfunc); 145} 146 147static void 148intpr_header(void) 149{ 150 151 if (!sflag && !pflag) { 152 if (bflag) { 153 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 154 "%10.10s %10.10s", 155 "Name", "Mtu", "Network", "Address", 156 "Ibytes", "Obytes"); 157 } else { 158 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 159 "%8.8s %5.5s", 160 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 161 if (dflag) 162 printf(" %6.6s", "Idrops"); 163 printf(" %8.8s %5.5s %5.5s", 164 "Opkts", "Oerrs", "Colls"); 165 } 166 if (dflag) 167 printf(" %6.6s", "Odrops"); 168 if (tflag) 169 printf(" %4.4s", "Time"); 170 putchar('\n'); 171 } 172} 173 174int 175if_data_ext_get(const char *ifname, struct if_data_ext *dext) 176{ 177 char namebuf[1024]; 178 size_t len; 179 uint64_t drops; 180 181 /* For sysctl */ 182 snprintf(namebuf, sizeof(namebuf), 183 "net.interfaces.%s.sndq.drops", ifname); 184 len = sizeof(drops); 185 if (sysctlbyname(namebuf, &drops, &len, NULL, 0) == -1) { 186 warn("%s", namebuf); 187 dext->ifi_oqdrops = 0; 188 return -1; 189 } else 190 dext->ifi_oqdrops = drops; 191 192 return 0; 193} 194 195static void 196intpr_sysctl(void) 197{ 198 struct if_msghdr *ifm; 199 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 200 static char *buf = NULL; 201 static size_t olen; 202 char *next, *lim, *cp; 203 struct rt_msghdr *rtm; 204 struct ifa_msghdr *ifam; 205 struct if_data *ifd = NULL; 206 struct sockaddr *sa, *rti_info[RTAX_MAX]; 207 struct sockaddr_dl *sdl; 208 uint64_t total = 0; 209 size_t len; 210 int did = 1, rtax = 0, n; 211 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 212 char origname[IFNAMSIZ]; /* without `*' */ 213 int ifindex = 0; 214 215 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 216 err(1, "sysctl"); 217 if (len > olen) { 218 free(buf); 219 if ((buf = malloc(len)) == NULL) 220 err(1, NULL); 221 olen = len; 222 } 223 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 224 err(1, "sysctl"); 225 226 intpr_header(); 227 228 lim = buf + len; 229 for (next = buf; next < lim; next += rtm->rtm_msglen) { 230 struct if_data_ext dext; 231 232 rtm = (struct rt_msghdr *)next; 233 if (rtm->rtm_version != RTM_VERSION) 234 continue; 235 switch (rtm->rtm_type) { 236 case RTM_IFINFO: 237 total = 0; 238 ifm = (struct if_msghdr *)next; 239 ifd = &ifm->ifm_data; 240 241 sa = (struct sockaddr *)(ifm + 1); 242 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 243 244 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 245 if (sdl == NULL || sdl->sdl_family != AF_LINK) 246 continue; 247 248 bzero(name, sizeof(name)); 249 if (sdl->sdl_nlen >= IFNAMSIZ) 250 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 251 else if (sdl->sdl_nlen > 0) 252 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 253 254 if (interface != NULL && strcmp(name, interface) != 0) 255 continue; 256 257 ifindex = sdl->sdl_index; 258 259 /* Keep the original name */ 260 strcpy(origname, name); 261 262 /* Mark inactive interfaces with a '*' */ 263 cp = strchr(name, '\0'); 264 if ((ifm->ifm_flags & IFF_UP) == 0) { 265 *cp++ = '*'; 266 *cp = '\0'; 267 } 268 269 if (qflag) { 270 total = ifd->ifi_ibytes + ifd->ifi_obytes + 271 ifd->ifi_ipackets + ifd->ifi_ierrors + 272 ifd->ifi_opackets + ifd->ifi_oerrors + 273 ifd->ifi_collisions; 274 if (dflag) 275 total += ifd->ifi_iqdrops; 276 if (total == 0) 277 continue; 278 } 279 /* Skip the first one */ 280 if (did) { 281 did = 0; 282 continue; 283 } 284 rtax = RTAX_IFP; 285 break; 286 case RTM_NEWADDR: 287 if (qflag && total == 0) 288 continue; 289 if (interface != NULL && strcmp(name, interface) != 0) 290 continue; 291 ifam = (struct ifa_msghdr *)next; 292 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 293 RTA_BRD)) == 0) 294 break; 295 296 sa = (struct sockaddr *)(ifam + 1); 297 298 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 299 rtax = RTAX_IFA; 300 did = 1; 301 break; 302 default: 303 continue; 304 } 305 if (vflag) 306 n = strlen(name) < 5 ? 5 : strlen(name); 307 else 308 n = 5; 309 310 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 311 if (dflag) 312 if_data_ext_get(origname, &dext); 313 314 print_addr(ifindex, rti_info[rtax], rti_info, ifd, 315 NULL, dflag ? &dext : NULL); 316 } 317} 318 319union ifaddr_u { 320 struct ifaddr ifa; 321 struct in_ifaddr in; 322#ifdef INET6 323 struct in6_ifaddr in6; 324#endif /* INET6 */ 325}; 326 327static void 328ifname_to_ifdata(int s, const char *ifname, struct if_data * const ifd) 329{ 330 struct ifdatareq ifdr; 331 332 memset(ifd, 0, sizeof(*ifd)); 333 strlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name)); 334 if (ioctl(s, SIOCGIFDATA, &ifdr) != 0) 335 return; 336 memcpy(ifd, &ifdr.ifdr_data, sizeof(ifdr.ifdr_data)); 337} 338 339static void 340intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 341{ 342 struct ifnet ifnet; 343 struct if_data ifd; 344 union ifaddr_u ifaddr; 345 u_long ifaddraddr; 346 struct ifnet_head ifhead; /* TAILQ_HEAD */ 347 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 348 int s; 349 350 if (ifnetaddr == 0) { 351 printf("ifnet: symbol not defined\n"); 352 return; 353 } 354 355 /* 356 * Find the pointer to the first ifnet structure. Replace 357 * the pointer to the TAILQ_HEAD with the actual pointer 358 * to the first list element. 359 */ 360 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 361 return; 362 ifnetaddr = (u_long)ifhead.tqh_first; 363 364 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 365 return; 366 367 intpr_header(); 368 369 ifaddraddr = 0; 370 while (ifnetaddr || ifaddraddr) { 371 char *cp; 372 int n; 373 374 if (ifaddraddr == 0) { 375 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 376 return; 377 memmove(name, ifnet.if_xname, IFNAMSIZ); 378 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 379 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 380 if (interface != NULL && strcmp(name, interface) != 0) 381 continue; 382 cp = strchr(name, '\0'); 383 384 if (pfunc) { 385 (*pfunc)(name); 386 continue; 387 } 388 389 if ((ifnet.if_flags & IFF_UP) == 0) 390 *cp++ = '*'; 391 *cp = '\0'; 392 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 393 } 394 if (vflag) 395 n = strlen(name) < 5 ? 5 : strlen(name); 396 else 397 n = 5; 398 printf("%-*.*s %-5llu ", n, n, name, 399 (unsigned long long)ifnet.if_mtu); 400 if (ifaddraddr == 0) { 401 printf("%-13.13s ", "none"); 402 printf("%-17.17s ", "none"); 403 } else { 404 struct sockaddr *sa; 405 406 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) 407 { 408 ifaddraddr = 0; 409 continue; 410 } 411#define CP(x) ((char *)(x)) 412 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 413 CP(&ifaddr); 414 sa = (struct sockaddr *)cp; 415 ifname_to_ifdata(s, name, &ifd); 416 print_addr(ifnet.if_index, sa, (void *)&ifaddr, 417 &ifd, &ifnet, NULL); 418 } 419 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 420 } 421 close(s); 422} 423 424static void 425mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids, 426 void (*pr)(const void *)) 427{ 428 uint8_t *mcast_addrs, *p; 429 const size_t incr = 2 * ias + sizeof(uint32_t); 430 size_t len; 431 432 if (mcast_oids[0] == 0) { 433 size_t oidlen = 4; 434 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 435 warnx("'%s' not found", oid); 436 return; 437 } 438 if (oidlen != 3) { 439 warnx("Wrong OID path for '%s'", oid); 440 return; 441 } 442 } 443 444 if (mcast_oids[3] == ifindex) 445 return; 446 mcast_oids[3] = ifindex; 447 448 mcast_addrs = asysctl(mcast_oids, 4, &len); 449 if (mcast_addrs == NULL && len != 0) { 450 warn("failed to read '%s'", oid); 451 return; 452 } 453 if (len) { 454 p = mcast_addrs; 455 while (len >= incr) { 456 (*pr)((p + ias)); 457 p += incr; 458 len -= incr; 459 } 460 } 461 free(mcast_addrs); 462} 463 464#ifdef INET6 465static void 466ia6_print(const struct in6_addr *ia) 467{ 468 struct sockaddr_in6 as6; 469 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 470 int n; 471 472 memset(&as6, 0, sizeof(as6)); 473 as6.sin6_len = sizeof(struct sockaddr_in6); 474 as6.sin6_family = AF_INET6; 475 as6.sin6_addr = *ia; 476 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 477 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 478 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 479 strlcpy(hbuf, "??", sizeof(hbuf)); 480 } 481 if (vflag) 482 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 483 else 484 n = 17; 485 printf("\n%25s %-*.*s ", "", n, n, hbuf); 486} 487 488static void 489mc6_print(const int ifindex) 490{ 491 static int mcast_oids[4]; 492 493 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast", 494 mcast_oids, (void (*)(const void *))ia6_print); 495} 496#endif 497 498static void 499ia4_print(const struct in_addr *ia) 500{ 501 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 502} 503 504static void 505mc4_print(const int ifindex) 506{ 507 static int mcast_oids[4]; 508 509 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast", 510 mcast_oids, (void (*)(const void *))ia4_print); 511} 512 513static void 514print_addr(const int ifindex, struct sockaddr *sa, struct sockaddr **rtinfo, 515 struct if_data *ifd, struct ifnet *ifnet, struct if_data_ext *dext) 516{ 517 char hexsep = '.'; /* for hexprint */ 518 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 519 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 520#ifdef INET6 521 const int niflag = NI_NUMERICHOST; 522 struct sockaddr_in6 *sin6, *netmask6; 523#endif 524 struct sockaddr_in netmask; 525 struct sockaddr_in *sin; 526 char *cp; 527 int n, m; 528 529 switch (sa->sa_family) { 530 case AF_UNSPEC: 531 printf("%-13.13s ", "none"); 532 printf("%-17.17s ", "none"); 533 break; 534 case AF_INET: 535 sin = (struct sockaddr_in *)sa; 536 if (use_sysctl) { 537 netmask = 538 *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 539 } else { 540 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 541 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 542 } 543 cp = netname4(sin, &netmask, nflag); 544 if (vflag) 545 n = strlen(cp) < 13 ? 13 : strlen(cp); 546 else 547 n = 13; 548 printf("%-*.*s ", n, n, cp); 549 cp = routename4(sin->sin_addr.s_addr, nflag); 550 if (vflag) 551 n = strlen(cp) < 17 ? 17 : strlen(cp); 552 else 553 n = 17; 554 printf("%-*.*s ", n, n, cp); 555 556 if (!aflag) 557 break; 558 if (ifnet) { 559 u_long multiaddr; 560 struct in_multi inm; 561 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 562 563 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 564 while (multiaddr != 0) { 565 kread(multiaddr, (char *)&inm, sizeof inm); 566 ia4_print(&inm.inm_addr); 567 multiaddr = (u_long)inm.inm_list.le_next; 568 } 569 } else 570 mc4_print(ifindex); 571 break; 572#ifdef INET6 573 case AF_INET6: 574 sin6 = (struct sockaddr_in6 *)sa; 575 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 576#ifdef __KAME__ 577 if (!vflag) 578 sin6->sin6_scope_id = 0; 579#endif 580 581 if (use_sysctl) 582 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 583 else { 584 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 585 netmask6 = &ifaddr_in6->ia_prefixmask; 586 } 587 588 cp = netname6(sin6, netmask6, nflag); 589 if (vflag) 590 n = strlen(cp) < 13 ? 13 : strlen(cp); 591 else 592 n = 13; 593 printf("%-*.*s ", n, n, cp); 594 if (getnameinfo((struct sockaddr *)sin6, 595 sin6->sin6_len, 596 hbuf, sizeof(hbuf), NULL, 0, 597 niflag) != 0) { 598 strlcpy(hbuf, "?", sizeof(hbuf)); 599 } 600 cp = hbuf; 601 if (vflag) 602 n = strlen(cp) < 17 ? 17 : strlen(cp); 603 else 604 n = 17; 605 printf("%-*.*s ", n, n, cp); 606 607 if (!aflag) 608 break; 609 if (ifnet) { 610 u_long multiaddr; 611 struct in6_multi inm; 612 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 613 614 multiaddr = (u_long)ifaddr->in6._ia6_multiaddrs.lh_first; 615 while (multiaddr != 0) { 616 kread(multiaddr, (char *)&inm, sizeof inm); 617 ia6_print(&inm.in6m_addr); 618 multiaddr = (u_long)inm.in6m_entry.le_next; 619 } 620 } else 621 mc6_print(ifindex); 622 break; 623#endif /*INET6*/ 624#ifndef SMALL 625 case AF_APPLETALK: 626 printf("atalk:%-7.7s ", atalk_print(sa, 0x10)); 627 printf("%-17.17s ", atalk_print(sa, 0x0b)); 628 break; 629#endif 630 case AF_LINK: 631 printf("%-13.13s ", "<Link>"); 632 if (getnameinfo(sa, sa->sa_len, 633 hbuf, sizeof(hbuf), NULL, 0, 634 NI_NUMERICHOST) != 0) { 635 strlcpy(hbuf, "?", sizeof(hbuf)); 636 } 637 cp = hbuf; 638 if (vflag) 639 n = strlen(cp) < 17 ? 17 : strlen(cp); 640 else 641 n = 17; 642 printf("%-*.*s ", n, n, cp); 643 break; 644 645 default: 646 m = printf("(%d)", sa->sa_family); 647 for (cp = sa->sa_len + (char *)sa; 648 --cp > sa->sa_data && (*cp == 0);) {} 649 n = cp - sa->sa_data + 1; 650 cp = sa->sa_data; 651 652 while (--n >= 0) 653 m += printf(hexfmt, *cp++ & 0xff, 654 n > 0 ? hexsep : ' '); 655 m = 32 - m; 656 while (m-- > 0) 657 putchar(' '); 658 break; 659 } 660 661 if (bflag) { 662 char humbuf[HUMBUF_SIZE]; 663 664 if (hflag && humanize_number(humbuf, sizeof(humbuf), 665 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 666 printf("%10s ", humbuf); 667 else 668 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 669 670 if (hflag && humanize_number(humbuf, sizeof(humbuf), 671 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 672 printf("%10s", humbuf); 673 else 674 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 675 } else { 676 printf("%8llu %5llu", 677 (unsigned long long)ifd->ifi_ipackets, 678 (unsigned long long)ifd->ifi_ierrors); 679 if (dflag) 680 printf(" %6" PRIu64, ifd->ifi_iqdrops); 681 printf(" %8llu %5llu %5llu", 682 (unsigned long long)ifd->ifi_opackets, 683 (unsigned long long)ifd->ifi_oerrors, 684 (unsigned long long)ifd->ifi_collisions); 685 } 686 if (dflag) 687 printf(" %6" PRIu64, ifnet ? 688 ifnet->if_snd.ifq_drops : dext->ifi_oqdrops); 689 if (tflag) 690 printf(" %4d", ifnet ? ifnet->if_timer : 0); 691 putchar('\n'); 692} 693 694static void 695iftot_banner(struct iftot *ift) 696{ 697 if (bflag) 698 printf("%7.7s in %8.8s %6.6s out %5.5s", 699 ift->ift_name, " ", 700 ift->ift_name, " "); 701 else 702 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 703 ift->ift_name, " ", 704 ift->ift_name, " ", " "); 705 if (dflag) 706 printf(" %5.5s", " "); 707 708 if (bflag) 709 printf(" %7.7s in %8.8s %6.6s out %5.5s", 710 "total", " ", "total", " "); 711 else 712 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 713 "total", " ", "total", " ", " "); 714 if (dflag) 715 printf(" %5.5s", " "); 716 putchar('\n'); 717 if (bflag) 718 printf("%10.10s %8.8s %10.10s %5.5s", 719 "bytes", " ", "bytes", " "); 720 else 721 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 722 "packets", "errs", "packets", "errs", "colls"); 723 if (dflag) 724 printf(" %5.5s", "drops"); 725 726 if (bflag) 727 printf(" %10.10s %8.8s %10.10s %5.5s", 728 "bytes", " ", "bytes", " "); 729 else 730 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 731 "packets", "errs", "packets", "errs", "colls"); 732 if (dflag) 733 printf(" %5.5s", "drops"); 734 putchar('\n'); 735 fflush(stdout); 736} 737 738static void 739iftot_print(struct iftot *cur, struct iftot *old) 740{ 741 if (bflag) 742 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 743 cur->ift_ib - old->ift_ib, " ", 744 cur->ift_ob - old->ift_ob, " "); 745 else 746 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 747 cur->ift_ip - old->ift_ip, 748 cur->ift_ie - old->ift_ie, 749 cur->ift_op - old->ift_op, 750 cur->ift_oe - old->ift_oe, 751 cur->ift_co - old->ift_co); 752 if (dflag) 753 printf(" %5" PRIu64, cur->ift_oq - old->ift_oq); 754} 755 756static void 757iftot_print_sum(struct iftot *cur, struct iftot *old) 758{ 759 if (bflag) 760 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 761 cur->ift_ib - old->ift_ib, " ", 762 cur->ift_ob - old->ift_ob, " "); 763 else 764 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 765 cur->ift_ip - old->ift_ip, 766 cur->ift_ie - old->ift_ie, 767 cur->ift_op - old->ift_op, 768 cur->ift_oe - old->ift_oe, 769 cur->ift_co - old->ift_co); 770 771 if (dflag) 772 printf(" %5" PRIu64, cur->ift_oq - old->ift_oq); 773} 774 775__dead static void 776sidewaysintpr_sysctl(unsigned interval) 777{ 778 struct itimerval it; 779 sigset_t emptyset; 780 sigset_t noalrm; 781 unsigned line; 782 783 set_lines(); 784 785 fetchifs(); 786 if (ip_cur.ift_name[0] == '\0') { 787 fprintf(stderr, "%s: %s: unknown interface\n", 788 getprogname(), interface); 789 exit(1); 790 } 791 792 sigemptyset(&emptyset); 793 sigemptyset(&noalrm); 794 sigaddset(&noalrm, SIGALRM); 795 sigprocmask(SIG_SETMASK, &noalrm, NULL); 796 797 signalled = 0; 798 (void)signal(SIGALRM, catchalarm); 799 800 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 801 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 802 setitimer(ITIMER_REAL, &it, NULL); 803 804banner: 805 iftot_banner(&ip_cur); 806 807 line = 0; 808 bzero(&ip_old, sizeof(ip_old)); 809 bzero(&sum_old, sizeof(sum_old)); 810loop: 811 bzero(&sum_cur, sizeof(sum_cur)); 812 813 fetchifs(); 814 815 iftot_print(&ip_cur, &ip_old); 816 817 ip_old = ip_cur; 818 819 iftot_print_sum(&sum_cur, &sum_old); 820 821 sum_old = sum_cur; 822 823 putchar('\n'); 824 fflush(stdout); 825 line++; 826 if (signalled == 0) 827 sigsuspend(&emptyset); 828 829 signalled = 0; 830 if (line == redraw_lines) 831 goto banner; 832 goto loop; 833 /*NOTREACHED*/ 834} 835 836static void 837sidewaysintpr_kvm(unsigned interval, u_long off) 838{ 839 struct itimerval it; 840 sigset_t emptyset; 841 sigset_t noalrm; 842 struct ifnet ifnet; 843 struct if_data ifd; 844 u_long firstifnet; 845 struct iftot *ip, *total; 846 unsigned line; 847 struct iftot *lastif, *sum, *interesting; 848 struct ifnet_head ifhead; /* TAILQ_HEAD */ 849 int s; 850 851 set_lines(); 852 853 /* 854 * Find the pointer to the first ifnet structure. Replace 855 * the pointer to the TAILQ_HEAD with the actual pointer 856 * to the first list element. 857 */ 858 if (kread(off, (char *)&ifhead, sizeof ifhead)) 859 return; 860 firstifnet = (u_long)ifhead.tqh_first; 861 862 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 863 return; 864 865 lastif = iftot; 866 sum = iftot + MAXIF - 1; 867 total = sum - 1; 868 interesting = (interface == NULL) ? iftot : NULL; 869 for (off = firstifnet, ip = iftot; off;) { 870 if (kread(off, (char *)&ifnet, sizeof ifnet)) 871 break; 872 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 873 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 874 if (interface && strcmp(ifnet.if_xname, interface) == 0) 875 interesting = ip; 876 ip++; 877 if (ip >= iftot + MAXIF - 2) 878 break; 879 off = (u_long)ifnet.if_list.tqe_next; 880 } 881 if (interesting == NULL) { 882 fprintf(stderr, "%s: %s: unknown interface\n", 883 getprogname(), interface); 884 exit(1); 885 } 886 lastif = ip; 887 888 sigemptyset(&emptyset); 889 sigemptyset(&noalrm); 890 sigaddset(&noalrm, SIGALRM); 891 sigprocmask(SIG_SETMASK, &noalrm, NULL); 892 893 signalled = 0; 894 (void)signal(SIGALRM, catchalarm); 895 896 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 897 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 898 setitimer(ITIMER_REAL, &it, NULL); 899 900banner: 901 if (bflag) 902 printf("%7.7s in %8.8s %6.6s out %5.5s", 903 interesting->ift_name, " ", 904 interesting->ift_name, " "); 905 else 906 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 907 interesting->ift_name, " ", 908 interesting->ift_name, " ", " "); 909 if (dflag) 910 printf(" %5.5s", " "); 911 if (lastif - iftot > 0) { 912 if (bflag) 913 printf(" %7.7s in %8.8s %6.6s out %5.5s", 914 "total", " ", "total", " "); 915 else 916 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 917 "total", " ", "total", " ", " "); 918 if (dflag) 919 printf(" %5.5s", " "); 920 } 921 for (ip = iftot; ip < iftot + MAXIF; ip++) { 922 ip->ift_ip = 0; 923 ip->ift_ib = 0; 924 ip->ift_ie = 0; 925 ip->ift_iq = 0; 926 ip->ift_op = 0; 927 ip->ift_ob = 0; 928 ip->ift_oe = 0; 929 ip->ift_oq = 0; 930 ip->ift_co = 0; 931 } 932 putchar('\n'); 933 if (bflag) 934 printf("%10.10s %8.8s %10.10s %5.5s", 935 "bytes", " ", "bytes", " "); 936 else 937 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 938 "packets", "errs", "packets", "errs", "colls"); 939 if (dflag) 940 printf(" %5.5s", "drops"); 941 if (lastif - iftot > 0) { 942 if (bflag) 943 printf(" %10.10s %8.8s %10.10s %5.5s", 944 "bytes", " ", "bytes", " "); 945 else 946 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 947 "packets", "errs", "packets", "errs", "colls"); 948 if (dflag) 949 printf(" %5.5s", "drops"); 950 } 951 putchar('\n'); 952 fflush(stdout); 953 line = 0; 954loop: 955 sum->ift_ip = 0; 956 sum->ift_ib = 0; 957 sum->ift_ie = 0; 958 sum->ift_iq = 0; 959 sum->ift_op = 0; 960 sum->ift_ob = 0; 961 sum->ift_oe = 0; 962 sum->ift_oq = 0; 963 sum->ift_co = 0; 964 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 965 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 966 off = 0; 967 continue; 968 } 969 ifname_to_ifdata(s, ip->ift_name, &ifd); 970 if (ip == interesting) { 971 if (bflag) { 972 char humbuf[HUMBUF_SIZE]; 973 974 if (hflag && humanize_number(humbuf, 975 sizeof(humbuf), 976 ifd.ifi_ibytes - ip->ift_ib, "", 977 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 978 printf("%10s %8.8s ", humbuf, " "); 979 else 980 printf("%10llu %8.8s ", 981 (unsigned long long) 982 (ifd.ifi_ibytes-ip->ift_ib), " "); 983 984 if (hflag && humanize_number(humbuf, 985 sizeof(humbuf), 986 ifd.ifi_obytes - ip->ift_ob, "", 987 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 988 printf("%10s %5.5s", humbuf, " "); 989 else 990 printf("%10llu %5.5s", 991 (unsigned long long) 992 (ifd.ifi_obytes-ip->ift_ob), " "); 993 } else { 994 printf("%8llu %5llu %8llu %5llu %5llu", 995 (unsigned long long) 996 (ifd.ifi_ipackets - ip->ift_ip), 997 (unsigned long long) 998 (ifd.ifi_ierrors - ip->ift_ie), 999 (unsigned long long) 1000 (ifd.ifi_opackets - ip->ift_op), 1001 (unsigned long long) 1002 (ifd.ifi_oerrors - ip->ift_oe), 1003 (unsigned long long) 1004 (ifd.ifi_collisions - ip->ift_co)); 1005 } 1006 if (dflag) 1007 printf(" %5" PRIu64, 1008 ifnet.if_snd.ifq_drops - ip->ift_oq); 1009 } 1010 ip->ift_ip = ifd.ifi_ipackets; 1011 ip->ift_ib = ifd.ifi_ibytes; 1012 ip->ift_ie = ifd.ifi_ierrors; 1013 ip->ift_op = ifd.ifi_opackets; 1014 ip->ift_ob = ifd.ifi_obytes; 1015 ip->ift_oe = ifd.ifi_oerrors; 1016 ip->ift_co = ifd.ifi_collisions; 1017 ip->ift_oq = ifnet.if_snd.ifq_drops; 1018 sum->ift_ip += ip->ift_ip; 1019 sum->ift_ib += ip->ift_ib; 1020 sum->ift_ie += ip->ift_ie; 1021 sum->ift_op += ip->ift_op; 1022 sum->ift_ob += ip->ift_ob; 1023 sum->ift_oe += ip->ift_oe; 1024 sum->ift_co += ip->ift_co; 1025 sum->ift_oq += ip->ift_oq; 1026 off = (u_long)ifnet.if_list.tqe_next; 1027 } 1028 if (lastif - iftot > 0) { 1029 if (bflag) { 1030 char humbuf[HUMBUF_SIZE]; 1031 1032 if (hflag && humanize_number(humbuf, 1033 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 1034 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1035 printf(" %10s %8.8s ", humbuf, " "); 1036 else 1037 printf(" %10llu %8.8s ", 1038 (unsigned long long) 1039 (sum->ift_ib - total->ift_ib), " "); 1040 1041 if (hflag && humanize_number(humbuf, 1042 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 1043 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1044 printf("%10s %5.5s", humbuf, " "); 1045 else 1046 printf("%10llu %5.5s", 1047 (unsigned long long) 1048 (sum->ift_ob - total->ift_ob), " "); 1049 } else { 1050 printf(" %8llu %5llu %8llu %5llu %5llu", 1051 (unsigned long long) 1052 (sum->ift_ip - total->ift_ip), 1053 (unsigned long long) 1054 (sum->ift_ie - total->ift_ie), 1055 (unsigned long long) 1056 (sum->ift_op - total->ift_op), 1057 (unsigned long long) 1058 (sum->ift_oe - total->ift_oe), 1059 (unsigned long long) 1060 (sum->ift_co - total->ift_co)); 1061 } 1062 if (dflag) 1063 printf(" %5llu", 1064 (unsigned long long)(sum->ift_oq - total->ift_oq)); 1065 } 1066 *total = *sum; 1067 putchar('\n'); 1068 fflush(stdout); 1069 line++; 1070 if (signalled == 0) 1071 sigsuspend(&emptyset); 1072 1073 signalled = 0; 1074 if (line == redraw_lines) 1075 goto banner; 1076 goto loop; 1077 /*NOTREACHED*/ 1078} 1079 1080/* 1081 * Print a running summary of interface statistics. 1082 * Repeat display every interval seconds, showing statistics 1083 * collected over that interval. Assumes that interval is non-zero. 1084 * First line printed at top of screen is always cumulative. 1085 */ 1086static void 1087sidewaysintpr(unsigned int interval, u_long off) 1088{ 1089 1090 if (use_sysctl) 1091 sidewaysintpr_sysctl(interval); 1092 else 1093 sidewaysintpr_kvm(interval, off); 1094} 1095 1096/* 1097 * Called if an interval expires before sidewaysintpr has completed a loop. 1098 * Sets a flag to not wait for the alarm. 1099 */ 1100static void 1101catchalarm(int signo) 1102{ 1103 1104 signalled = true; 1105} 1106 1107static void 1108get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1109{ 1110 int i; 1111 1112 for (i = 0; i < RTAX_MAX; i++) { 1113 if (addrs & (1 << i)) { 1114 rti_info[i] = sa; 1115 sa = (struct sockaddr *)((char *)(sa) + 1116 RT_ROUNDUP(sa->sa_len)); 1117 } else 1118 rti_info[i] = NULL; 1119 } 1120} 1121 1122static void 1123fetchifs(void) 1124{ 1125 struct if_msghdr *ifm; 1126 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1127 struct rt_msghdr *rtm; 1128 struct if_data *ifd = NULL; 1129 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1130 struct sockaddr_dl *sdl; 1131 static char *buf = NULL; 1132 static size_t olen; 1133 struct if_data_ext dext; 1134 char *next, *lim; 1135 char name[IFNAMSIZ]; 1136 size_t len; 1137 1138 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1139 err(1, "sysctl"); 1140 if (len > olen) { 1141 free(buf); 1142 if ((buf = malloc(len)) == NULL) 1143 err(1, NULL); 1144 olen = len; 1145 } 1146 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1147 err(1, "sysctl"); 1148 1149 memset(&dext, 0, sizeof(dext)); 1150 lim = buf + len; 1151 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1152 rtm = (struct rt_msghdr *)next; 1153 if (rtm->rtm_version != RTM_VERSION) 1154 continue; 1155 switch (rtm->rtm_type) { 1156 case RTM_IFINFO: 1157 ifm = (struct if_msghdr *)next; 1158 ifd = &ifm->ifm_data; 1159 1160 sa = (struct sockaddr *)(ifm + 1); 1161 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1162 1163 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1164 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1165 continue; 1166 bzero(name, sizeof(name)); 1167 if (sdl->sdl_nlen >= IFNAMSIZ) 1168 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1169 else if (sdl->sdl_nlen > 0) 1170 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1171 1172 if_data_ext_get(name, &dext); 1173 1174 if ((interface != NULL && !strcmp(name, interface)) || 1175 (interface == NULL && 1176 ((ip_cur.ift_ib + ip_cur.ift_ob) == 0 || 1177 (ip_cur.ift_ib + ip_cur.ift_ob < 1178 ifd->ifi_ibytes + ifd->ifi_obytes)))) { 1179 strlcpy(ip_cur.ift_name, name, 1180 sizeof(ip_cur.ift_name)); 1181 ip_cur.ift_ip = ifd->ifi_ipackets; 1182 ip_cur.ift_ib = ifd->ifi_ibytes; 1183 ip_cur.ift_ie = ifd->ifi_ierrors; 1184 ip_cur.ift_op = ifd->ifi_opackets; 1185 ip_cur.ift_ob = ifd->ifi_obytes; 1186 ip_cur.ift_oe = ifd->ifi_oerrors; 1187 ip_cur.ift_co = ifd->ifi_collisions; 1188 ip_cur.ift_iq = ifd->ifi_iqdrops; 1189 ip_cur.ift_oq = dext.ifi_oqdrops; 1190 } 1191 1192 sum_cur.ift_ip += ifd->ifi_ipackets; 1193 sum_cur.ift_ib += ifd->ifi_ibytes; 1194 sum_cur.ift_ie += ifd->ifi_ierrors; 1195 sum_cur.ift_op += ifd->ifi_opackets; 1196 sum_cur.ift_ob += ifd->ifi_obytes; 1197 sum_cur.ift_oe += ifd->ifi_oerrors; 1198 sum_cur.ift_co += ifd->ifi_collisions; 1199 sum_cur.ift_iq += ifd->ifi_iqdrops; 1200 sum_cur.ift_oq += dext.ifi_oqdrops; 1201 break; 1202 } 1203 } 1204 1205 /* 1206 * If we picked an interface, be sure to keep using it for the rest 1207 * of this instance. 1208 */ 1209 if (interface == NULL) 1210 interface = ip_cur.ift_name; 1211} 1212