10153eb66SRobert Watson /*- 27ff67a20SRobert Watson * Copyright (c) 2010-2011 Juniper Networks, Inc. 30153eb66SRobert Watson * All rights reserved. 40153eb66SRobert Watson * 50153eb66SRobert Watson * This software was developed by Robert N. M. Watson under contract 60153eb66SRobert Watson * to Juniper Networks, Inc. 70153eb66SRobert Watson * 80153eb66SRobert Watson * Redistribution and use in source and binary forms, with or without 90153eb66SRobert Watson * modification, are permitted provided that the following conditions 100153eb66SRobert Watson * are met: 110153eb66SRobert Watson * 1. Redistributions of source code must retain the above copyright 120153eb66SRobert Watson * notice, this list of conditions and the following disclaimer. 130153eb66SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 140153eb66SRobert Watson * notice, this list of conditions and the following disclaimer in the 150153eb66SRobert Watson * documentation and/or other materials provided with the distribution. 160153eb66SRobert Watson * 170153eb66SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 180153eb66SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190153eb66SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200153eb66SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 210153eb66SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 220153eb66SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 230153eb66SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 240153eb66SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 250153eb66SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 260153eb66SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 270153eb66SRobert Watson * SUCH DAMAGE. 280153eb66SRobert Watson */ 290153eb66SRobert Watson 300153eb66SRobert Watson #include <sys/cdefs.h> 310153eb66SRobert Watson 320153eb66SRobert Watson __FBSDID("$FreeBSD$"); 330153eb66SRobert Watson 3488737be2SRobert Watson #include <sys/param.h> 350153eb66SRobert Watson #include <sys/sysctl.h> 360153eb66SRobert Watson 3788737be2SRobert Watson #include <sys/_lock.h> 3888737be2SRobert Watson #include <sys/_mutex.h> 3988737be2SRobert Watson 4088737be2SRobert Watson #define _WANT_NETISR_INTERNAL 410153eb66SRobert Watson #include <net/netisr.h> 4288737be2SRobert Watson #include <net/netisr_internal.h> 430153eb66SRobert Watson 440153eb66SRobert Watson #include <err.h> 4588737be2SRobert Watson #include <kvm.h> 460153eb66SRobert Watson #include <stdint.h> 470153eb66SRobert Watson #include <stdio.h> 480153eb66SRobert Watson #include <stdlib.h> 49*ade9ccfeSMarcel Moolenaar #include <stdbool.h> 5088737be2SRobert Watson #include <string.h> 51*ade9ccfeSMarcel Moolenaar #include <libxo/xo.h> 520153eb66SRobert Watson #include "netstat.h" 530153eb66SRobert Watson 540153eb66SRobert Watson /* 550153eb66SRobert Watson * Print statistics for the kernel netisr subsystem. 560153eb66SRobert Watson */ 570153eb66SRobert Watson static u_int bindthreads; 580153eb66SRobert Watson static u_int maxthreads; 590153eb66SRobert Watson static u_int numthreads; 600153eb66SRobert Watson 610153eb66SRobert Watson static u_int defaultqlimit; 620153eb66SRobert Watson static u_int maxqlimit; 630153eb66SRobert Watson 648f092df0SRobert Watson static char dispatch_policy[20]; 650153eb66SRobert Watson 660153eb66SRobert Watson static struct sysctl_netisr_proto *proto_array; 670153eb66SRobert Watson static u_int proto_array_len; 680153eb66SRobert Watson 690153eb66SRobert Watson static struct sysctl_netisr_workstream *workstream_array; 700153eb66SRobert Watson static u_int workstream_array_len; 710153eb66SRobert Watson 720153eb66SRobert Watson static struct sysctl_netisr_work *work_array; 730153eb66SRobert Watson static u_int work_array_len; 740153eb66SRobert Watson 7588737be2SRobert Watson static u_int *nws_array; 7688737be2SRobert Watson 7788737be2SRobert Watson static u_int maxprot; 7888737be2SRobert Watson 7988737be2SRobert Watson static void 80321ae07fSPhilippe Charnier netisr_dispatch_policy_to_string(u_int policy, char *buf, 818f092df0SRobert Watson size_t buflen) 828f092df0SRobert Watson { 838f092df0SRobert Watson const char *str; 848f092df0SRobert Watson 85321ae07fSPhilippe Charnier switch (policy) { 868f092df0SRobert Watson case NETISR_DISPATCH_DEFAULT: 878f092df0SRobert Watson str = "default"; 888f092df0SRobert Watson break; 898f092df0SRobert Watson case NETISR_DISPATCH_DEFERRED: 908f092df0SRobert Watson str = "deferred"; 918f092df0SRobert Watson break; 928f092df0SRobert Watson case NETISR_DISPATCH_HYBRID: 938f092df0SRobert Watson str = "hybrid"; 948f092df0SRobert Watson break; 958f092df0SRobert Watson case NETISR_DISPATCH_DIRECT: 968f092df0SRobert Watson str = "direct"; 978f092df0SRobert Watson break; 988f092df0SRobert Watson default: 998f092df0SRobert Watson str = "unknown"; 1008f092df0SRobert Watson break; 1018f092df0SRobert Watson } 1028f092df0SRobert Watson snprintf(buf, buflen, "%s", str); 1038f092df0SRobert Watson } 1048f092df0SRobert Watson 1058f092df0SRobert Watson static void 106321ae07fSPhilippe Charnier netisr_load_kvm_uint(kvm_t *kd, const char *name, u_int *p) 10788737be2SRobert Watson { 10888737be2SRobert Watson struct nlist nl[] = { 10988737be2SRobert Watson { .n_name = name }, 11088737be2SRobert Watson { .n_name = NULL }, 11188737be2SRobert Watson }; 11288737be2SRobert Watson int ret; 11388737be2SRobert Watson 11488737be2SRobert Watson ret = kvm_nlist(kd, nl); 11588737be2SRobert Watson if (ret < 0) 116*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist(%s): %s", __func__, name, 11788737be2SRobert Watson kvm_geterr(kd)); 11888737be2SRobert Watson if (ret != 0) 119*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist(%s): unresolved symbol", __func__, 12088737be2SRobert Watson name); 12188737be2SRobert Watson if (kvm_read(kd, nl[0].n_value, p, sizeof(*p)) != sizeof(*p)) 122*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_read(%s): %s", __func__, name, 12388737be2SRobert Watson kvm_geterr(kd)); 12488737be2SRobert Watson } 12588737be2SRobert Watson 12688737be2SRobert Watson /* 12788737be2SRobert Watson * Load a nul-terminated string from KVM up to 'limit', guarantee that the 12888737be2SRobert Watson * string in local memory is nul-terminated. 12988737be2SRobert Watson */ 13088737be2SRobert Watson static void 13188737be2SRobert Watson netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit) 13288737be2SRobert Watson { 13388737be2SRobert Watson u_int i; 13488737be2SRobert Watson 13588737be2SRobert Watson for (i = 0; i < limit; i++) { 13688737be2SRobert Watson if (kvm_read(kd, addr + i, &dest[i], sizeof(dest[i])) != 13788737be2SRobert Watson sizeof(dest[i])) 138*ade9ccfeSMarcel Moolenaar xo_err(-1, "%s: kvm_read: %s", __func__, 13988737be2SRobert Watson kvm_geterr(kd)); 14088737be2SRobert Watson if (dest[i] == '\0') 14188737be2SRobert Watson break; 14288737be2SRobert Watson } 14388737be2SRobert Watson dest[limit - 1] = '\0'; 14488737be2SRobert Watson } 14588737be2SRobert Watson 14688737be2SRobert Watson static const char * 14788737be2SRobert Watson netisr_proto2name(u_int proto) 14888737be2SRobert Watson { 14988737be2SRobert Watson u_int i; 15088737be2SRobert Watson 15188737be2SRobert Watson for (i = 0; i < proto_array_len; i++) { 15288737be2SRobert Watson if (proto_array[i].snp_proto == proto) 15388737be2SRobert Watson return (proto_array[i].snp_name); 15488737be2SRobert Watson } 15588737be2SRobert Watson return ("unknown"); 15688737be2SRobert Watson } 15788737be2SRobert Watson 15888737be2SRobert Watson static int 15988737be2SRobert Watson netisr_protoispresent(u_int proto) 16088737be2SRobert Watson { 16188737be2SRobert Watson u_int i; 16288737be2SRobert Watson 16388737be2SRobert Watson for (i = 0; i < proto_array_len; i++) { 16488737be2SRobert Watson if (proto_array[i].snp_proto == proto) 16588737be2SRobert Watson return (1); 16688737be2SRobert Watson } 16788737be2SRobert Watson return (0); 16888737be2SRobert Watson } 16988737be2SRobert Watson 17088737be2SRobert Watson static void 17188737be2SRobert Watson netisr_load_kvm_config(kvm_t *kd) 17288737be2SRobert Watson { 1738f092df0SRobert Watson u_int tmp; 17488737be2SRobert Watson 17588737be2SRobert Watson netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads); 17688737be2SRobert Watson netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads); 17788737be2SRobert Watson netisr_load_kvm_uint(kd, "_nws_count", &numthreads); 17888737be2SRobert Watson 17988737be2SRobert Watson netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit); 18088737be2SRobert Watson netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit); 18188737be2SRobert Watson 1828f092df0SRobert Watson netisr_load_kvm_uint(kd, "_netisr_dispatch_policy", &tmp); 1838f092df0SRobert Watson netisr_dispatch_policy_to_string(tmp, dispatch_policy, 1848f092df0SRobert Watson sizeof(dispatch_policy)); 18588737be2SRobert Watson } 18688737be2SRobert Watson 1870153eb66SRobert Watson static void 1880153eb66SRobert Watson netisr_load_sysctl_uint(const char *name, u_int *p) 1890153eb66SRobert Watson { 1900153eb66SRobert Watson size_t retlen; 1910153eb66SRobert Watson 1920153eb66SRobert Watson retlen = sizeof(u_int); 1930153eb66SRobert Watson if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) 194*ade9ccfeSMarcel Moolenaar xo_err(-1, "%s", name); 1950153eb66SRobert Watson if (retlen != sizeof(u_int)) 196*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen); 1970153eb66SRobert Watson } 1980153eb66SRobert Watson 1990153eb66SRobert Watson static void 2008f092df0SRobert Watson netisr_load_sysctl_string(const char *name, char *p, size_t len) 2018f092df0SRobert Watson { 2028f092df0SRobert Watson size_t retlen; 2038f092df0SRobert Watson 2048f092df0SRobert Watson retlen = len; 2058f092df0SRobert Watson if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) 206*ade9ccfeSMarcel Moolenaar xo_err(-1, "%s", name); 2078f092df0SRobert Watson p[len - 1] = '\0'; 2088f092df0SRobert Watson } 2098f092df0SRobert Watson 2108f092df0SRobert Watson static void 21188737be2SRobert Watson netisr_load_sysctl_config(void) 2120153eb66SRobert Watson { 2130153eb66SRobert Watson 2140153eb66SRobert Watson netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads); 2150153eb66SRobert Watson netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads); 2160153eb66SRobert Watson netisr_load_sysctl_uint("net.isr.numthreads", &numthreads); 2170153eb66SRobert Watson 2180153eb66SRobert Watson netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit); 2190153eb66SRobert Watson netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit); 2200153eb66SRobert Watson 2218f092df0SRobert Watson netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy, 2228f092df0SRobert Watson sizeof(dispatch_policy)); 2230153eb66SRobert Watson } 2240153eb66SRobert Watson 2250153eb66SRobert Watson static void 22688737be2SRobert Watson netisr_load_kvm_proto(kvm_t *kd) 22788737be2SRobert Watson { 22888737be2SRobert Watson struct nlist nl[] = { 22988737be2SRobert Watson #define NLIST_NETISR_PROTO 0 23088737be2SRobert Watson { .n_name = "_netisr_proto" }, 23188737be2SRobert Watson { .n_name = NULL }, 23288737be2SRobert Watson }; 23388737be2SRobert Watson struct netisr_proto *np_array, *npp; 23488737be2SRobert Watson u_int i, protocount; 23588737be2SRobert Watson struct sysctl_netisr_proto *snpp; 23688737be2SRobert Watson size_t len; 23788737be2SRobert Watson int ret; 23888737be2SRobert Watson 23988737be2SRobert Watson /* 24088737be2SRobert Watson * Kernel compile-time and user compile-time definitions of 24188737be2SRobert Watson * NETISR_MAXPROT must match, as we use that to size work arrays. 24288737be2SRobert Watson */ 24388737be2SRobert Watson netisr_load_kvm_uint(kd, "_netisr_maxprot", &maxprot); 24488737be2SRobert Watson if (maxprot != NETISR_MAXPROT) 245*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: NETISR_MAXPROT mismatch", __func__); 24688737be2SRobert Watson len = maxprot * sizeof(*np_array); 24788737be2SRobert Watson np_array = malloc(len); 24888737be2SRobert Watson if (np_array == NULL) 249*ade9ccfeSMarcel Moolenaar xo_err(-1, "%s: malloc", __func__); 25088737be2SRobert Watson ret = kvm_nlist(kd, nl); 25188737be2SRobert Watson if (ret < 0) 252*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist(_netisr_proto): %s", __func__, 25388737be2SRobert Watson kvm_geterr(kd)); 25488737be2SRobert Watson if (ret != 0) 255*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist(_netisr_proto): unresolved symbol", 25688737be2SRobert Watson __func__); 25788737be2SRobert Watson if (kvm_read(kd, nl[NLIST_NETISR_PROTO].n_value, np_array, len) != 25888737be2SRobert Watson (ssize_t)len) 259*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_read(_netisr_proto): %s", __func__, 26088737be2SRobert Watson kvm_geterr(kd)); 26188737be2SRobert Watson 26288737be2SRobert Watson /* 26388737be2SRobert Watson * Size and allocate memory to hold only live protocols. 26488737be2SRobert Watson */ 26588737be2SRobert Watson protocount = 0; 26688737be2SRobert Watson for (i = 0; i < maxprot; i++) { 26788737be2SRobert Watson if (np_array[i].np_name == NULL) 26888737be2SRobert Watson continue; 26988737be2SRobert Watson protocount++; 27088737be2SRobert Watson } 27188737be2SRobert Watson proto_array = calloc(protocount, sizeof(*proto_array)); 27288737be2SRobert Watson if (proto_array == NULL) 27388737be2SRobert Watson err(-1, "malloc"); 27488737be2SRobert Watson protocount = 0; 27588737be2SRobert Watson for (i = 0; i < maxprot; i++) { 27688737be2SRobert Watson npp = &np_array[i]; 27788737be2SRobert Watson if (npp->np_name == NULL) 27888737be2SRobert Watson continue; 27988737be2SRobert Watson snpp = &proto_array[protocount]; 28088737be2SRobert Watson snpp->snp_version = sizeof(*snpp); 28188737be2SRobert Watson netisr_load_kvm_string(kd, (uintptr_t)npp->np_name, 28288737be2SRobert Watson snpp->snp_name, sizeof(snpp->snp_name)); 28388737be2SRobert Watson snpp->snp_proto = i; 28488737be2SRobert Watson snpp->snp_qlimit = npp->np_qlimit; 28588737be2SRobert Watson snpp->snp_policy = npp->np_policy; 2868f092df0SRobert Watson snpp->snp_dispatch = npp->np_dispatch; 28788737be2SRobert Watson if (npp->np_m2flow != NULL) 28888737be2SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW; 28988737be2SRobert Watson if (npp->np_m2cpuid != NULL) 29088737be2SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID; 29188737be2SRobert Watson if (npp->np_drainedcpu != NULL) 29288737be2SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU; 29388737be2SRobert Watson protocount++; 29488737be2SRobert Watson } 29588737be2SRobert Watson proto_array_len = protocount; 29688737be2SRobert Watson free(np_array); 29788737be2SRobert Watson } 29888737be2SRobert Watson 29988737be2SRobert Watson static void 30088737be2SRobert Watson netisr_load_sysctl_proto(void) 3010153eb66SRobert Watson { 3020153eb66SRobert Watson size_t len; 3030153eb66SRobert Watson 3040153eb66SRobert Watson if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0) 305*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.proto: query len"); 3060153eb66SRobert Watson if (len % sizeof(*proto_array) != 0) 307*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.proto: invalid len"); 3080153eb66SRobert Watson proto_array = malloc(len); 3090153eb66SRobert Watson if (proto_array == NULL) 310*ade9ccfeSMarcel Moolenaar xo_err(-1, "malloc"); 3110153eb66SRobert Watson if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0) 312*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.proto: query data"); 3130153eb66SRobert Watson if (len % sizeof(*proto_array) != 0) 314*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.proto: invalid len"); 3150153eb66SRobert Watson proto_array_len = len / sizeof(*proto_array); 3160153eb66SRobert Watson if (proto_array_len < 1) 317*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.proto: no data"); 3180153eb66SRobert Watson if (proto_array[0].snp_version != sizeof(proto_array[0])) 319*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.proto: invalid version"); 3200153eb66SRobert Watson } 3210153eb66SRobert Watson 3220153eb66SRobert Watson static void 32388737be2SRobert Watson netisr_load_kvm_workstream(kvm_t *kd) 32488737be2SRobert Watson { 32588737be2SRobert Watson struct nlist nl[] = { 32688737be2SRobert Watson #define NLIST_NWS_ARRAY 0 32788737be2SRobert Watson { .n_name = "_nws_array" }, 32888737be2SRobert Watson { .n_name = NULL }, 32988737be2SRobert Watson }; 33088737be2SRobert Watson struct netisr_workstream nws; 33188737be2SRobert Watson struct sysctl_netisr_workstream *snwsp; 33288737be2SRobert Watson struct sysctl_netisr_work *snwp; 33388737be2SRobert Watson struct netisr_work *nwp; 33488737be2SRobert Watson struct nlist nl_nws[2]; 33588737be2SRobert Watson u_int counter, cpuid, proto, wsid; 33688737be2SRobert Watson size_t len; 33788737be2SRobert Watson int ret; 33888737be2SRobert Watson 33988737be2SRobert Watson len = numthreads * sizeof(*nws_array); 34088737be2SRobert Watson nws_array = malloc(len); 34188737be2SRobert Watson if (nws_array == NULL) 342*ade9ccfeSMarcel Moolenaar xo_err(-1, "malloc"); 34388737be2SRobert Watson ret = kvm_nlist(kd, nl); 34488737be2SRobert Watson if (ret < 0) 345*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist: %s", __func__, kvm_geterr(kd)); 34688737be2SRobert Watson if (ret != 0) 347*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist: unresolved symbol", __func__); 34888737be2SRobert Watson if (kvm_read(kd, nl[NLIST_NWS_ARRAY].n_value, nws_array, len) != 34988737be2SRobert Watson (ssize_t)len) 350*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_read(_nws_array): %s", __func__, 35188737be2SRobert Watson kvm_geterr(kd)); 35288737be2SRobert Watson workstream_array = calloc(numthreads, sizeof(*workstream_array)); 35388737be2SRobert Watson if (workstream_array == NULL) 354*ade9ccfeSMarcel Moolenaar xo_err(-1, "calloc"); 35588737be2SRobert Watson workstream_array_len = numthreads; 35688737be2SRobert Watson work_array = calloc(numthreads * proto_array_len, sizeof(*work_array)); 35788737be2SRobert Watson if (work_array == NULL) 358*ade9ccfeSMarcel Moolenaar xo_err(-1, "calloc"); 35988737be2SRobert Watson counter = 0; 36088737be2SRobert Watson for (wsid = 0; wsid < numthreads; wsid++) { 36188737be2SRobert Watson cpuid = nws_array[wsid]; 36288737be2SRobert Watson if (kvm_dpcpu_setcpu(kd, cpuid) < 0) 363*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__, 36488737be2SRobert Watson cpuid, kvm_geterr(kd)); 36588737be2SRobert Watson bzero(nl_nws, sizeof(nl_nws)); 36688737be2SRobert Watson nl_nws[0].n_name = "_nws"; 36788737be2SRobert Watson ret = kvm_nlist(kd, nl_nws); 36888737be2SRobert Watson if (ret < 0) 369*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist looking up nws on CPU " 370*ade9ccfeSMarcel Moolenaar "%u: %s", __func__, cpuid, kvm_geterr(kd)); 37188737be2SRobert Watson if (ret != 0) 372*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_nlist(nws): unresolved symbol on " 37388737be2SRobert Watson "CPU %u", __func__, cpuid); 37488737be2SRobert Watson if (kvm_read(kd, nl_nws[0].n_value, &nws, sizeof(nws)) != 37588737be2SRobert Watson sizeof(nws)) 376*ade9ccfeSMarcel Moolenaar xo_errx(-1, "%s: kvm_read(nw): %s", __func__, 37788737be2SRobert Watson kvm_geterr(kd)); 37888737be2SRobert Watson snwsp = &workstream_array[wsid]; 37988737be2SRobert Watson snwsp->snws_version = sizeof(*snwsp); 38088737be2SRobert Watson snwsp->snws_wsid = cpuid; 38188737be2SRobert Watson snwsp->snws_cpu = cpuid; 38288737be2SRobert Watson if (nws.nws_intr_event != NULL) 38388737be2SRobert Watson snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR; 38488737be2SRobert Watson 38588737be2SRobert Watson /* 38688737be2SRobert Watson * Extract the CPU's per-protocol work information. 38788737be2SRobert Watson */ 388*ade9ccfeSMarcel Moolenaar xo_emit("counting to maxprot: {:maxprot/%u}\n", maxprot); 38988737be2SRobert Watson for (proto = 0; proto < maxprot; proto++) { 39088737be2SRobert Watson if (!netisr_protoispresent(proto)) 39188737be2SRobert Watson continue; 39288737be2SRobert Watson nwp = &nws.nws_work[proto]; 39388737be2SRobert Watson snwp = &work_array[counter]; 39488737be2SRobert Watson snwp->snw_version = sizeof(*snwp); 39588737be2SRobert Watson snwp->snw_wsid = cpuid; 39688737be2SRobert Watson snwp->snw_proto = proto; 39788737be2SRobert Watson snwp->snw_len = nwp->nw_len; 39888737be2SRobert Watson snwp->snw_watermark = nwp->nw_watermark; 39988737be2SRobert Watson snwp->snw_dispatched = nwp->nw_dispatched; 40088737be2SRobert Watson snwp->snw_hybrid_dispatched = 40188737be2SRobert Watson nwp->nw_hybrid_dispatched; 40288737be2SRobert Watson snwp->snw_qdrops = nwp->nw_qdrops; 40388737be2SRobert Watson snwp->snw_queued = nwp->nw_queued; 40488737be2SRobert Watson snwp->snw_handled = nwp->nw_handled; 40588737be2SRobert Watson counter++; 40688737be2SRobert Watson } 40788737be2SRobert Watson } 40888737be2SRobert Watson work_array_len = counter; 40988737be2SRobert Watson } 41088737be2SRobert Watson 41188737be2SRobert Watson static void 41288737be2SRobert Watson netisr_load_sysctl_workstream(void) 4130153eb66SRobert Watson { 4140153eb66SRobert Watson size_t len; 4150153eb66SRobert Watson 4160153eb66SRobert Watson if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0) 417*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.workstream: query len"); 4180153eb66SRobert Watson if (len % sizeof(*workstream_array) != 0) 419*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.workstream: invalid len"); 4200153eb66SRobert Watson workstream_array = malloc(len); 4210153eb66SRobert Watson if (workstream_array == NULL) 422*ade9ccfeSMarcel Moolenaar xo_err(-1, "malloc"); 4230153eb66SRobert Watson if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL, 4240153eb66SRobert Watson 0) < 0) 425*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.workstream: query data"); 4260153eb66SRobert Watson if (len % sizeof(*workstream_array) != 0) 427*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.workstream: invalid len"); 4280153eb66SRobert Watson workstream_array_len = len / sizeof(*workstream_array); 4290153eb66SRobert Watson if (workstream_array_len < 1) 430*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.workstream: no data"); 4310153eb66SRobert Watson if (workstream_array[0].snws_version != sizeof(workstream_array[0])) 432*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.workstream: invalid version"); 4330153eb66SRobert Watson } 4340153eb66SRobert Watson 4350153eb66SRobert Watson static void 43688737be2SRobert Watson netisr_load_sysctl_work(void) 4370153eb66SRobert Watson { 4380153eb66SRobert Watson size_t len; 4390153eb66SRobert Watson 4400153eb66SRobert Watson if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0) 441*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.work: query len"); 4420153eb66SRobert Watson if (len % sizeof(*work_array) != 0) 443*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.work: invalid len"); 4440153eb66SRobert Watson work_array = malloc(len); 4450153eb66SRobert Watson if (work_array == NULL) 446*ade9ccfeSMarcel Moolenaar xo_err(-1, "malloc"); 4470153eb66SRobert Watson if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0) 448*ade9ccfeSMarcel Moolenaar xo_err(-1, "net.isr.work: query data"); 4490153eb66SRobert Watson if (len % sizeof(*work_array) != 0) 450*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.work: invalid len"); 4510153eb66SRobert Watson work_array_len = len / sizeof(*work_array); 4520153eb66SRobert Watson if (work_array_len < 1) 453*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.work: no data"); 4540153eb66SRobert Watson if (work_array[0].snw_version != sizeof(work_array[0])) 455*ade9ccfeSMarcel Moolenaar xo_errx(-1, "net.isr.work: invalid version"); 4560153eb66SRobert Watson } 4570153eb66SRobert Watson 4580153eb66SRobert Watson static void 4590153eb66SRobert Watson netisr_print_proto(struct sysctl_netisr_proto *snpp) 4600153eb66SRobert Watson { 4618f092df0SRobert Watson char tmp[20]; 4620153eb66SRobert Watson 463*ade9ccfeSMarcel Moolenaar xo_emit("{[:-6}{k:name/%s}{]:}", snpp->snp_name); 464*ade9ccfeSMarcel Moolenaar xo_emit(" {:protocol/%5u}", snpp->snp_proto); 465*ade9ccfeSMarcel Moolenaar xo_emit(" {:queue-limit/%6u}", snpp->snp_qlimit); 466*ade9ccfeSMarcel Moolenaar xo_emit(" {:policy-type/%6s}", 4670153eb66SRobert Watson (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" : 4680153eb66SRobert Watson (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" : 4690153eb66SRobert Watson (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-"); 4708f092df0SRobert Watson netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp, 4718f092df0SRobert Watson sizeof(tmp)); 472*ade9ccfeSMarcel Moolenaar xo_emit(" {:policy/%8s}", tmp); 473*ade9ccfeSMarcel Moolenaar xo_emit(" {:flags/%s%s%s}\n", 4740153eb66SRobert Watson (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-", 4750153eb66SRobert Watson (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-", 4760153eb66SRobert Watson (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-"); 4770153eb66SRobert Watson } 4780153eb66SRobert Watson 4790153eb66SRobert Watson static void 4800153eb66SRobert Watson netisr_print_workstream(struct sysctl_netisr_workstream *snwsp) 4810153eb66SRobert Watson { 4820153eb66SRobert Watson struct sysctl_netisr_work *snwp; 4830153eb66SRobert Watson u_int i; 4840153eb66SRobert Watson 485*ade9ccfeSMarcel Moolenaar xo_open_list("work"); 4860153eb66SRobert Watson for (i = 0; i < work_array_len; i++) { 4870153eb66SRobert Watson snwp = &work_array[i]; 4880153eb66SRobert Watson if (snwp->snw_wsid != snwsp->snws_wsid) 4890153eb66SRobert Watson continue; 490*ade9ccfeSMarcel Moolenaar xo_open_instance("work"); 491*ade9ccfeSMarcel Moolenaar xo_emit("{t:workstream/%4u} ", snwsp->snws_wsid); 492*ade9ccfeSMarcel Moolenaar xo_emit("{t:cpu/%3u} ", snwsp->snws_cpu); 493*ade9ccfeSMarcel Moolenaar xo_emit("{P: }"); 494*ade9ccfeSMarcel Moolenaar xo_emit("{t:name/%-6s}", netisr_proto2name(snwp->snw_proto)); 495*ade9ccfeSMarcel Moolenaar xo_emit(" {t:length/%5u}", snwp->snw_len); 496*ade9ccfeSMarcel Moolenaar xo_emit(" {t:watermark/%5u}", snwp->snw_watermark); 497*ade9ccfeSMarcel Moolenaar xo_emit(" {t:dispatched/%8ju}", snwp->snw_dispatched); 498*ade9ccfeSMarcel Moolenaar xo_emit(" {t:hybrid-dispatched/%8ju}", 499*ade9ccfeSMarcel Moolenaar snwp->snw_hybrid_dispatched); 500*ade9ccfeSMarcel Moolenaar xo_emit(" {t:queue-drops/%8ju}", snwp->snw_qdrops); 501*ade9ccfeSMarcel Moolenaar xo_emit(" {t:queued/%8ju}", snwp->snw_queued); 502*ade9ccfeSMarcel Moolenaar xo_emit(" {t:handled/%8ju}", snwp->snw_handled); 503*ade9ccfeSMarcel Moolenaar xo_emit("\n"); 504*ade9ccfeSMarcel Moolenaar xo_close_instance("work"); 5050153eb66SRobert Watson } 506*ade9ccfeSMarcel Moolenaar xo_close_list("work"); 5070153eb66SRobert Watson } 5080153eb66SRobert Watson 5090153eb66SRobert Watson void 51088737be2SRobert Watson netisr_stats(void *kvmd) 5110153eb66SRobert Watson { 5120153eb66SRobert Watson struct sysctl_netisr_workstream *snwsp; 5130153eb66SRobert Watson struct sysctl_netisr_proto *snpp; 51488737be2SRobert Watson kvm_t *kd = kvmd; 5150153eb66SRobert Watson u_int i; 5160153eb66SRobert Watson 51788737be2SRobert Watson if (live) { 51888737be2SRobert Watson netisr_load_sysctl_config(); 51988737be2SRobert Watson netisr_load_sysctl_proto(); 52088737be2SRobert Watson netisr_load_sysctl_workstream(); 52188737be2SRobert Watson netisr_load_sysctl_work(); 52288737be2SRobert Watson } else { 52388737be2SRobert Watson if (kd == NULL) 524*ade9ccfeSMarcel Moolenaar xo_errx(-1, "netisr_stats: !live but !kd"); 52588737be2SRobert Watson netisr_load_kvm_config(kd); 52688737be2SRobert Watson netisr_load_kvm_proto(kd); 52788737be2SRobert Watson netisr_load_kvm_workstream(kd); /* Also does work. */ 52888737be2SRobert Watson } 5290153eb66SRobert Watson 530*ade9ccfeSMarcel Moolenaar xo_open_container("netisr"); 5310153eb66SRobert Watson 532*ade9ccfeSMarcel Moolenaar xo_emit("{T:Configuration}:\n"); 533*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", 534*ade9ccfeSMarcel Moolenaar "Setting", "Current", "Limit"); 535*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n", 536*ade9ccfeSMarcel Moolenaar "Thread count", numthreads, maxthreads); 537*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n", 538*ade9ccfeSMarcel Moolenaar "Default queue limit", defaultqlimit, maxqlimit); 539*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", 540*ade9ccfeSMarcel Moolenaar "Dispatch policy", dispatch_policy, "n/a"); 541*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n", 542*ade9ccfeSMarcel Moolenaar "Threads bound to CPUs", bindthreads ? "enabled" : "disabled", 543*ade9ccfeSMarcel Moolenaar "n/a"); 544*ade9ccfeSMarcel Moolenaar xo_emit("\n"); 545*ade9ccfeSMarcel Moolenaar 546*ade9ccfeSMarcel Moolenaar xo_emit("{T:Protocols}:\n"); 547*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-6s} {T:/%5s} {T:/%6s} {T:/%-6s} {T:/%-8s} {T:/%-5s}\n", 548*ade9ccfeSMarcel Moolenaar "Name", "Proto", "QLimit", "Policy", "Dispatch", "Flags"); 549*ade9ccfeSMarcel Moolenaar xo_open_list("protocol"); 5500153eb66SRobert Watson for (i = 0; i < proto_array_len; i++) { 551*ade9ccfeSMarcel Moolenaar xo_open_instance("protocol"); 5520153eb66SRobert Watson snpp = &proto_array[i]; 5530153eb66SRobert Watson netisr_print_proto(snpp); 554*ade9ccfeSMarcel Moolenaar xo_close_instance("protocol"); 5550153eb66SRobert Watson } 556*ade9ccfeSMarcel Moolenaar xo_close_list("protocol"); 557*ade9ccfeSMarcel Moolenaar xo_emit("\n"); 5580153eb66SRobert Watson 559*ade9ccfeSMarcel Moolenaar xo_emit("{T:Workstreams}:\n"); 560*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%4s} {T:/%3s} ", "WSID", "CPU"); 561*ade9ccfeSMarcel Moolenaar xo_emit("{P:/%2s}", ""); 562*ade9ccfeSMarcel Moolenaar xo_emit("{T:/%-6s} {T:/%5s} {T:/%5s} {T:/%8s} {T:/%8s} {T:/%8s} " 563*ade9ccfeSMarcel Moolenaar "{T:/%8s} {T:/%8s}\n", 564*ade9ccfeSMarcel Moolenaar "Name", "Len", "WMark", "Disp'd", "HDisp'd", "QDrops", "Queued", 565*ade9ccfeSMarcel Moolenaar "Handled"); 566*ade9ccfeSMarcel Moolenaar xo_open_list("workstream"); 5670153eb66SRobert Watson for (i = 0; i < workstream_array_len; i++) { 568*ade9ccfeSMarcel Moolenaar xo_open_instance("workstream"); 5690153eb66SRobert Watson snwsp = &workstream_array[i]; 5700153eb66SRobert Watson netisr_print_workstream(snwsp); 571*ade9ccfeSMarcel Moolenaar xo_close_instance("workstream"); 5720153eb66SRobert Watson } 573*ade9ccfeSMarcel Moolenaar xo_close_list("workstream"); 574*ade9ccfeSMarcel Moolenaar xo_close_container("netisr"); 5750153eb66SRobert Watson } 576