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