+ printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
+
+ free(mb_stat);
+ mb_stat = NULL;
+
+ if (mleak_stat != NULL) {
+ mleak_trace_stat_t *mltr;
+
+ printf("\nmbuf leak detection table:\n");
+ printf("\ttotal captured: %u (one per %u)\n"
+ "\ttotal allocs outstanding: %llu\n"
+ "\tnew hash recorded: %llu allocs, %llu traces\n"
+ "\thash collisions: %llu allocs, %llu traces\n"
+ "\toverwrites: %llu allocs, %llu traces\n"
+ "\tlock conflicts: %llu\n\n",
+ table.mleak_capture / table.mleak_sample_factor,
+ table.mleak_sample_factor,
+ table.outstanding_allocs,
+ table.alloc_recorded, table.trace_recorded,
+ table.alloc_collisions, table.trace_collisions,
+ table.alloc_overwrites, table.trace_overwrites,
+ table.total_conflicts);
+
+ printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
+ for (i = 0; i < mleak_stat->ml_cnt; i++) {
+ mltr = &mleak_stat->ml_trace[i];
+ printf("[%d] %llu outstanding alloc(s), "
+ "%llu hit(s), %llu collision(s)\n", (i + 1),
+ mltr->mltr_allocs, mltr->mltr_hitcount,
+ mltr->mltr_collisions);
+ }
+
+ printf(MB_LEAK_HDR);
+ for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
+ int j;
+
+ printf("%2d: ", (i + 1));
+ for (j = 0; j < mleak_stat->ml_cnt; j++) {
+ mltr = &mleak_stat->ml_trace[j];
+ if (i < mltr->mltr_depth) {
+ if (mleak_stat->ml_isaddr64) {
+ printf("0x%0llx ",
+ mltr->mltr_addr[i]);
+ } else {
+ printf("0x%08x ",
+ (u_int32_t)mltr->mltr_addr[i]);
+ }
+ } else {
+ printf(MB_LEAK_SPACING);
+ }
+ }
+ printf("\n");
+ }
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+}
+
+static const char *
+mbpr_state(int state)
+{
+ char *msg = "?";
+
+ switch (state) {
+ case MCS_DISABLED:
+ msg = "dis";
+ break;
+
+ case MCS_ONLINE:
+ msg = "on";
+ break;
+
+ case MCS_PURGING:
+ msg = "purge";
+ break;
+
+ case MCS_OFFLINE:
+ msg = "off";
+ break;
+ }
+ return (msg);
+}
+
+static const char *
+mbpr_mem(u_int32_t bytes)
+{
+ static char buf[33];
+ double mem = bytes;
+
+ if (mem < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
+ } else if ((mem /= 1024) < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
+ } else {
+ mem /= 1024;
+ (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
+ }
+ return (buf);
+}
+
+static int
+mbpr_getdata(void)
+{
+ size_t len;
+ int error = -1;
+
+ if (nmbtypes != 256) {
+ (void) fprintf(stderr,
+ "netstat: unexpected change to mbstat; check source\n");
+ goto done;
+ }
+
+ len = sizeof(mbstat);
+ if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
+ goto done;
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ mb_stat = calloc(1, len);
+ if (mb_stat == NULL) {
+ (void) fprintf(stderr,
+ "Error allocating %lu bytes for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ if (mb_stat->mbs_cnt == 0) {
+ (void) fprintf(stderr,
+ "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
+ goto done;
+ }
+
+ /* mbuf leak detection! */
+ if (mflag > 3) {
+ errno = 0;
+ len = sizeof (table);
+ if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
+ -1 && errno != ENXIO) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TABLE);
+ goto done;
+ } else if (errno == ENXIO) {
+ (void) fprintf(stderr, "mbuf leak detection is not "
+ "enabled in the kernel.\n");
+ goto skip;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "Error retrieving length for "
+ "%s: %d\n", KERN_IPC_MB_STAT, errno);
+ goto done;
+ }
+
+ mleak_stat = calloc(1, len);
+ if (mleak_stat == NULL) {
+ (void) fprintf(stderr, "Error allocating %lu bytes "
+ "for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TOP_TRACE);
+ goto done;
+ }
+ }
+
+skip:
+ len = sizeof (njcl);
+ (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
+ len = sizeof (njclbytes);
+ (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
+
+ error = 0;
+
+done:
+ if (error != 0 && mb_stat != NULL) {
+ free(mb_stat);
+ mb_stat = NULL;
+ }
+
+ if (error != 0 && mleak_stat != NULL) {
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+
+ return (error);