1 /* $OpenBSD: mbufs.c,v 1.32 2011/03/02 06:48:17 jasper 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 <sys/pool.h> 23 #include <net/if.h> 24 25 #include <err.h> 26 #include <errno.h> 27 #include <ifaddrs.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "systat.h" 32 33 34 /* pool info for mcl* pools */ 35 struct mclpool_info { 36 char title[16]; 37 int pool_offset; 38 int size; 39 } mclpools[MCLPOOLS]; 40 41 int mclpool_count = 0; 42 int mbpool_index = -1; 43 struct pool mbpool; 44 u_int mcllivelocks, mcllivelocks_cur, mcllivelocks_diff; 45 46 /* interfaces */ 47 static int num_ifs; 48 struct if_info { 49 char name[16]; 50 struct if_data data; 51 } *interfaces = NULL; 52 53 void print_mb(void); 54 int read_mb(void); 55 int select_mb(void); 56 static void showmbuf(struct if_info *, int, int); 57 58 59 /* Define fields */ 60 field_def fields_mbuf[] = { 61 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 62 {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 63 {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 68 {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 69 {"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 70 }; 71 72 73 #define FLD_MB_IFACE FIELD_ADDR(fields_mbuf,0) 74 #define FLD_MB_RXDELAY FIELD_ADDR(fields_mbuf,1) 75 #define FLD_MB_TXDELAY FIELD_ADDR(fields_mbuf,2) 76 #define FLD_MB_LLOCKS FIELD_ADDR(fields_mbuf,3) 77 #define FLD_MB_MSIZE FIELD_ADDR(fields_mbuf,4) 78 #define FLD_MB_MALIVE FIELD_ADDR(fields_mbuf,5) 79 #define FLD_MB_MLWM FIELD_ADDR(fields_mbuf,6) 80 #define FLD_MB_MHWM FIELD_ADDR(fields_mbuf,7) 81 #define FLD_MB_MCWM FIELD_ADDR(fields_mbuf,8) 82 83 84 /* Define views */ 85 field_def *view_mbuf[] = { 86 FLD_MB_IFACE, 87 #if NOTYET 88 FLD_MB_RXDELAY, FLD_MB_TXDELAY, 89 #endif 90 FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM, 91 FLD_MB_MCWM, NULL 92 }; 93 94 /* Define view managers */ 95 96 struct view_manager mbuf_mgr = { 97 "Mbufs", select_mb, read_mb, NULL, print_header, 98 print_mb, keyboard_callback, NULL, NULL 99 }; 100 101 field_view views_mb[] = { 102 {view_mbuf, "mbufs", '4', &mbuf_mgr}, 103 {NULL, NULL, 0, NULL} 104 }; 105 106 107 int 108 initmembufs(void) 109 { 110 field_view *v; 111 int i, mib[4], npools; 112 struct pool pool; 113 char pname[32]; 114 size_t size; 115 116 /* go through all pools to identify mbuf and cluster pools */ 117 bzero(mclpools, sizeof(mclpools)); 118 119 mib[0] = CTL_KERN; 120 mib[1] = KERN_POOL; 121 mib[2] = KERN_POOL_NPOOLS; 122 size = sizeof(npools); 123 124 if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) { 125 err(1, "sysctl(KERN_POOL_NPOOLS)"); 126 /* NOTREACHED */ 127 } 128 129 for (i = 1; i <= npools; i++) { 130 mib[0] = CTL_KERN; 131 mib[1] = KERN_POOL; 132 mib[2] = KERN_POOL_NAME; 133 mib[3] = i; 134 size = sizeof(pname); 135 if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) { 136 continue; 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"); 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 183 int 184 select_mb(void) 185 { 186 num_disp = 0; 187 return (0); 188 } 189 190 int 191 read_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 mib[0] = CTL_KERN; 201 mib[1] = KERN_NETLIVELOCKS; 202 size = sizeof(mcllivelocks_cur); 203 if (sysctl(mib, 2, &mcllivelocks_cur, &size, NULL, 0) < 0 && 204 errno != EOPNOTSUPP) { 205 error("sysctl(KERN_NETLIVELOCKS)"); 206 goto exit; 207 } 208 mcllivelocks_diff = mcllivelocks_cur - mcllivelocks; 209 mcllivelocks = mcllivelocks_cur; 210 211 num_disp = 0; 212 if (getifaddrs(&ifap)) { 213 error("getifaddrs: %s", strerror(errno)); 214 return (1); 215 } 216 217 nif = 1; 218 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) 219 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK) 220 nif++; 221 222 if (interfaces == NULL || num_ifs < nif) { 223 size_t len = sizeof(*ifi) * nif; 224 if (nif > SIZE_MAX / sizeof(*ifi)) { 225 error("overflow allocting %u interfaces", nif); 226 goto exit; 227 } 228 229 ifi = realloc(interfaces, len); 230 if (ifi == NULL) { 231 error("realloc: out of memory allocating %lld bytes", 232 (long long) len); 233 goto exit; 234 } 235 236 interfaces = ifi; 237 num_ifs = nif; 238 } 239 240 /* Fill in the "real" interfaces */ 241 ifi = interfaces + 1; 242 243 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 244 if (ifa->ifa_addr == NULL || 245 ifa->ifa_addr->sa_family != AF_LINK) 246 continue; 247 248 strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name)); 249 250 if (ifa->ifa_data) 251 memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data)); 252 else 253 bzero(&ifi->data, sizeof(ifi->data)); 254 ifi++; 255 } 256 257 /* Fill in the "System" entry from pools */ 258 bzero(interfaces, sizeof(interfaces[0])); 259 strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name)); 260 261 mib[0] = CTL_KERN; 262 mib[1] = KERN_POOL; 263 mib[2] = KERN_POOL_POOL; 264 mib[3] = mbpool_index; 265 size = sizeof(struct pool); 266 267 if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) { 268 error("sysctl(KERN_POOL_POOL, %d)", mib[3]); 269 goto exit; 270 } 271 272 for (i = 0; i < mclpool_count; i++) { 273 struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i]; 274 275 mib[3] = mclpools[i].pool_offset; 276 size = sizeof(struct pool); 277 278 if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { 279 error("sysctl(KERN_POOL_POOL, %d)", mib[3]); 280 continue; 281 } 282 283 mp->mcl_alive = pool.pr_nget - pool.pr_nput; 284 mp->mcl_hwm = pool.pr_hiwat; 285 } 286 287 num_disp = 1; 288 ret = 0; 289 290 for (i = 0; i < num_ifs; i++) { 291 struct if_info *ifi = &interfaces[i]; 292 int pnd = num_disp; 293 for (p = 0; p < mclpool_count; p++) { 294 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 295 if (mp->mcl_alive == 0) 296 continue; 297 num_disp++; 298 } 299 if (i && pnd == num_disp) 300 num_disp++; 301 } 302 303 exit: 304 freeifaddrs(ifap); 305 return (ret); 306 } 307 308 void 309 print_mb(void) 310 { 311 int i, p, n, count = 0; 312 313 showmbuf(interfaces, -1, 1); 314 315 for (n = i = 0; i < num_ifs; i++) { 316 struct if_info *ifi = &interfaces[i]; 317 int pcnt = count; 318 int showif = i; 319 320 if (maxprint > 0 && count >= maxprint) 321 return; 322 323 for (p = 0; p < mclpool_count; p++) { 324 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 325 if (mp->mcl_alive == 0) 326 continue; 327 if (n++ >= dispstart) { 328 showmbuf(ifi, p, showif); 329 showif = 0; 330 count++; 331 } 332 } 333 334 if (i && pcnt == count) { 335 /* only print the first line */ 336 if (n++ >= dispstart) { 337 showmbuf(ifi, -1, 1); 338 count++; 339 } 340 } 341 342 343 } 344 } 345 346 347 static void 348 showmbuf(struct if_info *ifi, int p, int showif) 349 { 350 if (showif) 351 print_fld_str(FLD_MB_IFACE, ifi->name); 352 353 if (p == -1 && ifi == interfaces) { 354 print_fld_uint(FLD_MB_LLOCKS, mcllivelocks_diff); 355 print_fld_size(FLD_MB_MSIZE, mbpool.pr_size); 356 print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput); 357 print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat); 358 } 359 360 #if NOTYET 361 print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay); 362 print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay); 363 #endif 364 365 if (p >= 0 && p < mclpool_count) { 366 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 367 368 print_fld_str(FLD_MB_MSIZE, mclpools[p].title); 369 print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive); 370 if (mp->mcl_lwm) 371 print_fld_size(FLD_MB_MLWM, mp->mcl_lwm); 372 if (mp->mcl_hwm) 373 print_fld_size(FLD_MB_MHWM, mp->mcl_hwm); 374 if (mp->mcl_cwm) 375 print_fld_size(FLD_MB_MCWM, mp->mcl_cwm); 376 } 377 378 end_line(); 379 } 380