1 /* $OpenBSD: mbufs.c,v 1.37 2014/11/06 12:50:55 dlg 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 #include <sys/sockio.h> 25 #include <sys/ioctl.h> 26 27 #include <err.h> 28 #include <errno.h> 29 #include <ifaddrs.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "systat.h" 34 35 /* pool info */ 36 int mbpool_index = -1; 37 int mclpools_index[MCLPOOLS]; 38 int mclpool_count = 0; 39 struct kinfo_pool mbpool; 40 u_int mcllivelocks, mcllivelocks_cur, mcllivelocks_diff; 41 42 /* interfaces */ 43 static int num_ifs = 0; 44 struct if_info { 45 char name[16]; 46 struct if_rxrinfo data; 47 } *interfaces = NULL; 48 49 static int sock; 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 /* Define fields */ 57 field_def fields_mbuf[] = { 58 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 59 {"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 60 {"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 61 {"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 62 {"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 63 {"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 64 {"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 65 {"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 66 {"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 67 }; 68 69 70 #define FLD_MB_IFACE FIELD_ADDR(fields_mbuf,0) 71 #define FLD_MB_RXDELAY FIELD_ADDR(fields_mbuf,1) 72 #define FLD_MB_TXDELAY FIELD_ADDR(fields_mbuf,2) 73 #define FLD_MB_LLOCKS FIELD_ADDR(fields_mbuf,3) 74 #define FLD_MB_MSIZE FIELD_ADDR(fields_mbuf,4) 75 #define FLD_MB_MALIVE FIELD_ADDR(fields_mbuf,5) 76 #define FLD_MB_MLWM FIELD_ADDR(fields_mbuf,6) 77 #define FLD_MB_MHWM FIELD_ADDR(fields_mbuf,7) 78 #define FLD_MB_MCWM FIELD_ADDR(fields_mbuf,8) 79 80 81 /* Define views */ 82 field_def *view_mbuf[] = { 83 FLD_MB_IFACE, 84 FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM, 85 FLD_MB_MCWM, NULL 86 }; 87 88 /* Define view managers */ 89 90 struct view_manager mbuf_mgr = { 91 "Mbufs", select_mb, read_mb, NULL, print_header, 92 print_mb, keyboard_callback, NULL, NULL 93 }; 94 95 field_view views_mb[] = { 96 {view_mbuf, "mbufs", '4', &mbuf_mgr}, 97 {NULL, NULL, 0, NULL} 98 }; 99 100 101 int 102 initmembufs(void) 103 { 104 struct if_rxring_info *ifr; 105 field_view *v; 106 int i, mib[4], npools; 107 struct kinfo_pool pool; 108 char pname[32]; 109 size_t size; 110 111 sock = socket(AF_INET, SOCK_DGRAM, 0); 112 if (sock == -1) { 113 err(1, "socket()"); 114 /* NOTREACHED */ 115 } 116 117 /* set up the "System" interface */ 118 119 interfaces = calloc(1, sizeof(*interfaces)); 120 if (interfaces == NULL) 121 err(1, "calloc: interfaces"); 122 123 ifr = calloc(MCLPOOLS, sizeof(*ifr)); 124 if (ifr == NULL) 125 err(1, "calloc: system pools"); 126 127 strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name)); 128 interfaces[0].data.ifri_total = MCLPOOLS; 129 interfaces[0].data.ifri_entries = ifr; 130 num_ifs = 1; 131 132 /* go through all pools to identify mbuf and cluster pools */ 133 134 mib[0] = CTL_KERN; 135 mib[1] = KERN_POOL; 136 mib[2] = KERN_POOL_NPOOLS; 137 size = sizeof(npools); 138 139 if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) { 140 err(1, "sysctl(KERN_POOL_NPOOLS)"); 141 /* NOTREACHED */ 142 } 143 144 for (i = 1; i <= npools; i++) { 145 mib[0] = CTL_KERN; 146 mib[1] = KERN_POOL; 147 mib[2] = KERN_POOL_NAME; 148 mib[3] = i; 149 size = sizeof(pname); 150 if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) { 151 continue; 152 } 153 154 if (strcmp(pname, "mbufpl") == 0) { 155 mbpool_index = i; 156 continue; 157 } 158 159 if (strncmp(pname, "mcl", 3) != 0) 160 continue; 161 162 if (mclpool_count == MCLPOOLS) { 163 warnx("mbufs: Too many mcl* pools"); 164 break; 165 } 166 167 mib[2] = KERN_POOL_POOL; 168 size = sizeof(pool); 169 170 if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { 171 err(1, "sysctl(KERN_POOL_POOL, %d)", i); 172 /* NOTREACHED */ 173 } 174 175 snprintf(ifr[mclpool_count].ifr_name, 176 sizeof(ifr[mclpool_count].ifr_name), "%dk", 177 pool.pr_size / 1024); 178 ifr[mclpool_count].ifr_size = pool.pr_size; 179 180 mclpools_index[mclpool_count++] = i; 181 } 182 183 if (mclpool_count != MCLPOOLS) 184 warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS); 185 186 /* add view to the engine */ 187 for (v = views_mb; v->name != NULL; v++) 188 add_view(v); 189 190 /* finally read it once */ 191 read_mb(); 192 193 return(1); 194 } 195 196 int 197 select_mb(void) 198 { 199 num_disp = 0; 200 return (0); 201 } 202 203 int 204 read_mb(void) 205 { 206 struct kinfo_pool pool; 207 struct ifaddrs *ifap, *ifa; 208 struct if_info *ifi; 209 struct if_rxring_info *ifr; 210 int mib[4]; 211 int i, p, nif, ret = 1, rv; 212 u_int rings; 213 size_t size; 214 215 mib[0] = CTL_KERN; 216 mib[1] = KERN_NETLIVELOCKS; 217 size = sizeof(mcllivelocks_cur); 218 if (sysctl(mib, 2, &mcllivelocks_cur, &size, NULL, 0) < 0 && 219 errno != EOPNOTSUPP) { 220 error("sysctl(KERN_NETLIVELOCKS)"); 221 goto exit; 222 } 223 mcllivelocks_diff = mcllivelocks_cur - mcllivelocks; 224 mcllivelocks = mcllivelocks_cur; 225 226 num_disp = 0; 227 if (getifaddrs(&ifap)) { 228 error("getifaddrs: %s", strerror(errno)); 229 return (1); 230 } 231 232 nif = 1; 233 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 234 if (ifa->ifa_addr == NULL || 235 ifa->ifa_addr->sa_family != AF_LINK) 236 continue; 237 238 nif++; 239 } 240 241 if (num_ifs < nif) { 242 ifi = reallocarray(interfaces, nif, sizeof(*interfaces)); 243 if (ifi == NULL) { 244 error("reallocarray: %d interfaces", nif); 245 goto exit; 246 } 247 248 interfaces = ifi; 249 while (num_ifs < nif) 250 memset(&interfaces[num_ifs++], 0, sizeof(*interfaces)); 251 } 252 253 /* Fill in the "real" interfaces */ 254 ifi = interfaces + 1; 255 256 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 257 if (ifa->ifa_addr == NULL || 258 ifa->ifa_addr->sa_family != AF_LINK) 259 continue; 260 261 strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name)); 262 for (;;) { 263 struct ifreq ifreq; 264 rings = ifi->data.ifri_total; 265 266 memset(&ifreq, 0, sizeof(ifreq)); 267 strlcpy(ifreq.ifr_name, ifa->ifa_name, 268 sizeof(ifreq.ifr_name)); 269 ifreq.ifr_data = (caddr_t)&ifi->data; 270 271 rv = ioctl(sock, SIOCGIFRXR, &ifreq); 272 if (rv == -1) { 273 if (errno == ENOTTY) { 274 free(ifi->data.ifri_entries); 275 ifi->data.ifri_total = 0; 276 ifi->data.ifri_entries = NULL; 277 break; 278 } 279 280 error("ioctl(SIOCGIFRXR) %s", strerror(errno)); 281 break; 282 } 283 284 if (rings >= ifi->data.ifri_total) 285 break; 286 287 ifr = reallocarray(ifi->data.ifri_entries, 288 ifi->data.ifri_total, sizeof(*ifr)); 289 if (ifr == NULL) { 290 ifi->data.ifri_total = rings; 291 error("reallocarray: %u rings", 292 ifi->data.ifri_total); 293 goto exit; 294 } 295 296 ifi->data.ifri_entries = ifr; 297 } 298 299 ifi++; 300 } 301 302 /* Fill in the "System" entry from pools */ 303 304 mib[0] = CTL_KERN; 305 mib[1] = KERN_POOL; 306 mib[2] = KERN_POOL_POOL; 307 mib[3] = mbpool_index; 308 size = sizeof(mbpool); 309 310 if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) { 311 error("sysctl(KERN_POOL_POOL, %d)", mib[3]); 312 goto exit; 313 } 314 315 for (i = 0; i < mclpool_count; i++) { 316 ifr = &interfaces[0].data.ifri_entries[i]; 317 318 mib[3] = mclpools_index[i]; 319 size = sizeof(pool); 320 321 if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { 322 error("sysctl(KERN_POOL_POOL, %d)", mib[3]); 323 continue; 324 } 325 326 ifr->ifr_info.rxr_alive = pool.pr_nget - pool.pr_nput; 327 ifr->ifr_info.rxr_hwm = pool.pr_hiwat; 328 } 329 330 num_disp = 1; 331 ret = 0; 332 333 for (i = 0; i < num_ifs; i++) { 334 struct if_info *ifi = &interfaces[i]; 335 int pnd = num_disp; 336 for (p = 0; p < ifi->data.ifri_total; p++) { 337 ifr = &ifi->data.ifri_entries[p]; 338 if (ifr->ifr_info.rxr_alive == 0) 339 continue; 340 num_disp++; 341 } 342 if (i && pnd == num_disp) 343 num_disp++; 344 } 345 346 exit: 347 freeifaddrs(ifap); 348 return (ret); 349 } 350 351 void 352 print_mb(void) 353 { 354 int i, p, n, count = 0; 355 356 showmbuf(interfaces, -1, 1); 357 358 for (n = i = 0; i < num_ifs; i++) { 359 struct if_info *ifi = &interfaces[i]; 360 int pcnt = count; 361 int showif = i; 362 363 if (maxprint > 0 && count >= maxprint) 364 return; 365 366 for (p = 0; p < ifi->data.ifri_total; p++) { 367 struct if_rxring_info *ifr = &ifi->data.ifri_entries[p]; 368 if (ifr->ifr_info.rxr_alive == 0) 369 continue; 370 if (n++ >= dispstart) { 371 showmbuf(ifi, p, showif); 372 showif = 0; 373 count++; 374 } 375 } 376 377 if (i && pcnt == count) { 378 /* only print the first line */ 379 if (n++ >= dispstart) { 380 showmbuf(ifi, -1, 1); 381 count++; 382 } 383 } 384 } 385 } 386 387 388 static void 389 showmbuf(struct if_info *ifi, int p, int showif) 390 { 391 if (showif) 392 print_fld_str(FLD_MB_IFACE, ifi->name); 393 394 if (p == -1 && ifi == interfaces) { 395 print_fld_uint(FLD_MB_LLOCKS, mcllivelocks_diff); 396 print_fld_size(FLD_MB_MSIZE, mbpool.pr_size); 397 print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput); 398 print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat); 399 } 400 401 if (p >= 0 && p < mclpool_count) { 402 struct if_rxring_info *ifr = &ifi->data.ifri_entries[p]; 403 struct if_rxring *rxr= &ifr->ifr_info; 404 print_fld_uint(FLD_MB_MSIZE, ifr->ifr_size); 405 print_fld_uint(FLD_MB_MALIVE, rxr->rxr_alive); 406 if (rxr->rxr_lwm) 407 print_fld_size(FLD_MB_MLWM, rxr->rxr_lwm); 408 if (rxr->rxr_hwm) 409 print_fld_size(FLD_MB_MHWM, rxr->rxr_hwm); 410 if (rxr->rxr_cwm) 411 print_fld_size(FLD_MB_MCWM, rxr->rxr_cwm); 412 } 413 414 end_line(); 415 } 416