diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index c039cbd4ac14..483e8ef2b502 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -15,7 +15,7 @@ CFLAGS+=-DINET6 BINGRP= kmem BINMODE=2555 -DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH} ${LIBUTIL} -LDADD= -lkvm -lipx -lnetgraph -lutil +DPADD= ${LIBKVM} ${LIBIPX} ${LIBMEMSTAT} ${LIBNETGRAPH} ${LIBUTIL} +LDADD= -lkvm -lipx -lmemstat -lnetgraph -lutil .include diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c index feb4871d8f42..b7b41eb05ecf 100644 --- a/usr.bin/netstat/mbuf.c +++ b/usr.bin/netstat/mbuf.c @@ -1,6 +1,8 @@ /* * Copyright (c) 1983, 1988, 1993 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. + * Copyright (c) 2005 Robert N. M. Watson + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -93,15 +96,14 @@ static struct mbtypenames { }; /* - * Print mbuf statistics. + * Print mbuf statistics extracted from kmem. */ void -mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, - u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, - u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) +mbpr_kmem(u_long mbaddr, u_long nmbcaddr, u_long nmbufaddr, u_long mbhiaddr, + u_long clhiaddr, u_long mbloaddr, u_long clloaddr, u_long pgsaddr, + u_long mbpaddr) { int i, nmbclusters; - int nsfbufs, nsfbufspeak, nsfbufsused; short nmbtypes; size_t mlen; long *mbtypes = NULL; @@ -115,25 +117,11 @@ mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, goto err; } - if (mbaddr) { - if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) - goto err; - if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) - goto err; - } else { - mlen = sizeof *mbstat; - if (sysctlbyname("kern.ipc.mbstat", mbstat, &mlen, NULL, 0) - < 0) { - warn("sysctl: retrieving mbstat"); - goto err; - } - mlen = sizeof(int); - if (sysctlbyname("kern.ipc.nmbclusters", &nmbclusters, &mlen, - NULL, 0) < 0) { - warn("sysctl: retrieving nmbclusters"); - goto err; - } - } + if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) + goto err; + if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) + goto err; + if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0; /* XXX */ if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0; /* XXX */ @@ -170,15 +158,6 @@ mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, printf("%lu/%d mbuf clusters in use (current/max)\n", mbstat->m_mclusts, nmbclusters); - mlen = sizeof(nsfbufs); - if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && - !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, - 0) && - !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, - 0)) { - printf("%d/%d/%d sfbufs in use (current/peak/max)\n", - nsfbufsused, nsfbufspeak, nsfbufs); - } printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE + mbstat->m_mclusts * MCLBYTES) / 1024); printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail); @@ -195,3 +174,185 @@ mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, if (mbstat != NULL) free(mbstat); } + +/* + * If running on a live kernel, directly query the zone allocator for stats + * from the four mbuf-related zones/types. + */ +static void +mbpr_sysctl(void) +{ + struct memory_type_list *mtlp; + struct memory_type *mtp; + u_int64_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size; + u_int64_t cluster_count, cluster_bytes, cluster_limit, cluster_free; + u_int64_t cluster_failures, cluster_size; + u_int64_t packet_count, packet_bytes, packet_free, packet_failures; + u_int64_t tag_count, tag_bytes; + u_int64_t bytes_inuse, bytes_incache, bytes_total; + int nsfbufs, nsfbufspeak, nsfbufsused; + struct mbstat mbstat; + size_t mlen; + + mtlp = memstat_mtl_alloc(); + if (mtlp == NULL) { + warn("memstat_mtl_alloc"); + return; + } + + /* + * Use memstat_sysctl_all() because some mbuf-related memory is in + * uma(9), and some malloc(9). + */ + if (memstat_sysctl_all(mtlp, 0) < 0) { + warn("memstat_sysctl_all"); + goto out; + } + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME); + goto out; + } + mbuf_count = memstat_get_count(mtp); + mbuf_bytes = memstat_get_bytes(mtp); + mbuf_free = memstat_get_free(mtp); + mbuf_failures = memstat_get_failures(mtp); + mbuf_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_PACKET_MEM_NAME); + goto out; + } + packet_count = memstat_get_count(mtp); + packet_bytes = memstat_get_bytes(mtp); + packet_free = memstat_get_free(mtp); + packet_failures = memstat_get_failures(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: zone %s not found", + MBUF_CLUSTER_MEM_NAME); + goto out; + } + cluster_count = memstat_get_count(mtp); + cluster_bytes = memstat_get_bytes(mtp); + cluster_limit = memstat_get_countlimit(mtp); + cluster_free = memstat_get_free(mtp); + cluster_failures = memstat_get_failures(mtp); + cluster_size = memstat_get_size(mtp); + + mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME); + if (mtp == NULL) { + warnx("memstat_mtl_find: malloc type %s not found", + MBUF_TAG_MEM_NAME); + goto out; + } + tag_count = memstat_get_count(mtp); + tag_bytes = memstat_get_bytes(mtp); + + printf("%llu/%llu/%llu mbufs in use (current/cache/total)\n", + mbuf_count + packet_count, mbuf_free + packet_free, + mbuf_count + packet_count + mbuf_free + packet_free); + + printf("%llu/%llu/%llu/%llu mbuf clusters in use " + "(current/cache/total/max)\n", + cluster_count - packet_free, cluster_free + packet_free, + cluster_count + cluster_free, cluster_limit); + +#if 0 + printf("%llu mbuf tags in use\n", tag_count); +#endif + + mlen = sizeof(nsfbufs); + if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && + !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, + 0) && + !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, + 0)) { + printf("%d/%d/%d sfbufs in use (current/peak/max)\n", + nsfbufsused, nsfbufspeak, nsfbufs); + } + + /*- + * Calculate in-use bytes as: + * - straight mbuf memory + * - mbuf memory in packets + * - the clusters attached to packets + * - and the rest of the non-packet-attached clusters. + * - m_tag memory + * This avoids counting the clusters attached to packets in the cache. + * This currently excludes sf_buf space. + */ + bytes_inuse = + mbuf_bytes + /* straight mbuf memory */ + packet_bytes + /* mbufs in packets */ + (packet_count * cluster_size) + /* clusters in packets */ + /* other clusters */ + ((cluster_count - packet_count - packet_free) * cluster_size) + + tag_bytes; + + /* + * Calculate in-cache bytes as: + * - cached straught mbufs + * - cached packet mbufs + * - cached packet clusters + * - cached straight clusters + * This currently excludes sf_buf space. + */ + bytes_incache = + (mbuf_free * mbuf_size) + /* straight free mbufs */ + (packet_free * mbuf_size) + /* mbufs in free packets */ + (packet_free * cluster_size) + /* clusters in free packets */ + (cluster_free * cluster_size); /* free clusters */ + + /* + * Total is bytes in use + bytes in cache. This doesn't take into + * account various other misc data structures, overhead, etc, but + * gives the user something useful despite that. + */ + bytes_total = bytes_inuse + bytes_incache; + + printf("%lluK/%lluK/%lluK bytes allocated to network " + "(current/cache/total)\n", bytes_inuse / 1024, + bytes_incache / 1024, bytes_total / 1024); + +#if 0 + printf("%llu/%llu/%llu requests for mbufs denied (mbufs/clusters/" + "mbuf+clusters)\n", mbuf_failures, cluster_failures, + packet_failures); +#endif + + mlen = sizeof(mbstat); + if (!sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) { + printf("%lu requests for sfbufs denied\n", + mbstat.sf_allocfail); + printf("%lu requests for sfbufs delayed\n", + mbstat.sf_allocwait); + printf("%lu requests for I/O initiated by sendfile\n", + mbstat.sf_iocnt); + printf("%lu calls to protocol drain routines\n", + mbstat.m_drain); + } + +out: + memstat_mtl_free(mtlp); +} + +/* + * Print mbuf statistics. + */ +void +mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, + u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, + u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) +{ + + if (mbaddr != 0) + mbpr_kmem(mbaddr, nmbcaddr, nmbufaddr, mbhiaddr, clhiaddr, + mbloaddr, clloaddr, pgsaddr, mbpaddr); + else + mbpr_sysctl(); +}