1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 #include <sys/mbuf.h> 44 #include <sys/protosw.h> 45 #include <sys/socket.h> 46 #include <sys/sysctl.h> 47 48 #include <err.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include "netstat.h" 53 54 #define YES 1 55 typedef int bool; 56 57 static struct mbtypenames { 58 short mt_type; 59 const char *mt_name; 60 } mbtypenames[] = { 61 { MT_DATA, "data" }, 62 { MT_OOBDATA, "oob data" }, 63 { MT_CONTROL, "ancillary data" }, 64 { MT_HEADER, "packet headers" }, 65 #ifdef MT_SOCKET 66 { MT_SOCKET, "socket structures" }, /* XXX */ 67 #endif 68 #ifdef MT_PCB 69 { MT_PCB, "protocol control blocks" }, /* XXX */ 70 #endif 71 #ifdef MT_RTABLE 72 { MT_RTABLE, "routing table entries" }, /* XXX */ 73 #endif 74 #ifdef MT_HTABLE 75 { MT_HTABLE, "IMP host table entries" }, /* XXX */ 76 #endif 77 #ifdef MT_ATABLE 78 { MT_ATABLE, "address resolution tables" }, 79 #endif 80 { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ 81 { MT_SONAME, "socket names and addresses" }, 82 #ifdef MT_SOOPTS 83 { MT_SOOPTS, "socket options" }, 84 #endif 85 #ifdef MT_RIGHTS 86 { MT_RIGHTS, "access rights" }, 87 #endif 88 #ifdef MT_IFADDR 89 { MT_IFADDR, "interface addresses" }, /* XXX */ 90 #endif 91 { 0, 0 } 92 }; 93 94 /* 95 * Print mbuf statistics. 96 */ 97 void 98 mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr, 99 u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr, 100 u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr) 101 { 102 int i, j, nmbufs, nmbclusters, page_size, num_objs; 103 int nsfbufs, nsfbufspeak, nsfbufsused; 104 u_int mbuf_hiwm, clust_hiwm, mbuf_lowm, clust_lowm; 105 u_long totspace[2], totused[2]; 106 u_long gentotnum, gentotfree, totnum, totfree; 107 u_long totmem, totmemalloced, totmemused; 108 short nmbtypes; 109 size_t mlen; 110 long *mbtypes = NULL; 111 struct mbstat *mbstat = NULL; 112 struct mbpstat **mbpstat = NULL; 113 struct mbtypenames *mp; 114 bool *seen = NULL; 115 116 mlen = sizeof *mbstat; 117 if ((mbstat = malloc(mlen)) == NULL) { 118 warn("malloc: cannot allocate memory for mbstat"); 119 goto err; 120 } 121 122 /* 123 * XXX: Unfortunately, for the time being, we have to fetch 124 * the total length of the per-CPU stats area via sysctl 125 * (regardless of whether we're looking at a core or not. 126 */ 127 if (sysctlbyname("kern.ipc.mb_statpcpu", NULL, &mlen, NULL, 0) < 0) { 128 warn("sysctl: retrieving mb_statpcpu len"); 129 goto err; 130 } 131 num_objs = (int)(mlen / sizeof(struct mbpstat)); 132 if ((mbpstat = calloc(num_objs, sizeof(struct mbpstat *))) == NULL) { 133 warn("calloc: cannot allocate memory for mbpstats pointers"); 134 goto err; 135 } 136 if ((mbpstat[0] = calloc(num_objs, sizeof(struct mbpstat))) == NULL) { 137 warn("calloc: cannot allocate memory for mbpstats"); 138 goto err; 139 } 140 141 if (mbaddr) { 142 if (kread(mbpaddr, (char *)mbpstat[0], mlen)) 143 goto err; 144 if (kread(mbaddr, (char *)mbstat, sizeof mbstat)) 145 goto err; 146 if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int))) 147 goto err; 148 if (kread(nmbufaddr, (char *)&nmbufs, sizeof(int))) 149 goto err; 150 if (kread(mbhiaddr, (char *)&mbuf_hiwm, sizeof(u_int))) 151 goto err; 152 if (kread(clhiaddr, (char *)&clust_hiwm, sizeof(u_int))) 153 goto err; 154 if (kread(mbloaddr, (char *)&mbuf_lowm, sizeof(u_int))) 155 goto err; 156 if (kread(clloaddr, (char *)&clust_lowm, sizeof(u_int))) 157 goto err; 158 if (kread(pgsaddr, (char *)&page_size, sizeof(int))) 159 goto err; 160 } else { 161 if (sysctlbyname("kern.ipc.mb_statpcpu", mbpstat[0], &mlen, 162 NULL, 0) < 0) { 163 warn("sysctl: retrieving mb_statpcpu"); 164 goto err; 165 } 166 mlen = sizeof *mbstat; 167 if (sysctlbyname("kern.ipc.mbstat", mbstat, &mlen, NULL, 0) 168 < 0) { 169 warn("sysctl: retrieving mbstat"); 170 goto err; 171 } 172 mlen = sizeof(int); 173 if (sysctlbyname("kern.ipc.nmbclusters", &nmbclusters, &mlen, 174 NULL, 0) < 0) { 175 warn("sysctl: retrieving nmbclusters"); 176 goto err; 177 } 178 mlen = sizeof(int); 179 if (sysctlbyname("kern.ipc.nmbufs", &nmbufs, &mlen, NULL, 0) 180 < 0) { 181 warn("sysctl: retrieving nmbufs"); 182 goto err; 183 } 184 mlen = sizeof(u_int); 185 if (sysctlbyname("kern.ipc.mbuf_hiwm", &mbuf_hiwm, &mlen, 186 NULL, 0) < 0) { 187 warn("sysctl: retrieving mbuf_hiwm"); 188 goto err; 189 } 190 mlen = sizeof(u_int); 191 if (sysctlbyname("kern.ipc.clust_hiwm", &clust_hiwm, &mlen, 192 NULL, 0) < 0) { 193 warn("sysctl: retrieving clust_hiwm"); 194 goto err; 195 } 196 mlen = sizeof(u_int); 197 if (sysctlbyname("kern.ipc.mbuf_lowm", &mbuf_lowm, &mlen, 198 NULL, 0) < 0) { 199 warn("sysctl: retrieving mbuf_lowm"); 200 goto err; 201 } 202 mlen = sizeof(u_int); 203 if (sysctlbyname("kern.ipc.clust_lowm", &clust_lowm, &mlen, 204 NULL, 0) < 0) { 205 warn("sysctl: retrieving clust_lowm"); 206 goto err; 207 } 208 mlen = sizeof(int); 209 if (sysctlbyname("hw.pagesize", &page_size, &mlen, NULL, 0) 210 < 0) { 211 warn("sysctl: retrieving hw.pagesize"); 212 goto err; 213 } 214 } 215 216 nmbtypes = mbstat->m_numtypes; 217 if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) { 218 warn("calloc: cannot allocate memory for mbtypes seen flag"); 219 goto err; 220 } 221 if ((mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) { 222 warn("calloc: cannot allocate memory for mbtypes"); 223 goto err; 224 } 225 226 for (i = 0; i < num_objs; i++) 227 mbpstat[i] = mbpstat[0] + i; 228 229 #undef MSIZE 230 #define MSIZE (mbstat->m_msize) 231 #undef MCLBYTES 232 #define MCLBYTES (mbstat->m_mclbytes) 233 #define GENLST (num_objs - 1) 234 235 totnum = mbpstat[GENLST]->mb_mbbucks * mbstat->m_mbperbuck; 236 totfree = mbpstat[GENLST]->mb_mbfree; 237 for (j = 1; j < nmbtypes; j++) 238 mbtypes[j] += mbpstat[GENLST]->mb_mbtypes[j]; 239 totspace[0] = mbpstat[GENLST]->mb_mbbucks * mbstat->m_mbperbuck * MSIZE; 240 for (i = 0; i < (num_objs - 1); i++) { 241 if (mbpstat[i]->mb_active == 0) 242 continue; 243 totspace[0] += mbpstat[i]->mb_mbbucks*mbstat->m_mbperbuck*MSIZE; 244 totnum += mbpstat[i]->mb_mbbucks * mbstat->m_mbperbuck; 245 totfree += mbpstat[i]->mb_mbfree; 246 for (j = 1; j < nmbtypes; j++) 247 mbtypes[j] += mbpstat[i]->mb_mbtypes[j]; 248 } 249 totused[0] = totnum - totfree; 250 if (cflag) { 251 printf("mbuf usage:\n" 252 "\tTotal:\t\t%lu/%lu/%d (in use/in pool/max)\n", 253 totused[0], totnum, nmbufs); 254 gentotnum = mbpstat[GENLST]->mb_mbbucks * mbstat->m_mbperbuck; 255 gentotfree = mbpstat[GENLST]->mb_mbfree; 256 printf("\tGEN cache:\t%lu/%lu (in use/in pool)\n", 257 gentotnum - gentotfree, gentotnum); 258 } else { 259 /* XXX: peak is now wrong. */ 260 printf("%lu/%lu/%d mbufs in use (current/peak/max):\n", 261 totused[0], totnum, nmbufs); 262 } 263 264 for (i = 0; cflag && i < (num_objs - 1); i++) { 265 if (mbpstat[i]->mb_active == 0) 266 continue; 267 printf("\tCPU #%d cache:\t%lu/%lu (in use/in pool)\n", 268 i, 269 (mbpstat[i]->mb_mbbucks * mbstat->m_mbperbuck - 270 mbpstat[i]->mb_mbfree), 271 (mbpstat[i]->mb_mbbucks * mbstat->m_mbperbuck)); 272 } 273 if (cflag) { 274 printf("\tMbuf cache high watermark: %d\n", mbuf_hiwm); 275 #ifdef NOTYET 276 printf("\tMbuf cache low watermark: %d\n", mbuf_lowm); 277 #endif 278 } 279 for (mp = mbtypenames; mp->mt_name; mp++) { 280 if (mbtypes[mp->mt_type]) { 281 seen[mp->mt_type] = YES; 282 printf("\t %lu mbufs allocated to %s\n", 283 mbtypes[mp->mt_type], mp->mt_name); 284 } 285 } 286 for (i = 1; i < nmbtypes; i++) { 287 if (!seen[i] && mbtypes[i]) 288 printf("\t %lu mbufs allocated to <mbuf type: %d>\n", 289 mbtypes[i], i); 290 } 291 if (cflag) 292 printf("\t%.1f%% of mbuf map consumed\n", 293 totspace[0] * 100.0 / (nmbufs * MSIZE)); 294 295 totnum = mbpstat[GENLST]->mb_clbucks * mbstat->m_clperbuck; 296 totfree = mbpstat[GENLST]->mb_clfree; 297 totspace[1] = mbpstat[GENLST]->mb_clbucks*mbstat->m_clperbuck*MCLBYTES; 298 for (i = 0; i < (num_objs - 1); i++) { 299 if (mbpstat[i]->mb_active == 0) 300 continue; 301 totspace[1] += mbpstat[i]->mb_clbucks * mbstat->m_clperbuck 302 * MCLBYTES; 303 totnum += mbpstat[i]->mb_clbucks * mbstat->m_clperbuck; 304 totfree += mbpstat[i]->mb_clfree; 305 } 306 totused[1] = totnum - totfree; 307 if (cflag) { 308 printf("mbuf cluster usage:\n" 309 "\tTotal:\t\t%lu/%lu/%d (in use/in pool/max)\n", 310 totused[1], totnum, nmbclusters); 311 gentotnum = mbpstat[GENLST]->mb_clbucks * mbstat->m_clperbuck; 312 gentotfree = mbpstat[GENLST]->mb_clfree; 313 printf("\tGEN cache:\t%lu/%lu (in use/in pool)\n", 314 gentotnum - gentotfree, gentotnum); 315 } else { 316 /* XXX: peak is now wrong. */ 317 printf("%lu/%lu/%d mbuf clusters in use (current/peak/max)\n", 318 totused[1], totnum, nmbclusters); 319 } 320 for (i = 0; cflag && i < (num_objs - 1); i++) { 321 if (mbpstat[i]->mb_active == 0) 322 continue; 323 printf("\tCPU #%d cache:\t%lu/%lu (in use/in pool)\n", 324 i, 325 (mbpstat[i]->mb_clbucks * mbstat->m_clperbuck - 326 mbpstat[i]->mb_clfree), 327 (mbpstat[i]->mb_clbucks * mbstat->m_clperbuck)); 328 } 329 if (cflag) { 330 printf("\tCluster cache high watermark: %d\n", clust_hiwm); 331 #ifdef NOTYET 332 printf("\tCluster cache low watermark: %d\n", clust_lowm); 333 #endif 334 } 335 if (cflag) 336 printf("\t%.1f%% of cluster map consumed\n", 337 totspace[1] * 100.0 / (nmbclusters * MCLBYTES)); 338 mlen = sizeof(nsfbufs); 339 if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) && 340 !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL, 341 0) && 342 !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL, 343 0)) { 344 printf("%d/%d/%d sfbufs in use (current/peak/max)\n", 345 nsfbufsused, nsfbufspeak, nsfbufs); 346 } 347 totmem = nmbufs * MSIZE + nmbclusters * MCLBYTES; 348 totmemalloced = totspace[0] + totspace[1]; 349 totmemused = totused[0] * MSIZE + totused[1] * MCLBYTES; 350 printf( 351 "%lu KBytes allocated to network (%.1f%% in use, %.1f%% wired)\n", 352 totmem / 1024, totmemused * 100.0 / totmem, 353 totmemalloced * 100.0 / totmem); 354 printf("%lu requests for memory denied\n", mbstat->m_drops); 355 printf("%lu requests for memory delayed\n", mbstat->m_wait); 356 printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail); 357 printf("%lu requests for sfbufs delayed\n", mbstat->sf_allocwait); 358 printf("%lu requests for I/O initiated by sendfile\n", 359 mbstat->sf_iocnt); 360 printf("%lu calls to protocol drain routines\n", mbstat->m_drain); 361 362 err: 363 if (mbtypes != NULL) 364 free(mbtypes); 365 if (seen != NULL) 366 free(seen); 367 if (mbstat != NULL) 368 free(mbstat); 369 if (mbpstat != NULL) { 370 if (mbpstat[0] != NULL) 371 free(mbpstat[0]); 372 free(mbpstat); 373 } 374 } 375