1204202Srwatson/*- 2217775Srwatson * Copyright (c) 2010-2011 Juniper Networks, Inc. 3204202Srwatson * All rights reserved. 4204202Srwatson * 5204202Srwatson * This software was developed by Robert N. M. Watson under contract 6204202Srwatson * to Juniper Networks, Inc. 7204202Srwatson * 8204202Srwatson * Redistribution and use in source and binary forms, with or without 9204202Srwatson * modification, are permitted provided that the following conditions 10204202Srwatson * are met: 11204202Srwatson * 1. Redistributions of source code must retain the above copyright 12204202Srwatson * notice, this list of conditions and the following disclaimer. 13204202Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14204202Srwatson * notice, this list of conditions and the following disclaimer in the 15204202Srwatson * documentation and/or other materials provided with the distribution. 16204202Srwatson * 17204202Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18204202Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204202Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204202Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21204202Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204202Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204202Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204202Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204202Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204202Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204202Srwatson * SUCH DAMAGE. 28204202Srwatson */ 29204202Srwatson 30204202Srwatson#include <sys/cdefs.h> 31204202Srwatson 32204202Srwatson__FBSDID("$FreeBSD$"); 33204202Srwatson 34204499Srwatson#include <sys/param.h> 35204202Srwatson#include <sys/sysctl.h> 36204202Srwatson 37204499Srwatson#include <sys/_lock.h> 38204499Srwatson#include <sys/_mutex.h> 39204499Srwatson 40204499Srwatson#define _WANT_NETISR_INTERNAL 41204202Srwatson#include <net/netisr.h> 42204499Srwatson#include <net/netisr_internal.h> 43204202Srwatson 44204202Srwatson#include <err.h> 45204499Srwatson#include <kvm.h> 46204202Srwatson#include <stdint.h> 47204202Srwatson#include <stdio.h> 48204202Srwatson#include <stdlib.h> 49204499Srwatson#include <string.h> 50204202Srwatson 51204202Srwatson#include "netstat.h" 52204202Srwatson 53204202Srwatson/* 54204202Srwatson * Print statistics for the kernel netisr subsystem. 55204202Srwatson */ 56204202Srwatsonstatic u_int bindthreads; 57204202Srwatsonstatic u_int maxthreads; 58204202Srwatsonstatic u_int numthreads; 59204202Srwatson 60204202Srwatsonstatic u_int defaultqlimit; 61204202Srwatsonstatic u_int maxqlimit; 62204202Srwatson 63222250Srwatsonstatic char dispatch_policy[20]; 64204202Srwatson 65204202Srwatsonstatic struct sysctl_netisr_proto *proto_array; 66204202Srwatsonstatic u_int proto_array_len; 67204202Srwatson 68204202Srwatsonstatic struct sysctl_netisr_workstream *workstream_array; 69204202Srwatsonstatic u_int workstream_array_len; 70204202Srwatson 71204202Srwatsonstatic struct sysctl_netisr_work *work_array; 72204202Srwatsonstatic u_int work_array_len; 73204202Srwatson 74204499Srwatsonstatic u_int *nws_array; 75204499Srwatson 76204499Srwatsonstatic u_int maxprot; 77204499Srwatson 78204202Srwatsonstatic void 79246988Scharniernetisr_dispatch_policy_to_string(u_int policy, char *buf, 80222250Srwatson size_t buflen) 81222250Srwatson{ 82222250Srwatson const char *str; 83222250Srwatson 84246988Scharnier switch (policy) { 85222250Srwatson case NETISR_DISPATCH_DEFAULT: 86222250Srwatson str = "default"; 87222250Srwatson break; 88222250Srwatson case NETISR_DISPATCH_DEFERRED: 89222250Srwatson str = "deferred"; 90222250Srwatson break; 91222250Srwatson case NETISR_DISPATCH_HYBRID: 92222250Srwatson str = "hybrid"; 93222250Srwatson break; 94222250Srwatson case NETISR_DISPATCH_DIRECT: 95222250Srwatson str = "direct"; 96222250Srwatson break; 97222250Srwatson default: 98222250Srwatson str = "unknown"; 99222250Srwatson break; 100222250Srwatson } 101222250Srwatson snprintf(buf, buflen, "%s", str); 102222250Srwatson} 103222250Srwatson 104222250Srwatsonstatic void 105246988Scharniernetisr_load_kvm_uint(kvm_t *kd, const char *name, u_int *p) 106204499Srwatson{ 107204499Srwatson struct nlist nl[] = { 108204499Srwatson { .n_name = name }, 109204499Srwatson { .n_name = NULL }, 110204499Srwatson }; 111204499Srwatson int ret; 112204499Srwatson 113204499Srwatson ret = kvm_nlist(kd, nl); 114204499Srwatson if (ret < 0) 115204499Srwatson errx(-1, "%s: kvm_nlist(%s): %s", __func__, name, 116204499Srwatson kvm_geterr(kd)); 117204499Srwatson if (ret != 0) 118204499Srwatson errx(-1, "%s: kvm_nlist(%s): unresolved symbol", __func__, 119204499Srwatson name); 120204499Srwatson if (kvm_read(kd, nl[0].n_value, p, sizeof(*p)) != sizeof(*p)) 121204499Srwatson errx(-1, "%s: kvm_read(%s): %s", __func__, name, 122204499Srwatson kvm_geterr(kd)); 123204499Srwatson} 124204499Srwatson 125204499Srwatson/* 126204499Srwatson * Load a nul-terminated string from KVM up to 'limit', guarantee that the 127204499Srwatson * string in local memory is nul-terminated. 128204499Srwatson */ 129204499Srwatsonstatic void 130204499Srwatsonnetisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit) 131204499Srwatson{ 132204499Srwatson u_int i; 133204499Srwatson 134204499Srwatson for (i = 0; i < limit; i++) { 135204499Srwatson if (kvm_read(kd, addr + i, &dest[i], sizeof(dest[i])) != 136204499Srwatson sizeof(dest[i])) 137204499Srwatson err(-1, "%s: kvm_read: %s", __func__, 138204499Srwatson kvm_geterr(kd)); 139204499Srwatson if (dest[i] == '\0') 140204499Srwatson break; 141204499Srwatson } 142204499Srwatson dest[limit - 1] = '\0'; 143204499Srwatson} 144204499Srwatson 145204499Srwatsonstatic const char * 146204499Srwatsonnetisr_proto2name(u_int proto) 147204499Srwatson{ 148204499Srwatson u_int i; 149204499Srwatson 150204499Srwatson for (i = 0; i < proto_array_len; i++) { 151204499Srwatson if (proto_array[i].snp_proto == proto) 152204499Srwatson return (proto_array[i].snp_name); 153204499Srwatson } 154204499Srwatson return ("unknown"); 155204499Srwatson} 156204499Srwatson 157204499Srwatsonstatic int 158204499Srwatsonnetisr_protoispresent(u_int proto) 159204499Srwatson{ 160204499Srwatson u_int i; 161204499Srwatson 162204499Srwatson for (i = 0; i < proto_array_len; i++) { 163204499Srwatson if (proto_array[i].snp_proto == proto) 164204499Srwatson return (1); 165204499Srwatson } 166204499Srwatson return (0); 167204499Srwatson} 168204499Srwatson 169204499Srwatsonstatic void 170204499Srwatsonnetisr_load_kvm_config(kvm_t *kd) 171204499Srwatson{ 172222250Srwatson u_int tmp; 173204499Srwatson 174204499Srwatson netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads); 175204499Srwatson netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads); 176204499Srwatson netisr_load_kvm_uint(kd, "_nws_count", &numthreads); 177204499Srwatson 178204499Srwatson netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit); 179204499Srwatson netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit); 180204499Srwatson 181222250Srwatson netisr_load_kvm_uint(kd, "_netisr_dispatch_policy", &tmp); 182222250Srwatson netisr_dispatch_policy_to_string(tmp, dispatch_policy, 183222250Srwatson sizeof(dispatch_policy)); 184204499Srwatson} 185204499Srwatson 186204499Srwatsonstatic void 187204202Srwatsonnetisr_load_sysctl_uint(const char *name, u_int *p) 188204202Srwatson{ 189204202Srwatson size_t retlen; 190204202Srwatson 191204202Srwatson retlen = sizeof(u_int); 192204202Srwatson if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) 193204202Srwatson err(-1, "%s", name); 194204202Srwatson if (retlen != sizeof(u_int)) 195204202Srwatson errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen); 196204202Srwatson} 197204202Srwatson 198204202Srwatsonstatic void 199222250Srwatsonnetisr_load_sysctl_string(const char *name, char *p, size_t len) 200222250Srwatson{ 201222250Srwatson size_t retlen; 202222250Srwatson 203222250Srwatson retlen = len; 204222250Srwatson if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) 205222250Srwatson err(-1, "%s", name); 206222250Srwatson p[len - 1] = '\0'; 207222250Srwatson} 208222250Srwatson 209222250Srwatsonstatic void 210204499Srwatsonnetisr_load_sysctl_config(void) 211204202Srwatson{ 212204202Srwatson 213204202Srwatson netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads); 214204202Srwatson netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads); 215204202Srwatson netisr_load_sysctl_uint("net.isr.numthreads", &numthreads); 216204202Srwatson 217204202Srwatson netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit); 218204202Srwatson netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit); 219204202Srwatson 220222250Srwatson netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy, 221222250Srwatson sizeof(dispatch_policy)); 222204202Srwatson} 223204202Srwatson 224204202Srwatsonstatic void 225204499Srwatsonnetisr_load_kvm_proto(kvm_t *kd) 226204202Srwatson{ 227204499Srwatson struct nlist nl[] = { 228204499Srwatson#define NLIST_NETISR_PROTO 0 229204499Srwatson { .n_name = "_netisr_proto" }, 230204499Srwatson { .n_name = NULL }, 231204499Srwatson }; 232204499Srwatson struct netisr_proto *np_array, *npp; 233204499Srwatson u_int i, protocount; 234204499Srwatson struct sysctl_netisr_proto *snpp; 235204202Srwatson size_t len; 236204499Srwatson int ret; 237204202Srwatson 238204499Srwatson /* 239204499Srwatson * Kernel compile-time and user compile-time definitions of 240204499Srwatson * NETISR_MAXPROT must match, as we use that to size work arrays. 241204499Srwatson */ 242204499Srwatson netisr_load_kvm_uint(kd, "_netisr_maxprot", &maxprot); 243204499Srwatson if (maxprot != NETISR_MAXPROT) 244204499Srwatson errx(-1, "%s: NETISR_MAXPROT mismatch", __func__); 245204499Srwatson len = maxprot * sizeof(*np_array); 246204499Srwatson np_array = malloc(len); 247204499Srwatson if (np_array == NULL) 248204499Srwatson err(-1, "%s: malloc", __func__); 249204499Srwatson ret = kvm_nlist(kd, nl); 250204499Srwatson if (ret < 0) 251204499Srwatson errx(-1, "%s: kvm_nlist(_netisr_proto): %s", __func__, 252204499Srwatson kvm_geterr(kd)); 253204499Srwatson if (ret != 0) 254204499Srwatson errx(-1, "%s: kvm_nlist(_netisr_proto): unresolved symbol", 255204499Srwatson __func__); 256204499Srwatson if (kvm_read(kd, nl[NLIST_NETISR_PROTO].n_value, np_array, len) != 257204499Srwatson (ssize_t)len) 258204499Srwatson errx(-1, "%s: kvm_read(_netisr_proto): %s", __func__, 259204499Srwatson kvm_geterr(kd)); 260204499Srwatson 261204499Srwatson /* 262204499Srwatson * Size and allocate memory to hold only live protocols. 263204499Srwatson */ 264204499Srwatson protocount = 0; 265204499Srwatson for (i = 0; i < maxprot; i++) { 266204499Srwatson if (np_array[i].np_name == NULL) 267204499Srwatson continue; 268204499Srwatson protocount++; 269204499Srwatson } 270204499Srwatson proto_array = calloc(protocount, sizeof(*proto_array)); 271204499Srwatson if (proto_array == NULL) 272204499Srwatson err(-1, "malloc"); 273204499Srwatson protocount = 0; 274204499Srwatson for (i = 0; i < maxprot; i++) { 275204499Srwatson npp = &np_array[i]; 276204499Srwatson if (npp->np_name == NULL) 277204499Srwatson continue; 278204499Srwatson snpp = &proto_array[protocount]; 279204499Srwatson snpp->snp_version = sizeof(*snpp); 280204499Srwatson netisr_load_kvm_string(kd, (uintptr_t)npp->np_name, 281204499Srwatson snpp->snp_name, sizeof(snpp->snp_name)); 282204499Srwatson snpp->snp_proto = i; 283204499Srwatson snpp->snp_qlimit = npp->np_qlimit; 284204499Srwatson snpp->snp_policy = npp->np_policy; 285222250Srwatson snpp->snp_dispatch = npp->np_dispatch; 286204499Srwatson if (npp->np_m2flow != NULL) 287204499Srwatson snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW; 288204499Srwatson if (npp->np_m2cpuid != NULL) 289204499Srwatson snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID; 290204499Srwatson if (npp->np_drainedcpu != NULL) 291204499Srwatson snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU; 292204499Srwatson protocount++; 293204499Srwatson } 294204499Srwatson proto_array_len = protocount; 295204499Srwatson free(np_array); 296204499Srwatson} 297204499Srwatson 298204499Srwatsonstatic void 299204499Srwatsonnetisr_load_sysctl_proto(void) 300204499Srwatson{ 301204499Srwatson size_t len; 302204499Srwatson 303204202Srwatson if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0) 304204202Srwatson err(-1, "net.isr.proto: query len"); 305204202Srwatson if (len % sizeof(*proto_array) != 0) 306204202Srwatson errx(-1, "net.isr.proto: invalid len"); 307204202Srwatson proto_array = malloc(len); 308204202Srwatson if (proto_array == NULL) 309204202Srwatson err(-1, "malloc"); 310204202Srwatson if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0) 311204202Srwatson err(-1, "net.isr.proto: query data"); 312204202Srwatson if (len % sizeof(*proto_array) != 0) 313204202Srwatson errx(-1, "net.isr.proto: invalid len"); 314204202Srwatson proto_array_len = len / sizeof(*proto_array); 315204202Srwatson if (proto_array_len < 1) 316204202Srwatson errx(-1, "net.isr.proto: no data"); 317204202Srwatson if (proto_array[0].snp_version != sizeof(proto_array[0])) 318204202Srwatson errx(-1, "net.isr.proto: invalid version"); 319204202Srwatson} 320204202Srwatson 321204202Srwatsonstatic void 322204499Srwatsonnetisr_load_kvm_workstream(kvm_t *kd) 323204202Srwatson{ 324204499Srwatson struct nlist nl[] = { 325204499Srwatson#define NLIST_NWS_ARRAY 0 326204499Srwatson { .n_name = "_nws_array" }, 327204499Srwatson { .n_name = NULL }, 328204499Srwatson }; 329204499Srwatson struct netisr_workstream nws; 330204499Srwatson struct sysctl_netisr_workstream *snwsp; 331204499Srwatson struct sysctl_netisr_work *snwp; 332204499Srwatson struct netisr_work *nwp; 333204499Srwatson struct nlist nl_nws[2]; 334204499Srwatson u_int counter, cpuid, proto, wsid; 335204202Srwatson size_t len; 336204499Srwatson int ret; 337204202Srwatson 338204499Srwatson len = numthreads * sizeof(*nws_array); 339204499Srwatson nws_array = malloc(len); 340204499Srwatson if (nws_array == NULL) 341204499Srwatson err(-1, "malloc"); 342204499Srwatson ret = kvm_nlist(kd, nl); 343204499Srwatson if (ret < 0) 344204499Srwatson errx(-1, "%s: kvm_nlist: %s", __func__, kvm_geterr(kd)); 345204499Srwatson if (ret != 0) 346204499Srwatson errx(-1, "%s: kvm_nlist: unresolved symbol", __func__); 347204499Srwatson if (kvm_read(kd, nl[NLIST_NWS_ARRAY].n_value, nws_array, len) != 348204499Srwatson (ssize_t)len) 349204499Srwatson errx(-1, "%s: kvm_read(_nws_array): %s", __func__, 350204499Srwatson kvm_geterr(kd)); 351204499Srwatson workstream_array = calloc(numthreads, sizeof(*workstream_array)); 352204499Srwatson if (workstream_array == NULL) 353204499Srwatson err(-1, "calloc"); 354204499Srwatson workstream_array_len = numthreads; 355204499Srwatson work_array = calloc(numthreads * proto_array_len, sizeof(*work_array)); 356204499Srwatson if (work_array == NULL) 357204499Srwatson err(-1, "calloc"); 358204499Srwatson counter = 0; 359204499Srwatson for (wsid = 0; wsid < numthreads; wsid++) { 360204499Srwatson cpuid = nws_array[wsid]; 361204499Srwatson if (kvm_dpcpu_setcpu(kd, cpuid) < 0) 362204499Srwatson errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, 363204499Srwatson cpuid, kvm_geterr(kd)); 364204499Srwatson bzero(nl_nws, sizeof(nl_nws)); 365204499Srwatson nl_nws[0].n_name = "_nws"; 366204499Srwatson ret = kvm_nlist(kd, nl_nws); 367204499Srwatson if (ret < 0) 368204499Srwatson errx(-1, "%s: kvm_nlist looking up nws on CPU %u: %s", 369204499Srwatson __func__, cpuid, kvm_geterr(kd)); 370204499Srwatson if (ret != 0) 371204499Srwatson errx(-1, "%s: kvm_nlist(nws): unresolved symbol on " 372204499Srwatson "CPU %u", __func__, cpuid); 373204499Srwatson if (kvm_read(kd, nl_nws[0].n_value, &nws, sizeof(nws)) != 374204499Srwatson sizeof(nws)) 375204499Srwatson errx(-1, "%s: kvm_read(nw): %s", __func__, 376204499Srwatson kvm_geterr(kd)); 377204499Srwatson snwsp = &workstream_array[wsid]; 378204499Srwatson snwsp->snws_version = sizeof(*snwsp); 379204499Srwatson snwsp->snws_wsid = cpuid; 380204499Srwatson snwsp->snws_cpu = cpuid; 381204499Srwatson if (nws.nws_intr_event != NULL) 382204499Srwatson snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR; 383204499Srwatson 384204499Srwatson /* 385204499Srwatson * Extract the CPU's per-protocol work information. 386204499Srwatson */ 387204499Srwatson printf("counting to maxprot: %u\n", maxprot); 388204499Srwatson for (proto = 0; proto < maxprot; proto++) { 389204499Srwatson if (!netisr_protoispresent(proto)) 390204499Srwatson continue; 391204499Srwatson nwp = &nws.nws_work[proto]; 392204499Srwatson snwp = &work_array[counter]; 393204499Srwatson snwp->snw_version = sizeof(*snwp); 394204499Srwatson snwp->snw_wsid = cpuid; 395204499Srwatson snwp->snw_proto = proto; 396204499Srwatson snwp->snw_len = nwp->nw_len; 397204499Srwatson snwp->snw_watermark = nwp->nw_watermark; 398204499Srwatson snwp->snw_dispatched = nwp->nw_dispatched; 399204499Srwatson snwp->snw_hybrid_dispatched = 400204499Srwatson nwp->nw_hybrid_dispatched; 401204499Srwatson snwp->snw_qdrops = nwp->nw_qdrops; 402204499Srwatson snwp->snw_queued = nwp->nw_queued; 403204499Srwatson snwp->snw_handled = nwp->nw_handled; 404204499Srwatson counter++; 405204499Srwatson } 406204499Srwatson } 407204499Srwatson work_array_len = counter; 408204499Srwatson} 409204499Srwatson 410204499Srwatsonstatic void 411204499Srwatsonnetisr_load_sysctl_workstream(void) 412204499Srwatson{ 413204499Srwatson size_t len; 414204499Srwatson 415204202Srwatson if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0) 416204202Srwatson err(-1, "net.isr.workstream: query len"); 417204202Srwatson if (len % sizeof(*workstream_array) != 0) 418204202Srwatson errx(-1, "net.isr.workstream: invalid len"); 419204202Srwatson workstream_array = malloc(len); 420204202Srwatson if (workstream_array == NULL) 421204202Srwatson err(-1, "malloc"); 422204202Srwatson if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL, 423204202Srwatson 0) < 0) 424204202Srwatson err(-1, "net.isr.workstream: query data"); 425204202Srwatson if (len % sizeof(*workstream_array) != 0) 426204202Srwatson errx(-1, "net.isr.workstream: invalid len"); 427204202Srwatson workstream_array_len = len / sizeof(*workstream_array); 428204202Srwatson if (workstream_array_len < 1) 429204202Srwatson errx(-1, "net.isr.workstream: no data"); 430204202Srwatson if (workstream_array[0].snws_version != sizeof(workstream_array[0])) 431204202Srwatson errx(-1, "net.isr.workstream: invalid version"); 432204202Srwatson} 433204202Srwatson 434204202Srwatsonstatic void 435204499Srwatsonnetisr_load_sysctl_work(void) 436204202Srwatson{ 437204202Srwatson size_t len; 438204202Srwatson 439204202Srwatson if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0) 440204202Srwatson err(-1, "net.isr.work: query len"); 441204202Srwatson if (len % sizeof(*work_array) != 0) 442204202Srwatson errx(-1, "net.isr.work: invalid len"); 443204202Srwatson work_array = malloc(len); 444204202Srwatson if (work_array == NULL) 445204202Srwatson err(-1, "malloc"); 446204202Srwatson if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0) 447204202Srwatson err(-1, "net.isr.work: query data"); 448204202Srwatson if (len % sizeof(*work_array) != 0) 449204202Srwatson errx(-1, "net.isr.work: invalid len"); 450204202Srwatson work_array_len = len / sizeof(*work_array); 451204202Srwatson if (work_array_len < 1) 452204202Srwatson errx(-1, "net.isr.work: no data"); 453204202Srwatson if (work_array[0].snw_version != sizeof(work_array[0])) 454204202Srwatson errx(-1, "net.isr.work: invalid version"); 455204202Srwatson} 456204202Srwatson 457204202Srwatsonstatic void 458204202Srwatsonnetisr_print_proto(struct sysctl_netisr_proto *snpp) 459204202Srwatson{ 460222250Srwatson char tmp[20]; 461204202Srwatson 462204202Srwatson printf("%-6s", snpp->snp_name); 463204202Srwatson printf(" %5u", snpp->snp_proto); 464204202Srwatson printf(" %6u", snpp->snp_qlimit); 465204202Srwatson printf(" %6s", 466204202Srwatson (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" : 467204202Srwatson (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" : 468204202Srwatson (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-"); 469222250Srwatson netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp, 470222250Srwatson sizeof(tmp)); 471222250Srwatson printf(" %8s", tmp); 472204202Srwatson printf(" %s%s%s\n", 473204202Srwatson (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-", 474204202Srwatson (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-", 475204202Srwatson (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-"); 476204202Srwatson} 477204202Srwatson 478204202Srwatsonstatic void 479204202Srwatsonnetisr_print_workstream(struct sysctl_netisr_workstream *snwsp) 480204202Srwatson{ 481204202Srwatson struct sysctl_netisr_work *snwp; 482204202Srwatson u_int i; 483204202Srwatson 484204202Srwatson for (i = 0; i < work_array_len; i++) { 485204202Srwatson snwp = &work_array[i]; 486204202Srwatson if (snwp->snw_wsid != snwsp->snws_wsid) 487204202Srwatson continue; 488217776Srwatson printf("%4u ", snwsp->snws_wsid); 489217776Srwatson printf("%3u ", snwsp->snws_cpu); 490204202Srwatson printf("%2s", ""); 491204202Srwatson printf("%-6s", netisr_proto2name(snwp->snw_proto)); 492204202Srwatson printf(" %5u", snwp->snw_len); 493204202Srwatson printf(" %5u", snwp->snw_watermark); 494204202Srwatson printf(" %8ju", snwp->snw_dispatched); 495204202Srwatson printf(" %8ju", snwp->snw_hybrid_dispatched); 496204202Srwatson printf(" %8ju", snwp->snw_qdrops); 497204202Srwatson printf(" %8ju", snwp->snw_queued); 498204202Srwatson printf(" %8ju", snwp->snw_handled); 499204202Srwatson printf("\n"); 500204202Srwatson } 501204202Srwatson} 502204202Srwatson 503204202Srwatsonvoid 504204499Srwatsonnetisr_stats(void *kvmd) 505204202Srwatson{ 506204202Srwatson struct sysctl_netisr_workstream *snwsp; 507204202Srwatson struct sysctl_netisr_proto *snpp; 508204499Srwatson kvm_t *kd = kvmd; 509204202Srwatson u_int i; 510204202Srwatson 511204499Srwatson if (live) { 512204499Srwatson netisr_load_sysctl_config(); 513204499Srwatson netisr_load_sysctl_proto(); 514204499Srwatson netisr_load_sysctl_workstream(); 515204499Srwatson netisr_load_sysctl_work(); 516204499Srwatson } else { 517204499Srwatson if (kd == NULL) 518204499Srwatson errx(-1, "netisr_stats: !live but !kd"); 519204499Srwatson netisr_load_kvm_config(kd); 520204499Srwatson netisr_load_kvm_proto(kd); 521204499Srwatson netisr_load_kvm_workstream(kd); /* Also does work. */ 522204499Srwatson } 523204202Srwatson 524204202Srwatson printf("Configuration:\n"); 525204515Srwatson printf("%-25s %12s %12s\n", "Setting", "Current", "Limit"); 526204202Srwatson printf("%-25s %12u %12u\n", "Thread count", numthreads, maxthreads); 527204202Srwatson printf("%-25s %12u %12u\n", "Default queue limit", defaultqlimit, 528204202Srwatson maxqlimit); 529222250Srwatson printf("%-25s %12s %12s\n", "Dispatch policy", dispatch_policy, 530222250Srwatson "n/a"); 531204202Srwatson printf("%-25s %12s %12s\n", "Threads bound to CPUs", 532204202Srwatson bindthreads ? "enabled" : "disabled", "n/a"); 533204202Srwatson printf("\n"); 534204202Srwatson 535204202Srwatson printf("Protocols:\n"); 536222250Srwatson printf("%-6s %5s %6s %-6s %-8s %-5s\n", "Name", "Proto", "QLimit", 537222250Srwatson "Policy", "Dispatch", "Flags"); 538204202Srwatson for (i = 0; i < proto_array_len; i++) { 539204202Srwatson snpp = &proto_array[i]; 540204202Srwatson netisr_print_proto(snpp); 541204202Srwatson } 542204202Srwatson printf("\n"); 543204202Srwatson 544204202Srwatson printf("Workstreams:\n"); 545204202Srwatson printf("%4s %3s ", "WSID", "CPU"); 546204202Srwatson printf("%2s", ""); 547204202Srwatson printf("%-6s %5s %5s %8s %8s %8s %8s %8s\n", "Name", "Len", "WMark", 548204202Srwatson "Disp'd", "HDisp'd", "QDrops", "Queued", "Handled"); 549204202Srwatson for (i = 0; i < workstream_array_len; i++) { 550204202Srwatson snwsp = &workstream_array[i]; 551204202Srwatson netisr_print_workstream(snwsp); 552204202Srwatson } 553204202Srwatson} 554