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