mbufs.c revision 1.19
1/* $OpenBSD: mbufs.c,v 1.19 2008/12/17 08:21:43 canacar Exp $ */ 2/* 3 * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17#include <sys/param.h> 18#include <sys/types.h> 19#include <sys/socket.h> 20#include <sys/sysctl.h> 21#include <sys/mbuf.h> 22#include <net/if.h> 23 24#include <err.h> 25#include <errno.h> 26#include <ifaddrs.h> 27#include <stdlib.h> 28#include <string.h> 29 30#include "systat.h" 31 32 33/* pool info for mcl* pools */ 34struct mclpool_info { 35 char title[16]; 36 int pool_offset; 37 int size; 38} mclpools[MCLPOOLS]; 39 40int mclpool_count = 0; 41int mbpool_index = -1; 42struct pool mbpool; 43 44/* interfaces */ 45static int num_ifs; 46struct if_info { 47 char name[16]; 48 struct if_data data; 49} *interfaces = NULL; 50 51void print_mb(void); 52int read_mb(void); 53int select_mb(void); 54static void 55showmbuf(struct if_info *, int); 56 57 58/* Define fields */ 59field_def fields_mbuf[] = { 60 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 61 {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 62 {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 63 {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 68}; 69 70 71#define FIELD_ADDR(x) (&fields_mbuf[x]) 72 73#define FLD_MB_IFACE FIELD_ADDR(0) 74#define FLD_MB_RXDELAY FIELD_ADDR(1) 75#define FLD_MB_TXDELAY FIELD_ADDR(2) 76#define FLD_MB_LLOCKS FIELD_ADDR(3) 77#define FLD_MB_MSIZE FIELD_ADDR(4) 78#define FLD_MB_MALIVE FIELD_ADDR(5) 79#define FLD_MB_MLWM FIELD_ADDR(6) 80#define FLD_MB_MHWM FIELD_ADDR(7) 81 82 83/* Define views */ 84field_def *view_mbuf[] = { 85 FLD_MB_IFACE, 86#if NOTYET 87 FLD_MB_RXDELAY, FLD_MB_TXDELAY, 88#endif 89 FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM, 90 NULL 91}; 92 93/* Define view managers */ 94 95struct view_manager mbuf_mgr = { 96 "Mbufs", select_mb, read_mb, NULL, print_header, 97 print_mb, keyboard_callback, NULL, NULL 98}; 99 100field_view views_mb[] = { 101 {view_mbuf, "mbufs", '4', &mbuf_mgr}, 102 {NULL, NULL, 0, NULL} 103}; 104 105 106int 107initmembufs(void) 108{ 109 field_view *v; 110 int i, mib[4], npools; 111 struct pool pool; 112 char pname[32]; 113 size_t size; 114 115 /* go through all pools to identify mbuf and cluster pools */ 116 bzero(mclpools, sizeof(mclpools)); 117 118 mib[0] = CTL_KERN; 119 mib[1] = KERN_POOL; 120 mib[2] = KERN_POOL_NPOOLS; 121 size = sizeof(npools); 122 123 if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) { 124 err(1, "sysctl(KERN_POOL_NPOOLS)"); 125 /* NOTREACHED */ 126 } 127 128 for (i = 1; i <= npools; i++) { 129 mib[0] = CTL_KERN; 130 mib[1] = KERN_POOL; 131 mib[2] = KERN_POOL_NAME; 132 mib[3] = i; 133 size = sizeof(pname); 134 if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) { 135 err(1, "sysctl(KERN_POOL_POOLNAME, %d)", i); 136 /* NOTREACHED */ 137 } 138 139 if (strcmp(pname, "mbpl") == 0) { 140 mbpool_index = i; 141 continue; 142 } 143 144 if (strncmp(pname, "mcl", 3) != 0) 145 continue; 146 147 if (mclpool_count == MCLPOOLS) { 148 warnx("mbufs: Too many mcl* pools", i); 149 break; 150 } 151 152 mib[2] = KERN_POOL_POOL; 153 size = sizeof(struct pool); 154 155 if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { 156 err(1, "sysctl(KERN_POOL_POOL, %d)", i); 157 /* NOTREACHED */ 158 } 159 160 mclpools[mclpool_count].size = pool.pr_size; 161 mclpools[mclpool_count].pool_offset = i; 162 snprintf(mclpools[mclpool_count].title, 163 sizeof(mclpools[0].title), "%dk", 164 pool.pr_size / 1024); 165 166 mclpool_count++; 167 } 168 169 if (mclpool_count != MCLPOOLS) 170 warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS); 171 172 /* add view to the engine */ 173 for (v = views_mb; v->name != NULL; v++) 174 add_view(v); 175 176 177 /* finally read it once */ 178 read_mb(); 179 180 return(1); 181} 182 183int 184select_mb(void) 185{ 186 num_disp = 0; 187 return (0); 188} 189 190int 191read_mb(void) 192{ 193 struct pool pool; 194 struct ifaddrs *ifap, *ifa; 195 struct if_info *ifi; 196 int mib[4]; 197 int i, p, nif, ret = 1; 198 size_t size; 199 200 num_disp = 0; 201 if (getifaddrs(&ifap)) { 202 error("getifaddrs: %s", strerror(errno)); 203 return (1); 204 } 205 206 nif = 1; 207 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) 208 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK) 209 nif++; 210 211 if (interfaces == NULL || num_ifs < nif) { 212 size_t len = sizeof(*ifi) * nif; 213 if (nif > SIZE_MAX / sizeof(*ifi)) { 214 error("overflow allocting %u interfaces", nif); 215 goto exit; 216 } 217 218 ifi = realloc(interfaces, len); 219 if (ifi == NULL) { 220 error("realloc: out of memory allocating %lld bytes", 221 (long long) len); 222 goto exit; 223 } 224 225 interfaces = ifi; 226 num_ifs = nif; 227 } 228 229 /* Fill in the "real" interfaces */ 230 ifi = interfaces + 1; 231 232 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 233 if (ifa->ifa_addr == NULL || 234 ifa->ifa_addr->sa_family != AF_LINK) 235 continue; 236 237 strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name)); 238 239 if (ifa->ifa_data) 240 memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data)); 241 else 242 bzero(&ifi->data, sizeof(ifi->data)); 243 ifi++; 244 } 245 246 /* Fill in the "System" entry from pools */ 247 bzero(interfaces, sizeof(interfaces[0])); 248 strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name)); 249 250 mib[0] = CTL_KERN; 251 mib[1] = KERN_POOL; 252 mib[2] = KERN_POOL_POOL; 253 mib[3] = mbpool_index; 254 size = sizeof(struct pool); 255 256 if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) { 257 error("sysctl(KERN_POOL_POOL, %d)", i); 258 goto exit; 259 } 260 261 for (i = 0; i < mclpool_count; i++) { 262 struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i]; 263 264 mib[3] = mclpools[i].pool_offset; 265 size = sizeof(struct pool); 266 267 if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { 268 error("sysctl(KERN_POOL_POOL, %d)", mib[3]); 269 continue; 270 } 271 272 mp->mcl_size = pool.pr_size; 273 mp->mcl_alive = pool.pr_nget - pool.pr_nput; 274 mp->mcl_hwm = pool.pr_hiwat; 275 } 276 277 num_disp = 1; 278 ret = 0; 279 280 for (i = 0; i < num_ifs; i++) { 281 struct if_info *ifi = &interfaces[i]; 282 int pnd = num_disp; 283 for (p = 0; p < mclpool_count; p++) { 284 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 285 if (mp->mcl_size != (ushort)mclpools[p].size) 286 break; 287 if (mp->mcl_alive == 0) 288 continue; 289 num_disp++; 290 } 291 if (i && pnd == num_disp) 292 num_disp++; 293 } 294 295 exit: 296 freeifaddrs(ifap); 297 return (ret); 298} 299 300void 301print_mb(void) 302{ 303 int i, p, n, count = 0; 304 305 showmbuf(interfaces, -1); 306 307 for (n = i = 0; i < num_ifs; i++) { 308 struct if_info *ifi = &interfaces[i]; 309 int pcnt = count; 310 if (maxprint > 0 && count >= maxprint) 311 return; 312 313 for (p = 0; p < mclpool_count; p++) { 314 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 315 if (mp->mcl_size != (ushort)mclpools[p].size) 316 break; 317 if (mp->mcl_alive == 0) 318 continue; 319 if (n++ >= dispstart) { 320 showmbuf(ifi, p); 321 count++; 322 } 323 } 324 325 if (i && pcnt == count) { 326 /* only print the first line */ 327 if (n++ >= dispstart) { 328 showmbuf(ifi, -1); 329 count++; 330 } 331 } 332 333 334 } 335} 336 337 338static void 339showmbuf(struct if_info *ifi, int p) 340{ 341 int i; 342 343 344 345 if (p == -1 || (p == 0 && ifi != interfaces)) { 346 print_fld_str(FLD_MB_IFACE, ifi->name); 347 } 348 349 if (p == -1 && ifi == interfaces) { 350 print_fld_size(FLD_MB_MSIZE, mbpool.pr_size); 351 print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput); 352 print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat); 353 } 354 355 356 357#if NOTYET 358 print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay); 359 print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay); 360 print_fld_size(FLD_MB_LLOCKS, ifi->data.ifi_txdelay); 361#endif 362 363 if (p >= 0 && p < mclpool_count) { 364 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 365 366 print_fld_str(FLD_MB_MSIZE, mclpools[p].title); 367 print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive); 368 if (mp->mcl_lwm) 369 print_fld_size(FLD_MB_MLWM, mp->mcl_lwm); 370 if (mp->mcl_hwm) 371 print_fld_size(FLD_MB_MHWM, mp->mcl_hwm); 372 } 373 374 end_line(); 375} 376 377 378