]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/mbuf.c
network_cmds-306.tar.gz
[apple/network_cmds.git] / netstat.tproj / mbuf.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*
25 * Copyright (c) 1983, 1988, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57
58 #include <sys/param.h>
59 #include <sys/socket.h>
60 #include <sys/mbuf.h>
61 #include <sys/sysctl.h>
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <errno.h>
66 #include "netstat.h"
67 #include <netat/sysglue.h> /* To get Appletalk message/mbuf types */
68
69 #define YES 1
70 typedef int bool;
71
72 struct mbstat mbstat;
73
74 static struct mbtypes {
75 int mt_type;
76 char *mt_name;
77 } mbtypes[] = {
78 { MT_DATA, "data" },
79 { MT_OOBDATA, "oob data" },
80 { MT_CONTROL, "ancillary data" },
81 { MT_HEADER, "packet headers" },
82 { MT_SOCKET, "socket structures" }, /* XXX */
83 { MT_PCB, "protocol control blocks" }, /* XXX */
84 { MT_RTABLE, "routing table entries" }, /* XXX */
85 { MT_HTABLE, "IMP host table entries" }, /* XXX */
86 { MT_ATABLE, "address resolution tables" },
87 { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
88 { MT_SONAME, "socket names and addresses" },
89 { MT_SOOPTS, "socket options" },
90 { MT_RIGHTS, "access rights" },
91 { MT_IFADDR, "interface addresses" }, /* XXX */
92 { MT_TAG, "packet tags" }, /* XXX */
93 { MSG_DATA, "Appletalk data blocks"},
94 { MSG_PROTO, "Appletalk internal msgs"},
95 { MSG_IOCTL, "Appletalk ioctl requests"},
96 { MSG_ERROR, "Appletalk error indicators"},
97 { MSG_HANGUP, "Appletalk termination requests"},
98 { MSG_IOCACK, "Appletalk ioctl acks"},
99 { MSG_IOCNAK, "Appletalk ioctl failure indicators"},
100 { MSG_CTL, "Appletalk control msgs"},
101 { 0, 0 }
102 };
103
104 int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
105 bool seen[256]; /* "have we seen this type yet?" */
106
107 mb_stat_t *mb_stat;
108 unsigned int njcl, njclbytes;
109
110 #define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
111 #define KERN_IPC_NJCL "kern.ipc.njcl"
112 #define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
113
114 #define MB_STAT_HDR1 "\
115 class buf active ctotal total cache cached uncached memory\n\
116 name size bufs bufs bufs state bufs bufs usage\n\
117 ---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
118 "
119
120 #define MB_STAT_HDR2 "\n\
121 class waiter notify purge wretry nwretry failure\n\
122 name count count count count count count\n\
123 ---------- -------- -------- -------- -------- -------- --------\n\
124 "
125
126 static const char *mbpr_state(int);
127 static const char *mbpr_mem(u_int32_t);
128 static int mbpr_getdata(void);
129
130 /*
131 * Print mbuf statistics.
132 */
133 void
134 mbpr(void)
135 {
136 unsigned long totmem = 0, totfree = 0, totmbufs, totused;
137 double totpct;
138 u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
139 u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
140 u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
141 int i;
142 struct mbtypes *mp;
143 mb_class_stat_t *cp;
144
145 if (mbpr_getdata() != 0)
146 return;
147
148 m_msize = mbstat.m_msize;
149 cp = &mb_stat->mbs_class[0];
150 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
151 if (cp->mbcl_size == m_msize) {
152 m_mbufs = cp->mbcl_active;
153 } else if (cp->mbcl_size == mbstat.m_mclbytes) {
154 m_clfree = cp->mbcl_total - cp->mbcl_active;
155 } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
156 m_bigclfree = cp->mbcl_total - cp->mbcl_active;
157 } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
158 m_16kclfree = cp->mbcl_total - cp->mbcl_active;
159 m_16kclusters = cp->mbcl_total;
160 } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
161 m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
162 } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
163 m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
164 } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
165 m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
166 }
167 }
168
169 /* adjust free counts to include composite caches */
170 m_clfree += m_mbufclfree;
171 m_bigclfree += m_mbufbigclfree;
172 m_16kclfree += m_mbuf16kclfree;
173
174 cp = &mb_stat->mbs_class[0];
175 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
176 u_int32_t mem;
177
178 mem = cp->mbcl_ctotal * cp->mbcl_size;
179 totmem += mem;
180 totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
181 cp->mbcl_size;
182 if (mflag > 1) {
183 if (i == 0)
184 printf(MB_STAT_HDR1);
185
186 if (njcl == 0 &&
187 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
188 continue;
189
190 printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
191 cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
192 cp->mbcl_ctotal, cp->mbcl_total,
193 mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
194 cp->mbcl_infree, mbpr_mem(mem));
195 }
196 }
197
198 cp = &mb_stat->mbs_class[0];
199 for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
200 if (mflag > 2) {
201 if (i == 0)
202 printf(MB_STAT_HDR2);
203
204 if (njcl == 0 &&
205 cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
206 continue;
207
208 printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
209 cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
210 cp->mbcl_notified, cp->mbcl_purge_cnt,
211 cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
212 cp->mbcl_fail_cnt);
213 }
214 }
215
216 if (mflag > 1)
217 printf("\n");
218
219 totmbufs = 0;
220 for (mp = mbtypes; mp->mt_name; mp++)
221 totmbufs += mbstat.m_mtypes[mp->mt_type];
222 /*
223 * These stats are not updated atomically in the kernel;
224 * adjust the total as neeeded.
225 */
226 if (totmbufs > m_mbufs)
227 totmbufs = m_mbufs;
228 printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
229 for (mp = mbtypes; mp->mt_name; mp++)
230 if (mbstat.m_mtypes[mp->mt_type]) {
231 seen[mp->mt_type] = YES;
232 printf("\t%u mbufs allocated to %s\n",
233 mbstat.m_mtypes[mp->mt_type], mp->mt_name);
234 }
235 seen[MT_FREE] = YES;
236 for (i = 0; i < nmbtypes; i++)
237 if (!seen[i] && mbstat.m_mtypes[i]) {
238 printf("\t%u mbufs allocated to <mbuf type %d>\n",
239 mbstat.m_mtypes[i], i);
240 }
241 if ((m_mbufs - totmbufs) > 0)
242 printf("\t%lu mbufs allocated to caches\n",
243 m_mbufs - totmbufs);
244 printf("%u/%u mbuf 2KB clusters in use\n",
245 (unsigned int)(mbstat.m_clusters - m_clfree),
246 (unsigned int)mbstat.m_clusters);
247 printf("%u/%u mbuf 4KB clusters in use\n",
248 (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
249 (unsigned int)mbstat.m_bigclusters);
250 if (njcl > 0) {
251 printf("%u/%u mbuf %uKB clusters in use\n",
252 m_16kclusters - m_16kclfree, m_16kclusters,
253 njclbytes/1024);
254 }
255 totused = totmem - totfree;
256 if (totmem == 0)
257 totpct = 0;
258 else if (totused < (ULONG_MAX/100))
259 totpct = (totused * 100)/(double)totmem;
260 else {
261 u_long totmem1 = totmem/100;
262 u_long totused1 = totused/100;
263 totpct = (totused1 * 100)/(double)totmem1;
264 }
265 printf("%lu KB allocated to network (%.1f%% in use)\n",
266 totmem / 1024, totpct);
267
268 printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
269 printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
270 printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
271
272 free(mb_stat);
273 }
274
275 static const char *
276 mbpr_state(int state)
277 {
278 char *msg = "?";
279
280 switch (state) {
281 case MCS_DISABLED:
282 msg = "dis";
283 break;
284
285 case MCS_ONLINE:
286 msg = "on";
287 break;
288
289 case MCS_PURGING:
290 msg = "purge";
291 break;
292
293 case MCS_OFFLINE:
294 msg = "off";
295 break;
296 }
297 return (msg);
298 }
299
300 static const char *
301 mbpr_mem(u_int32_t bytes)
302 {
303 static char buf[33];
304 double mem = bytes;
305
306 if (mem < 1024) {
307 (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
308 } else if ((mem /= 1024) < 1024) {
309 (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
310 } else {
311 mem /= 1024;
312 (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
313 }
314 return (buf);
315 }
316
317 static int
318 mbpr_getdata(void)
319 {
320 size_t len;
321 int error = -1;
322
323 if (nmbtypes != 256) {
324 (void) fprintf(stderr,
325 "netstat: unexpected change to mbstat; check source\n");
326 goto done;
327 }
328
329 len = sizeof(mbstat);
330 if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
331 goto done;
332
333 if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
334 (void) fprintf(stderr,
335 "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
336 goto done;
337 }
338
339 mb_stat = calloc(1, len);
340 if (mb_stat == NULL) {
341 (void) fprintf(stderr,
342 "Error allocating %lu bytes for sysctl data\n", len);
343 goto done;
344 }
345
346 if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
347 (void) fprintf(stderr,
348 "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
349 goto done;
350 }
351
352 if (mb_stat->mbs_cnt == 0) {
353 (void) fprintf(stderr,
354 "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
355 goto done;
356 }
357
358 len = sizeof (njcl);
359 (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
360 len = sizeof (njclbytes);
361 (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
362
363 error = 0;
364
365 done:
366 if (error != 0 && mb_stat != NULL)
367 free(mb_stat);
368
369 return (error);
370 }