/*- * Copyright (c) 1998 Andrzej Bialecki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/release/picobsd/tinyware/ns/ns.c,v 1.8.2.7 2002/03/27 20:42:03 abial Exp $ */ /* * Small replacement for netstat. Uses only sysctl(3) to get the info. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BRIDGING #include /* IFT_ETHER */ #include #include #endif #include #include #include #include #include char *progname; int iflag = 0; int lflag = 0; /* print cpu load info */ int rflag = 0; int sflag = 0; int pflag = 0; int mflag = 0; /* print mbuf stats */ int wflag = 0; /* repeat every wait seconds */ int delta = 0 ; extern char *optarg; extern int optind; void usage() { fprintf(stderr, "\n%s [-nmrsil] [-p proto] [-w wait]\n", progname); #ifdef BRIDGING fprintf(stderr, " proto: {ip|tcp|udp|icmp|bdg}\n\n"); #else fprintf(stderr, " proto: {ip|tcp|udp|icmp}\n\n"); #endif } /* * The following parts related to retrieving the routing table and * interface information, were borrowed from R. Stevens' code examples * accompanying his excellent book. Thanks! */ char * sock_ntop(const struct sockaddr *sa, size_t salen) { char portstr[7]; static char str[128]; /* Unix domain is largest */ switch (sa->sa_family) { case 255: { int i = 0; u_long mask; u_int index = 1 << 31; u_short new_mask = 0; mask = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); while (mask & index) { new_mask++; index >>= 1; } sprintf(str, "/%hu", new_mask); return (str); } case AF_UNSPEC: case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)sa; if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) return (NULL); if (ntohs(sin->sin_port) != 0) { snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); strcat(str, portstr); } if (strcmp(str, "0.0.0.0") == 0) sprintf(str, "default"); return (str); } case AF_UNIX: { struct sockaddr_un *unp = (struct sockaddr_un *)sa; /* * OK to have no pathname bound to the socket: * happens on every connect() unless client calls * bind() first. */ if (unp->sun_path[0] == 0) strcpy(str, "(no pathname bound)"); else snprintf(str, sizeof(str), "%s", unp->sun_path); return (str); } case AF_LINK: { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen > 0) { bcopy(&sdl->sdl_data[0], str, sdl->sdl_nlen); str[sdl->sdl_nlen] = '\0'; } else snprintf(str, sizeof(str), "link#%d", sdl->sdl_index); return (str); } default: snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family, salen); return (str); } return (NULL); } char * Sock_ntop(const struct sockaddr *sa, size_t salen) { char *ptr; if ((ptr = sock_ntop(sa, salen)) == NULL) err(1, "sock_ntop error"); /* inet_ntop() sets errno */ return (ptr); } #define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a)) #define NEXT_SA(ap) \ ap=(struct sockaddr *) \ ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\ sizeof(u_long))) void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; NEXT_SA(sa); } else rti_info[i] = NULL; } } void get_flags(char *buf, int flags) { if (flags & 0x1) strcat(buf, "U"); if (flags & 0x2) strcat(buf, "G"); if (flags & 0x4) strcat(buf, "H"); if (flags & 0x8) strcat(buf, "r"); if (flags & 0x10) strcat(buf, "d"); #ifdef NEVER if (flags & 0x20) strcat(buf, "mod,"); #endif /*NEVER*/ if (flags & 0x100) strcat(buf, "C"); if (flags & 0x400) strcat(buf, "L"); if (flags & 0x800) strcat(buf, "S"); if (flags & 0x10000) strcat(buf, "c"); if (flags & 0x20000) strcat(buf, "W"); #ifdef NEVER if (flags & 0x200000) strcat(buf, ",LOC"); #endif /*NEVER*/ if (flags & 0x400000) strcat(buf, "b"); #ifdef NEVER if (flags & 0x800000) strcat(buf, ",MCA"); #endif /*NEVER*/ } void print_routing(char *proto) { int mib[6]; int i = 0; int rt_len; int if_len; int if_num; char *rt_buf; char *if_buf; char *next; char *lim; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct if_msghdr **ifm_table; struct ifa_msghdr *ifam; struct sockaddr *sa; struct sockaddr *sa1; struct sockaddr *rti_info[RTAX_MAX]; struct sockaddr **if_table; struct rt_metrics rm; char fbuf[50]; /* keep a copy of statistics here for future use */ static unsigned *base_stats = NULL ; static unsigned base_len = 0 ; /* Get the routing table */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; /*Estimate the size of table */ if (sysctl(mib, 6, NULL, &rt_len, NULL, 0) == -1) { perror("sysctl size"); exit(-1); } if ((rt_buf = (char *)malloc(rt_len)) == NULL) { perror("malloc"); exit(-1); } /* Now get it. */ if (sysctl(mib, 6, rt_buf, &rt_len, NULL, 0) == -1) { perror("sysctl get"); exit(-1); } /* Get the interfaces table */ mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = 0; mib[4] = NET_RT_IFLIST; mib[5] = 0; /* Estimate the size of table */ if (sysctl(mib, 6, NULL, &if_len, NULL, 0) == -1) { perror("sysctl size"); exit(-1); } if ((if_buf = (char *)malloc(if_len)) == NULL) { perror("malloc"); exit(-1); } /* Now get it. */ if (sysctl(mib, 6, if_buf, &if_len, NULL, 0) == -1) { perror("sysctl get"); exit(-1); } lim = if_buf + if_len; i = 0; for (next = if_buf, i = 0; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; i++; } if_num = i; if_table = (struct sockaddr **)calloc(i, sizeof(struct sockaddr)); ifm_table = (struct if_msghdr **)calloc(i, sizeof(struct if_msghdr)); if (iflag) { printf("\nInterface table:\n"); printf("----------------\n"); printf("Name Mtu Network Address " "Ipkts Ierrs Opkts Oerrs Coll\n"); } /* scan the list and store base values */ i = 0 ; for (next = if_buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; i++ ; } if (base_stats == NULL || i != base_len) { base_stats = calloc(i*5, sizeof(unsigned)); base_len = i ; } i = 0; for (next = if_buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if_table[i] = (struct sockaddr *)(ifm + 1); ifm_table[i] = ifm; sa = if_table[i]; if (iflag && sa->sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; unsigned *bp = &base_stats[i*5]; printf("%-4s %-5d ", sock_ntop(if_table[i], if_table[i]->sa_len), ifm->ifm_data.ifi_mtu); if (sdl->sdl_alen == 6) { unsigned char *p = sdl->sdl_data + sdl->sdl_nlen; printf("%02x:%02x:%02x:%02x:%02x:%02x ", p[0], p[1], p[2], p[3], p[4], p[5]); } else printf(" "); printf("%9d%6d%9d%6d%6d\n", ifm->ifm_data.ifi_ipackets - bp[0], ifm->ifm_data.ifi_ierrors - bp[1], ifm->ifm_data.ifi_opackets - bp[2], ifm->ifm_data.ifi_oerrors - bp[3], ifm->ifm_data.ifi_collisions -bp[4]); if (delta > 0) { bp[0] = ifm->ifm_data.ifi_ipackets ; bp[1] = ifm->ifm_data.ifi_ierrors ; bp[2] = ifm->ifm_data.ifi_opackets ; bp[3] = ifm->ifm_data.ifi_oerrors ; bp[4] = ifm->ifm_data.ifi_collisions ; } } i++; } if (!rflag) { free(rt_buf); free(if_buf); free(if_table); free(ifm_table); return; } /* Now dump the routing table */ printf("\nRouting table:\n"); printf("--------------\n"); printf ("Destination Gateway Flags Netif Use\n"); lim = rt_buf + rt_len; for (next = rt_buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if (rtm->rtm_flags & RTF_WASCLONED) { if ((rtm->rtm_flags & RTF_LLINFO) == 0) continue; } if ((sa = rti_info[RTAX_DST]) != NULL) { sprintf(fbuf, "%s", sock_ntop(sa, sa->sa_len)); if (((sa1 = rti_info[RTAX_NETMASK]) != NULL) && sa1->sa_family == 255) { strcat(fbuf, sock_ntop(sa1, sa1->sa_len)); } printf("%-19s", fbuf); } if ((sa = rti_info[RTAX_GATEWAY]) != NULL) { printf("%-19s", sock_ntop(sa, sa->sa_len)); } memset(fbuf, 0, sizeof(fbuf)); get_flags(fbuf, rtm->rtm_flags); printf("%-10s", fbuf); for (i = 0; i < if_num; i++) { ifm = ifm_table[i]; if ((ifm->ifm_index == rtm->rtm_index) && (ifm->ifm_data.ifi_type > 0)) { sa = if_table[i]; break; } } if (ifm->ifm_type == RTM_IFINFO) { get_rtaddrs(ifm->ifm_addrs, sa, rti_info); printf(" %s", Sock_ntop(sa, sa->sa_len)); } else if (ifm->ifm_type == RTM_NEWADDR) { ifam = (struct ifa_msghdr *)ifm_table[rtm->rtm_index - 1]; sa = (struct sockaddr *)(ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); printf(" %s", Sock_ntop(sa, sa->sa_len)); } printf(" %u", rtm->rtm_use); printf("\n"); } free(rt_buf); free(if_buf); free(if_table); free(ifm_table); return; } print_ip_stats() { int mib[4]; int len; struct ipstat s; mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_IP; #ifndef IPCTL_STATS printf("sorry, ip stats not available\n"); return -1; #else mib[3] = IPCTL_STATS; len = sizeof(struct ipstat); if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { perror("sysctl"); return (-1); } printf("\nIP statistics:\n"); printf("--------------\n"); printf(" %10lu total packets received\n", s.ips_total); printf("* Packets ok:\n"); printf(" %10lu fragments received\n", s.ips_fragments); printf(" %10lu forwarded\n", s.ips_forward); #if __FreeBSD_version > 300001 printf(" %10lu fast forwarded\n", s.ips_fastforward); #endif printf(" %10lu forwarded on same net (redirect)\n", s.ips_redirectsent); printf(" %10lu delivered to upper level\n", s.ips_delivered); printf(" %10lu total ip packets generated here\n", s.ips_localout); printf(" %10lu total packets reassembled ok\n", s.ips_reassembled); printf(" %10lu total datagrams successfully fragmented\n", s.ips_fragmented); printf(" %10lu output fragments created\n", s.ips_ofragments); printf(" %10lu total raw IP packets generated\n", s.ips_rawout); printf("\n* Bad packets:\n"); printf(" %10lu bad checksum\n", s.ips_badsum); printf(" %10lu too short\n", s.ips_tooshort); printf(" %10lu not enough data (too small)\n", s.ips_toosmall); printf(" %10lu more data than declared in header\n", s.ips_badhlen); printf(" %10lu less data than declared in header\n", s.ips_badlen); printf(" %10lu fragments dropped (dups, no mbuf)\n", s.ips_fragdropped); printf(" %10lu fragments timed out in reassembly\n", s.ips_fragtimeout); printf(" %10lu received for unreachable dest.\n", s.ips_cantforward); printf(" %10lu unknown or unsupported protocol\n", s.ips_noproto); printf(" %10lu lost due to no bufs etc.\n", s.ips_odropped); printf(" %10lu couldn't fragment (DF set, etc.)\n", s.ips_cantfrag); printf(" %10lu error in IP options processing\n", s.ips_badoptions); printf(" %10lu dropped due to no route\n", s.ips_noroute); printf(" %10lu bad IP version\n", s.ips_badvers); printf(" %10lu too long (more than max IP size)\n", s.ips_toolong); #if __FreeBSD_version > 300001 printf(" %10lu multicast for unregistered groups\n", s.ips_notmember); #endif #endif } print_tcp_stats() { int mib[4]; int len; struct tcpstat s; mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_TCP; #ifndef TCPCTL_STATS printf("sorry, tcp stats not available\n"); return -1; #else mib[3] = TCPCTL_STATS; len = sizeof(struct tcpstat); if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { perror("sysctl"); return (-1); } printf("\nTCP statistics:\n"); printf("---------------\n"); printf("* Connections:\n"); printf(" %10lu initiated\n", s.tcps_connattempt); printf(" %10lu accepted\n", s.tcps_accepts); printf(" %10lu established\n", s.tcps_connects); printf(" %10lu dropped\n", s.tcps_drops); printf(" %10lu embryonic connections dropped\n", s.tcps_conndrops); printf(" %10lu closed (includes dropped)\n", s.tcps_closed); printf(" %10lu segments where we tried to get RTT\n", s.tcps_segstimed); printf(" %10lu times RTT successfully updated\n", s.tcps_rttupdated); printf(" %10lu delayed ACKs sent\n", s.tcps_delack); printf(" %10lu dropped in rxmt timeout\n", s.tcps_timeoutdrop); printf(" %10lu retrasmit timeouts\n", s.tcps_rexmttimeo); printf(" %10lu persist timeouts\n", s.tcps_persisttimeo); printf(" %10lu keepalive timeouts\n", s.tcps_keeptimeo); printf(" %10lu keepalive probes sent\n", s.tcps_keepprobe); printf(" %10lu dropped in keepalive\n", s.tcps_keepdrops); printf("* Packets sent:\n"); printf(" %10lu total packets sent\n", s.tcps_sndtotal); printf(" %10lu data packets sent\n", s.tcps_sndpack); printf(" %10lu data bytes sent\n", s.tcps_sndbyte); printf(" %10lu data packets retransmitted\n", s.tcps_sndrexmitpack); printf(" %10lu data bytes retransmitted\n", s.tcps_sndrexmitbyte); printf(" %10lu ACK-only packets sent\n", s.tcps_sndacks); printf(" %10lu window probes sent\n", s.tcps_sndprobe); printf(" %10lu URG-only packets sent\n", s.tcps_sndurg); printf(" %10lu window update-only packets sent\n", s.tcps_sndwinup); printf(" %10lu control (SYN,FIN,RST) packets sent\n", s.tcps_sndctrl); printf("* Packets received:\n"); printf(" %10lu total packets received\n", s.tcps_rcvtotal); printf(" %10lu packets in sequence\n", s.tcps_rcvpack); printf(" %10lu bytes in sequence\n", s.tcps_rcvbyte); printf(" %10lu packets with bad checksum\n", s.tcps_rcvbadsum); printf(" %10lu packets with bad offset\n", s.tcps_rcvbadoff); printf(" %10lu packets too short\n", s.tcps_rcvshort); printf(" %10lu duplicate-only packets\n", s.tcps_rcvduppack); printf(" %10lu duplicate-only bytes\n", s.tcps_rcvdupbyte); printf(" %10lu packets with some duplicate data\n", s.tcps_rcvpartduppack); printf(" %10lu duplicate bytes in partially dup. packets\n", s.tcps_rcvpartdupbyte); printf(" %10lu out-of-order packets\n", s.tcps_rcvoopack); printf(" %10lu out-of-order bytes\n", s.tcps_rcvoobyte); printf(" %10lu packets with data after window\n", s.tcps_rcvpackafterwin); printf(" %10lu bytes received after window\n", s.tcps_rcvbyteafterwin); printf(" %10lu packets received after 'close'\n", s.tcps_rcvafterclose); printf(" %10lu window probe packets\n", s.tcps_rcvwinprobe); printf(" %10lu duplicate ACKs\n", s.tcps_rcvdupack); printf(" %10lu ACKs for unsent data\n", s.tcps_rcvacktoomuch); printf(" %10lu ACK packets\n", s.tcps_rcvackpack); printf(" %10lu bytes ACKed by received ACKs\n", s.tcps_rcvackbyte); printf(" %10lu window update packets\n", s.tcps_rcvwinupd); printf(" %10lu segments dropped due to PAWS\n", s.tcps_pawsdrop); printf(" %10lu times header predict ok for ACKs\n", s.tcps_predack); printf(" %10lu times header predict ok for data packets\n", s.tcps_preddat); printf(" %10lu PCB cache misses\n", s.tcps_pcbcachemiss); printf(" %10lu times cached RTT in route updated\n", s.tcps_cachedrtt); printf(" %10lu times cached RTTVAR updated\n", s.tcps_cachedrttvar); printf(" %10lu times ssthresh updated\n", s.tcps_cachedssthresh); printf(" %10lu times RTT initialized from route\n", s.tcps_usedrtt); printf(" %10lu times RTTVAR initialized from route\n", s.tcps_usedrttvar); printf(" %10lu times ssthresh initialized from route\n", s.tcps_usedssthresh); printf(" %10lu timeout in persist state\n", s.tcps_persistdrop); printf(" %10lu bogus SYN, e.g. premature ACK\n", s.tcps_badsyn); printf(" %10lu resends due to MTU discovery\n", s.tcps_mturesent); printf(" %10lu listen queue overflows\n", s.tcps_listendrop); #endif } print_udp_stats() { int mib[4]; int len; struct udpstat s; mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_UDP; mib[3] = UDPCTL_STATS; len = sizeof(struct udpstat); if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { perror("sysctl"); return (-1); } printf("\nUDP statistics:\n"); printf("---------------\n"); printf("* Packets received:\n"); printf(" %10lu total input packets\n", s.udps_ipackets); printf(" %10lu packets shorter than header (dropped)\n", s.udps_hdrops); printf(" %10lu bad checksum\n", s.udps_badsum); printf(" %10lu data length larger than packet\n", s.udps_badlen); printf(" %10lu no socket on specified port\n", s.udps_noport); printf(" %10lu of above, arrived as broadcast\n", s.udps_noportbcast); printf(" %10lu not delivered, input socket full\n", s.udps_fullsock); printf(" %10lu packets missing PCB cache\n", s.udpps_pcbcachemiss); printf(" %10lu packets not for hashed PCBs\n", s.udpps_pcbhashmiss); printf("* Packets sent:\n"); printf(" %10lu total output packets\n", s.udps_opackets); #if __FreeBSD_version > 300001 printf(" %10lu output packets on fast path\n", s.udps_fastout); #endif } char *icmp_names[] = { "echo reply", "#1", "#2", "destination unreachable", "source quench", "routing redirect", "#6", "#7", "echo", "router advertisement", "router solicitation", "time exceeded", "parameter problem", "time stamp", "time stamp reply", "information request", "information request reply", "address mask request", "address mask reply", }; print_icmp_stats() { int mib[4]; int len; int i; struct icmpstat s; mib[0] = CTL_NET; mib[1] = PF_INET; mib[2] = IPPROTO_ICMP; mib[3] = ICMPCTL_STATS; len = sizeof(struct icmpstat); if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) { perror("sysctl"); return (-1); } printf("\nICMP statistics:\n"); printf("----------------\n"); printf("* Output histogram:\n"); for (i = 0; i < (ICMP_MAXTYPE + 1); i++) { if (s.icps_outhist[i] > 0) printf("\t%10lu %s\n", s.icps_outhist[i], icmp_names[i]); } printf("* Input histogram:\n"); for (i = 0; i < (ICMP_MAXTYPE + 1); i++) { if (s.icps_inhist[i] > 0) printf("\t%10lu %s\n", s.icps_inhist[i], icmp_names[i]); } printf("* Other stats:\n"); printf(" %10lu calls to icmp_error\n", s.icps_error); printf(" %10lu no error 'cuz old ip too short\n", s.icps_oldshort); printf(" %10lu no error 'cuz old was icmp\n", s.icps_oldicmp); printf(" %10lu icmp code out of range\n", s.icps_badcode); printf(" %10lu packets shorter than min length\n", s.icps_tooshort); printf(" %10lu bad checksum\n", s.icps_checksum); printf(" %10lu calculated bound mismatch\n", s.icps_badlen); printf(" %10lu number of responses\n", s.icps_reflect); printf(" %10lu broad/multi-cast echo requests dropped\n", s.icps_bmcastecho); printf(" %10lu broad/multi-cast timestamp requests dropped\n", s.icps_bmcasttstamp); } static struct mbtypenames { int mt_type; char *mt_name; } mbtypenames[] = { { MT_DATA, "data" }, { MT_OOBDATA, "oob data" }, { MT_CONTROL, "ancillary data" }, { MT_HEADER, "packet headers" }, #ifdef MT_SOCKET { MT_SOCKET, "socket structures" }, /* XXX */ #endif #ifdef MT_PCB { MT_PCB, "protocol control blocks" }, /* XXX */ #endif #ifdef MT_RTABLE { MT_RTABLE, "routing table entries" }, /* XXX */ #endif #ifdef MT_HTABLE { MT_HTABLE, "IMP host table entries" }, /* XXX */ #endif #ifdef MT_ATABLE { MT_ATABLE, "address resolution tables" }, #endif { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ { MT_SONAME, "socket names and addresses" }, #ifdef MT_SOOPTS { MT_SOOPTS, "socket options" }, #endif #ifdef MT_RIGHTS { MT_RIGHTS, "access rights" }, #endif #ifdef MT_IFADDR { MT_IFADDR, "interface addresses" }, /* XXX */ #endif { 0, 0 } }; void print_mbuf_stats() { u_long totmem, totpossible, totmbufs; register int i; struct mbstat mbstat; struct mbtypenames *mp; int name[3], nmbclusters, nmbufs, nmbtypes; size_t nmbclen, nmbuflen, mbstatlen, mbtypeslen; u_long *mbtypes; int *seen; /* "have we seen this type yet?" */ if (mflag == 0) return ; mbtypes = NULL; seen = NULL; if (sysctlbyname("kern.ipc.mbtypes", NULL, &mbtypeslen, NULL, 0) < 0) { warn("sysctl: retrieving mbtypes length"); goto err; } if ((mbtypes = malloc(mbtypeslen)) == NULL) { warn("malloc: %lu bytes for mbtypes", (u_long)mbtypeslen); goto err; } nmbtypes = mbtypeslen / sizeof(*mbtypes); if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) { warn("calloc"); goto err; } name[0] = CTL_KERN; name[1] = KERN_IPC; name[2] = KIPC_MBSTAT; mbstatlen = sizeof mbstat; if (sysctl(name, 3, &mbstat, &mbstatlen, 0, 0) < 0) { warn("sysctl: retrieving mbstat"); goto err; } if (sysctlbyname("kern.ipc.mbtypes",mbtypes,&mbtypeslen,NULL,0) < 0) { warn("sysctl: retrieving mbtypes"); goto err; } name[2] = KIPC_NMBCLUSTERS; nmbclen = sizeof(int); if (sysctl(name, 3, &nmbclusters, &nmbclen, 0, 0) < 0) { warn("sysctl: retrieving nmbclusters"); goto err; } nmbuflen = sizeof(int); if (sysctlbyname("kern.ipc.nmbufs", &nmbufs, &nmbuflen, 0, 0) < 0) { warn("sysctl: retrieving nmbufs"); goto err; } #undef MSIZE #define MSIZE (mbstat.m_msize) #undef MCLBYTES #define MCLBYTES (mbstat.m_mclbytes) totmbufs = 0; for (mp = mbtypenames; mp->mt_name; mp++) totmbufs += mbtypes[mp->mt_type]; printf("%lu/%lu/%u mbufs in use (current/peak/max):\n", totmbufs, mbstat.m_mbufs, nmbufs); for (mp = mbtypenames; mp->mt_name; mp++) if (mbtypes[mp->mt_type]) { seen[mp->mt_type] = 1; printf("\t%lu mbufs allocated to %s\n", mbtypes[mp->mt_type], mp->mt_name); } seen[MT_FREE] = 1; for (i = 0; i < nmbtypes; i++) if (!seen[i] && mbtypes[i]) { printf("\t%lu mbufs allocated to \n", mbtypes[i], i); } printf("%lu/%lu/%u mbuf clusters in use (current/peak/max)\n", mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters, nmbclusters); totmem = mbstat.m_mbufs * MSIZE + mbstat.m_clusters * MCLBYTES; totpossible = nmbclusters * MCLBYTES + MSIZE * nmbufs; printf("%lu Kbytes allocated to network (%lu%% of mb_map in use)\n", totmem / 1024, (totmem * 100) / totpossible); printf("%lu requests for memory denied\n", mbstat.m_drops); printf("%lu requests for memory delayed\n", mbstat.m_wait); printf("%lu calls to protocol drain routines\n", mbstat.m_drain); err: if (mbtypes != NULL) free(mbtypes); if (seen != NULL) free(seen); } int stats(char *proto) { print_mbuf_stats(); if (!sflag) return 0; if (pflag) { if (proto == NULL) { fprintf(stderr, "Option '-p' requires paramter.\n"); usage(); exit(-1); } if (strcmp(proto, "ip") == 0) print_ip_stats(); if (strcmp(proto, "icmp") == 0) print_icmp_stats(); if (strcmp(proto, "udp") == 0) print_udp_stats(); if (strcmp(proto, "tcp") == 0) print_tcp_stats(); #ifdef BRIDGING if (strcmp(proto, "bdg") == 0) print_bdg_stats(); #endif return (0); } print_ip_stats(); print_icmp_stats(); print_udp_stats(); print_tcp_stats(); #ifdef BRIDGING print_bdg_stats(); #endif return (0); } int main(int argc, char *argv[]) { char c; char *proto = NULL; int have_flags = 0 ; progname = argv[0]; while ((c = getopt(argc, argv, "dilmnrsp:w:")) != -1) { have_flags++ ; switch (c) { case 'd': /* print deltas in stats every w seconds */ delta++ ; break; case 'w': wflag = atoi(optarg); break; case 'n': /* ignored, just for compatibility with std netstat */ break; case 'r': rflag++; break; case 'i': iflag++; break; case 'm': mflag++; break; case 'l': lflag++; break; case 's': sflag++; rflag = 0; break; case 'p': pflag++; sflag++; proto = optarg; break; case '?': default: usage(); exit(0); break; } } if (have_flags == 0) rflag = 1; /* default */ argc -= optind; if (argc > 0) { usage(); exit(-1); } if (wflag) printf("\033[H\033[J"); again: if (wflag) { struct timeval t; gettimeofday(&t, NULL); printf("\033[H%s", ctime(&t.tv_sec)); } print_routing(proto); print_load_stats(); stats(proto); if (wflag) { sleep(wflag); goto again; } exit(0); } int print_load_stats(void) { static u_int32_t cp_time[5]; u_int32_t new_cp_time[5]; int l; int shz; static int stathz ; if (!lflag || !wflag) return 0; l = sizeof(new_cp_time) ; bzero(new_cp_time, l); if (sysctlbyname("kern.cp_time", new_cp_time, &l, NULL, 0) < 0) { warn("sysctl: retrieving cp_time length"); return 0; } if (stathz == 0) { struct clockinfo ci; bzero (&ci, sizeof(ci)); l = sizeof(ci) ; if (sysctlbyname("kern.clockrate", &ci, &l, NULL, 0) < 0) { warn("sysctl: retrieving clockinfo length"); return 0; } stathz = ci.stathz ; bcopy(new_cp_time, cp_time, sizeof(cp_time)); } shz = stathz * wflag ; if (shz == 0) shz = 1; #define X(i) ( (double)(new_cp_time[i] - cp_time[i])*100/shz ) printf("\nUSER %5.2f%% NICE %5.2f%% SYS %5.2f%% " "INTR %5.2f%% IDLE %5.2f%%\n", X(0), X(1), X(2), X(3), X(4) ); bcopy(new_cp_time, cp_time, sizeof(cp_time)); } #ifdef BRIDGING /* print bridge statistics */ int print_bdg_stats() { int i; int mib[4]; int slen; struct bdg_stats s; slen = sizeof(s); mib[0] = CTL_NET; mib[1] = PF_LINK; mib[2] = IFT_ETHER; mib[3] = PF_BDG; if (sysctl(mib, 4, &s, &slen, NULL, 0) == -1) { return 0; /* no bridging */ } printf("-- Bridging statistics --\n"); printf( "Name In Out Forward Drop Bcast" "Mcast Local Unknown\n"); for (i = 0; i < 16; i++) { if (s.s[i].name[0]) printf("%-6s %9d%9d%9d%9d%9d%9d%9d%9d\n", s.s[i].name, s.s[i].p_in[(int)BDG_IN], s.s[i].p_in[(int)BDG_OUT], s.s[i].p_in[(int)BDG_FORWARD], s.s[i].p_in[(int)BDG_DROP], s.s[i].p_in[(int)BDG_BCAST], s.s[i].p_in[(int)BDG_MCAST], s.s[i].p_in[(int)BDG_LOCAL], s.s[i].p_in[(int)BDG_UNKNOWN]); } } #endif