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