From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- network_cmds/netstat.tproj/mbuf.c | 476 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 476 insertions(+) create mode 100644 network_cmds/netstat.tproj/mbuf.c (limited to 'network_cmds/netstat.tproj/mbuf.c') diff --git a/network_cmds/netstat.tproj/mbuf.c b/network_cmds/netstat.tproj/mbuf.c new file mode 100644 index 0000000..38645e9 --- /dev/null +++ b/network_cmds/netstat.tproj/mbuf.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2008-2010 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "netstat.h" + +#define YES 1 +typedef int bool; + +struct mbstat mbstat; + +static struct mbtypes { + int mt_type; + char *mt_name; +} mbtypes[] = { + { MT_DATA, "data" }, + { MT_OOBDATA, "oob data" }, + { MT_CONTROL, "ancillary data" }, + { MT_HEADER, "packet headers" }, + { MT_SOCKET, "socket structures" }, /* XXX */ + { MT_PCB, "protocol control blocks" }, /* XXX */ + { MT_RTABLE, "routing table entries" }, /* XXX */ + { MT_HTABLE, "IMP host table entries" }, /* XXX */ + { MT_ATABLE, "address resolution tables" }, + { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ + { MT_SONAME, "socket names and addresses" }, + { MT_SOOPTS, "socket options" }, + { MT_RIGHTS, "access rights" }, + { MT_IFADDR, "interface addresses" }, /* XXX */ + { MT_TAG, "packet tags" }, /* XXX */ + { 0, 0 } +}; + +int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short); +bool seen[256]; /* "have we seen this type yet?" */ + +mb_stat_t *mb_stat; +unsigned int njcl, njclbytes; +mleak_stat_t *mleak_stat; +struct mleak_table table; + +#define KERN_IPC_MB_STAT "kern.ipc.mb_stat" +#define KERN_IPC_NJCL "kern.ipc.njcl" +#define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes" +#define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table" +#define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace" + +#define MB_STAT_HDR1 "\ +class buf active ctotal total cache cached uncached memory\n\ +name size bufs bufs bufs state bufs bufs usage\n\ +---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\ +" + +#define MB_STAT_HDR2 "\n\ +class waiter notify purge wretry nwretry failure\n\ +name count count count count count count\n\ +---------- -------- -------- -------- -------- -------- --------\n\ +" + +#define MB_LEAK_HDR "\n\ + calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\ + ------------------ ------------------ ------------------ ------------------ ------------------ \n\ +" + +#define MB_LEAK_SPACING " " +static const char *mbpr_state(int); +static const char *mbpr_mem(u_int32_t); +static int mbpr_getdata(void); + +/* + * Print mbuf statistics. + */ +void +mbpr(void) +{ + unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0; + double totpct; + u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0; + u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0; + u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0; + int i; + struct mbtypes *mp; + mb_class_stat_t *cp; + + if (mbpr_getdata() != 0) + return; + + m_msize = mbstat.m_msize; + cp = &mb_stat->mbs_class[0]; + for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) { + if (cp->mbcl_size == m_msize) { + m_mbufs = cp->mbcl_active; + } else if (cp->mbcl_size == mbstat.m_mclbytes) { + m_clfree = cp->mbcl_total - cp->mbcl_active; + } else if (cp->mbcl_size == mbstat.m_bigmclbytes) { + m_bigclfree = cp->mbcl_total - cp->mbcl_active; + } else if (njcl > 0 && cp->mbcl_size == njclbytes) { + m_16kclfree = cp->mbcl_total - cp->mbcl_active; + m_16kclusters = cp->mbcl_total; + } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) { + m_mbufclfree = cp->mbcl_total - cp->mbcl_active; + } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) { + m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active; + } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) { + m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active; + } + } + + /* adjust free counts to include composite caches */ + m_clfree += m_mbufclfree; + m_bigclfree += m_mbufbigclfree; + m_16kclfree += m_mbuf16kclfree; + + cp = &mb_stat->mbs_class[0]; + for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) { + u_int32_t mem; + + mem = cp->mbcl_ctotal * cp->mbcl_size; + totmem += mem; + totreturned += cp->mbcl_release_cnt; + totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) * + cp->mbcl_size; + if (mflag > 1) { + if (i == 0) + printf(MB_STAT_HDR1); + + if (njcl == 0 && + cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes)) + continue; + + printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n", + cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active, + cp->mbcl_ctotal, cp->mbcl_total, + mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached, + cp->mbcl_infree, mbpr_mem(mem)); + } + } + + cp = &mb_stat->mbs_class[0]; + for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) { + if (mflag > 2) { + if (i == 0) + printf(MB_STAT_HDR2); + + if (njcl == 0 && + cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes)) + continue; + + printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n", + cp->mbcl_cname, cp->mbcl_mc_waiter_cnt, + cp->mbcl_notified, cp->mbcl_purge_cnt, + cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt, + cp->mbcl_fail_cnt); + } + } + + if (mflag > 1) + printf("\n"); + + totmbufs = 0; + for (mp = mbtypes; mp->mt_name; mp++) + totmbufs += mbstat.m_mtypes[mp->mt_type]; + /* + * These stats are not updated atomically in the kernel; + * adjust the total as neeeded. + */ + if (totmbufs > m_mbufs) + totmbufs = m_mbufs; + printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs); + for (mp = mbtypes; mp->mt_name; mp++) + if (mbstat.m_mtypes[mp->mt_type]) { + seen[mp->mt_type] = YES; + printf("\t%u mbufs allocated to %s\n", + mbstat.m_mtypes[mp->mt_type], mp->mt_name); + } + seen[MT_FREE] = YES; + for (i = 0; i < nmbtypes; i++) + if (!seen[i] && mbstat.m_mtypes[i]) { + printf("\t%u mbufs allocated to \n", + mbstat.m_mtypes[i], i); + } + if ((m_mbufs - totmbufs) > 0) + printf("\t%lu mbufs allocated to caches\n", + m_mbufs - totmbufs); + printf("%u/%u mbuf 2KB clusters in use\n", + (unsigned int)(mbstat.m_clusters - m_clfree), + (unsigned int)mbstat.m_clusters); + printf("%u/%u mbuf 4KB clusters in use\n", + (unsigned int)(mbstat.m_bigclusters - m_bigclfree), + (unsigned int)mbstat.m_bigclusters); + if (njcl > 0) { + printf("%u/%u mbuf %uKB clusters in use\n", + m_16kclusters - m_16kclfree, m_16kclusters, + njclbytes/1024); + } + totused = totmem - totfree; + if (totmem == 0) + totpct = 0; + else if (totused < (ULONG_MAX/100)) + totpct = (totused * 100)/(double)totmem; + else { + u_long totmem1 = totmem/100; + u_long totused1 = totused/100; + totpct = (totused1 * 100)/(double)totmem1; + } + printf("%lu KB allocated to network (%.1f%% in use)\n", + totmem / 1024, totpct); + printf("%lu KB returned to the system\n", totreturned / 1024); + + printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops); + printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait); + 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); +} -- cgit v1.2.3-56-ge451