1 /* $OpenBSD: mbufs.c,v 1.24 2009/04/20 20:30:41 chl 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 */ 34 struct mclpool_info { 35 char title[16]; 36 int pool_offset; 37 int size; 38 } mclpools[MCLPOOLS]; 39 40 int mclpool_count = 0; 41 int mbpool_index = -1; 42 struct pool mbpool; 43 44 /* interfaces */ 45 static int num_ifs; 46 struct if_info { 47 char name[16]; 48 struct if_data data; 49 } *interfaces = NULL; 50 51 void print_mb(void); 52 int read_mb(void); 53 int select_mb(void); 54 static void showmbuf(struct if_info *, int, int); 55 56 57 /* Define fields */ 58 field_def fields_mbuf[] = { 59 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 60 {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 61 {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 62 {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 63 {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 {"CWM", 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 #define FLD_MB_MCWM FIELD_ADDR(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 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_alive = pool.pr_nget - pool.pr_nput; 273 mp->mcl_hwm = pool.pr_hiwat; 274 } 275 276 num_disp = 1; 277 ret = 0; 278 279 for (i = 0; i < num_ifs; i++) { 280 struct if_info *ifi = &interfaces[i]; 281 int pnd = num_disp; 282 for (p = 0; p < mclpool_count; p++) { 283 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 284 if (mp->mcl_alive == 0) 285 continue; 286 num_disp++; 287 } 288 if (i && pnd == num_disp) 289 num_disp++; 290 } 291 292 exit: 293 freeifaddrs(ifap); 294 return (ret); 295 } 296 297 void 298 print_mb(void) 299 { 300 int i, p, n, count = 0; 301 302 showmbuf(interfaces, -1, 1); 303 304 for (n = i = 0; i < num_ifs; i++) { 305 struct if_info *ifi = &interfaces[i]; 306 int pcnt = count; 307 int showif = i; 308 309 if (maxprint > 0 && count >= maxprint) 310 return; 311 312 for (p = 0; p < mclpool_count; p++) { 313 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 314 if (mp->mcl_alive == 0) 315 continue; 316 if (n++ >= dispstart) { 317 showmbuf(ifi, p, showif); 318 showif = 0; 319 count++; 320 } 321 } 322 323 if (i && pcnt == count) { 324 /* only print the first line */ 325 if (n++ >= dispstart) { 326 showmbuf(ifi, -1, 1); 327 count++; 328 } 329 } 330 331 332 } 333 } 334 335 336 static void 337 showmbuf(struct if_info *ifi, int p, int showif) 338 { 339 if (showif) 340 print_fld_str(FLD_MB_IFACE, ifi->name); 341 342 if (p == -1 && ifi == interfaces) { 343 print_fld_size(FLD_MB_MSIZE, mbpool.pr_size); 344 print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput); 345 print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat); 346 } 347 348 #if NOTYET 349 print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay); 350 print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay); 351 #endif 352 if (ifi->data.ifi_livelocks) 353 print_fld_size(FLD_MB_LLOCKS, ifi->data.ifi_livelocks); 354 355 if (p >= 0 && p < mclpool_count) { 356 struct mclpool *mp = &ifi->data.ifi_mclpool[p]; 357 358 print_fld_str(FLD_MB_MSIZE, mclpools[p].title); 359 print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive); 360 if (mp->mcl_lwm) 361 print_fld_size(FLD_MB_MLWM, mp->mcl_lwm); 362 if (mp->mcl_hwm) 363 print_fld_size(FLD_MB_MHWM, mp->mcl_hwm); 364 if (mp->mcl_cwm) 365 print_fld_size(FLD_MB_MCWM, mp->mcl_cwm); 366 } 367 368 end_line(); 369 } 370