1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. 4 * Copyright (c) 2005 Robert N. M. Watson 5 * 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #if 0 37 #ifndef lint 38 static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93"; 39 #endif /* not lint */ 40 #endif 41 42 #include <sys/cdefs.h> 43 __FBSDID("$FreeBSD$"); 44 45 #include <sys/param.h> 46 #include <sys/mbuf.h> 47 #include <sys/protosw.h> 48 #include <sys/socket.h> 49 #include <sys/sysctl.h> 50 51 #include <err.h> 52 #include <memstat.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include "netstat.h" 57 58 #define YES 1 59 typedef int bool; 60 61 static struct mbtypenames { 62 short mt_type; 63 const char *mt_name; 64 } mbtypenames[] = { 65 { MT_DATA, "data" }, 66 { MT_OOBDATA, "oob data" }, 67 { MT_CONTROL, "ancillary data" }, 68 { MT_HEADER, "packet headers" }, 69 #ifdef MT_SOCKET 70 { MT_SOCKET, "socket structures" }, /* XXX */ 71 #endif 72 #ifdef MT_PCB 73 { MT_PCB, "protocol control blocks" }, /* XXX */ 74 #endif 75 #ifdef MT_RTABLE 76 { MT_RTABLE, "routing table entries" }, /* XXX */ 77 #endif 78 #ifdef MT_HTABLE 79 { MT_HTABLE, "IMP host table entries" }, /* XXX */ 80 #endif 81 #ifdef MT_ATABLE 82 { MT_ATABLE, "address resolution tables" }, 83 #endif 84 { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ 85 { MT_SONAME, "socket names and addresses" }, 86 #ifdef MT_SOOPTS 87 { MT_SOOPTS, "socket options" }, 88 #endif 89 #ifdef MT_RIGHTS 90 { MT_RIGHTS, "access rights" }, 91 #endif 92 #ifdef MT_IFADDR 93 { MT_IFADDR, "interface addresses" }, /* XXX */ 94 #endif 95 { 0, 0 } 96 }; 97 98 /* 99 * Print mbuf statistics extracted from kmem. 100 */ 101 void 102 mbpr_kmem(u_long mbaddr, u_long nmbcaddr, u_long nmbufaddr, u_long mbhiaddr, 103 u_long clhiaddr, u_long mbloaddr, u_long clloaddr, u_long pgsaddr, 104 u_long mbpaddr) 105 { 106 int i, nmbclusters; 107 short nmbtypes; 108 size_t mlen; 109 long *mbtypes = NULL; 110 struct mbstat *mbstat = NULL; 111 struct mbtypenames *mp; 112 bool *seen = NULL; 113 114 mlen = sizeof *mbstat; 115 if ((mbstat = malloc(mlen)) == NULL) { 116 warn("malloc: cannot allocate memory for mbstat"); 117 goto err; 118 } 119 120 if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) 121 goto err; 122 if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) 123 goto err; 124 125 if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0; /* XXX */ 126 if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0; /* XXX */ 127 128 nmbtypes = mbstat->m_numtypes; 129 if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) { 130 warn("calloc: cannot allocate memory for mbtypes seen flag"); 131 goto err; 132 } 133 if ((mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) { 134 warn("calloc: cannot allocate memory for mbtypes"); 135 goto err; 136 } 137 138 #undef MSIZE 139 #define MSIZE (mbstat->m_msize) 140 #undef MCLBYTES 141 #define MCLBYTES (mbstat->m_mclbytes) 142 143 printf("%lu mbufs in use\n", mbstat->m_mbufs); 144 145 for (mp = mbtypenames; mp->mt_name; mp++) { 146 if (mbtypes[mp->mt_type]) { 147 seen[mp->mt_type] = YES; 148 printf("\t %lu mbufs allocated to %s\n", 149 mbtypes[mp->mt_type], mp->mt_name); 150 } 151 } 152 for (i = 1; i < nmbtypes; i++) { 153 if (!seen[i] && mbtypes[i]) 154 printf("\t %lu mbufs allocated to <mbuf type: %d>\n", 155 mbtypes[i], i); 156 } 157 158 printf("%lu/%d mbuf clusters in use (current/max)\n", 159 mbstat->m_mclusts, nmbclusters); 160 161 printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE + 162 mbstat->m_mclusts * MCLBYTES) / 1024); 163 printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail); 164 printf("%lu requests for sfbufs delayed\n", mbstat->sf_allocwait); 165 printf("%lu requests for I/O initiated by sendfile\n", 166 mbstat->sf_iocnt); 167 printf("%lu calls to protocol drain routines\n", mbstat->m_drain); 168 169 err: 170 if (mbtypes != NULL) 171 free(mbtypes); 172 if (seen != NULL) 173 free(seen); 174 if (mbstat != NULL) 175 free(mbstat); 176 } 177 178 /* 179 * If running on a live kernel, directly query the zone allocator for stats 180 * from the four mbuf-related zones/types. 181 */ 182 static void 183 mbpr_sysctl(void) 184 { 185 struct memory_type_list *mtlp; 186 struct memory_type *mtp; 187 u_int64_t mbuf_count, mbuf_bytes, mbuf_free, mbuf_failures, mbuf_size; 188 u_int64_t cluster_count, cluster_bytes, cluster_limit, cluster_free; 189 u_int64_t cluster_failures, cluster_size; 190 u_int64_t packet_count, packet_bytes, packet_free, packet_failures; 191 u_int64_t tag_count, tag_bytes; 192 u_int64_t bytes_inuse, bytes_incache, bytes_total; 193 int nsfbufs, nsfbufspeak, nsfbufsused; 194 struct mbstat mbstat; 195 size_t mlen; 196 197 mtlp = memstat_mtl_alloc(); 198 if (mtlp == NULL) { 199 warn("memstat_mtl_alloc"); 200 return; 201 } 202 203 /* 204 * Use memstat_sysctl_all() because some mbuf-related memory is in 205 * uma(9), and some malloc(9). 206 */ 207 if (memstat_sysctl_all(mtlp, 0) < 0) { 208 warnx("memstat_sysctl_all: %s", 209 memstat_strerror(memstat_mtl_geterror(mtlp))); 210 goto out; 211 } 212 213 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME); 214 if (mtp == NULL) { 215 warnx("memstat_mtl_find: zone %s not found", MBUF_MEM_NAME); 216 goto out; 217 } 218 mbuf_count = memstat_get_count(mtp); 219 mbuf_bytes = memstat_get_bytes(mtp); 220 mbuf_free = memstat_get_free(mtp); 221 mbuf_failures = memstat_get_failures(mtp); 222 mbuf_size = memstat_get_size(mtp); 223 224 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_PACKET_MEM_NAME); 225 if (mtp == NULL) { 226 warnx("memstat_mtl_find: zone %s not found", 227 MBUF_PACKET_MEM_NAME); 228 goto out; 229 } 230 packet_count = memstat_get_count(mtp); 231 packet_bytes = memstat_get_bytes(mtp); 232 packet_free = memstat_get_free(mtp); 233 packet_failures = memstat_get_failures(mtp); 234 235 mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_CLUSTER_MEM_NAME); 236 if (mtp == NULL) { 237 warnx("memstat_mtl_find: zone %s not found", 238 MBUF_CLUSTER_MEM_NAME); 239 goto out; 240 } 241 cluster_count = memstat_get_count(mtp); 242 cluster_bytes = memstat_get_bytes(mtp); 243 cluster_limit = memstat_get_countlimit(mtp); 244 cluster_free = memstat_get_free(mtp); 245 cluster_failures = memstat_get_failures(mtp); 246 cluster_size = memstat_get_size(mtp); 247 248 mtp = memstat_mtl_find(mtlp, ALLOCATOR_MALLOC, MBUF_TAG_MEM_NAME); 249 if (mtp == NULL) { 250 warnx("memstat_mtl_find: malloc type %s not found", 251 MBUF_TAG_MEM_NAME); 252 goto out; 253 } 254 tag_count = memstat_get_count(mtp); 255 tag_bytes = memstat_get_bytes(mtp); 256 257 printf("%llu/%llu/%llu mbufs in use (current/cache/total)\n", 258 mbuf_count + packet_count, mbuf_free + packet_free, 259 mbuf_count + packet_count + mbuf_free + packet_free); 260 261 printf("%llu/%llu/%llu/%llu mbuf clusters in use " 262 "(current/cache/total/max)\n", 263 cluster_count - packet_free, cluster_free + packet_free, 264 cluster_count + cluster_free, cluster_limit); 265 266 #if 0 267 printf("%llu mbuf tags in use\n", tag_count); 268 #endif 269 270 mlen = sizeof(nsfbufs); 271 if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && 272 !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, 273 0) && 274 !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, 275 0)) { 276 printf("%d/%d/%d sfbufs in use (current/peak/max)\n", 277 nsfbufsused, nsfbufspeak, nsfbufs); 278 } 279 280 /*- 281 * Calculate in-use bytes as: 282 * - straight mbuf memory 283 * - mbuf memory in packets 284 * - the clusters attached to packets 285 * - and the rest of the non-packet-attached clusters. 286 * - m_tag memory 287 * This avoids counting the clusters attached to packets in the cache. 288 * This currently excludes sf_buf space. 289 */ 290 bytes_inuse = 291 mbuf_bytes + /* straight mbuf memory */ 292 packet_bytes + /* mbufs in packets */ 293 (packet_count * cluster_size) + /* clusters in packets */ 294 /* other clusters */ 295 ((cluster_count - packet_count - packet_free) * cluster_size) + 296 tag_bytes; 297 298 /* 299 * Calculate in-cache bytes as: 300 * - cached straught mbufs 301 * - cached packet mbufs 302 * - cached packet clusters 303 * - cached straight clusters 304 * This currently excludes sf_buf space. 305 */ 306 bytes_incache = 307 (mbuf_free * mbuf_size) + /* straight free mbufs */ 308 (packet_free * mbuf_size) + /* mbufs in free packets */ 309 (packet_free * cluster_size) + /* clusters in free packets */ 310 (cluster_free * cluster_size); /* free clusters */ 311 312 /* 313 * Total is bytes in use + bytes in cache. This doesn't take into 314 * account various other misc data structures, overhead, etc, but 315 * gives the user something useful despite that. 316 */ 317 bytes_total = bytes_inuse + bytes_incache; 318 319 printf("%lluK/%lluK/%lluK bytes allocated to network " 320 "(current/cache/total)\n", bytes_inuse / 1024, 321 bytes_incache / 1024, bytes_total / 1024); 322 323 #if 0 324 printf("%llu/%llu/%llu requests for mbufs denied (mbufs/clusters/" 325 "mbuf+clusters)\n", mbuf_failures, cluster_failures, 326 packet_failures); 327 #endif 328 329 mlen = sizeof(mbstat); 330 if (!sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) { 331 printf("%lu requests for sfbufs denied\n", 332 mbstat.sf_allocfail); 333 printf("%lu requests for sfbufs delayed\n", 334 mbstat.sf_allocwait); 335 printf("%lu requests for I/O initiated by sendfile\n", 336 mbstat.sf_iocnt); 337 printf("%lu calls to protocol drain routines\n", 338 mbstat.m_drain); 339 } 340 341 out: 342 memstat_mtl_free(mtlp); 343 } 344 345 /* 346 * Print mbuf statistics. 347 */ 348 void 349 mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, 350 u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, 351 u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) 352 { 353 354 if (mbaddr != 0) 355 mbpr_kmem(mbaddr, nmbcaddr, nmbufaddr, mbhiaddr, clhiaddr, 356 mbloaddr, clloaddr, pgsaddr, mbpaddr); 357 else 358 mbpr_sysctl(); 359 } 360