xref: /freebsd/usr.bin/netstat/netisr.c (revision 95968ea7ec8f1cd3c1d03cc56c704cb2392d0d25)
10153eb66SRobert Watson /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
47ff67a20SRobert Watson  * Copyright (c) 2010-2011 Juniper Networks, Inc.
50153eb66SRobert Watson  * All rights reserved.
60153eb66SRobert Watson  *
70153eb66SRobert Watson  * This software was developed by Robert N. M. Watson under contract
80153eb66SRobert Watson  * to Juniper Networks, Inc.
90153eb66SRobert Watson  *
100153eb66SRobert Watson  * Redistribution and use in source and binary forms, with or without
110153eb66SRobert Watson  * modification, are permitted provided that the following conditions
120153eb66SRobert Watson  * are met:
130153eb66SRobert Watson  * 1. Redistributions of source code must retain the above copyright
140153eb66SRobert Watson  *    notice, this list of conditions and the following disclaimer.
150153eb66SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
160153eb66SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
170153eb66SRobert Watson  *    documentation and/or other materials provided with the distribution.
180153eb66SRobert Watson  *
190153eb66SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
200153eb66SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
210153eb66SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
220153eb66SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
230153eb66SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
240153eb66SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
250153eb66SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
260153eb66SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
270153eb66SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
280153eb66SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
290153eb66SRobert Watson  * SUCH DAMAGE.
300153eb66SRobert Watson  */
310153eb66SRobert Watson 
320153eb66SRobert Watson 
3388737be2SRobert Watson #include <sys/param.h>
340153eb66SRobert Watson #include <sys/sysctl.h>
350153eb66SRobert Watson 
3688737be2SRobert Watson #include <sys/_lock.h>
3788737be2SRobert Watson #include <sys/_mutex.h>
3888737be2SRobert Watson 
3988737be2SRobert Watson #define	_WANT_NETISR_INTERNAL
400153eb66SRobert Watson #include <net/netisr.h>
4188737be2SRobert Watson #include <net/netisr_internal.h>
420153eb66SRobert Watson 
430153eb66SRobert Watson #include <stdint.h>
440153eb66SRobert Watson #include <stdio.h>
450153eb66SRobert Watson #include <stdlib.h>
46ade9ccfeSMarcel Moolenaar #include <stdbool.h>
4788737be2SRobert Watson #include <string.h>
48*95968ea7SYan-Hao Wang #include <sysexits.h>
49ade9ccfeSMarcel Moolenaar #include <libxo/xo.h>
500153eb66SRobert Watson #include "netstat.h"
5181dacd8bSHiroki Sato #include "nl_defs.h"
520153eb66SRobert Watson 
530153eb66SRobert Watson /*
540153eb66SRobert Watson  * Print statistics for the kernel netisr subsystem.
550153eb66SRobert Watson  */
560153eb66SRobert Watson static u_int				 bindthreads;
570153eb66SRobert Watson static u_int				 maxthreads;
580153eb66SRobert Watson static u_int				 numthreads;
590153eb66SRobert Watson 
600153eb66SRobert Watson static u_int				 defaultqlimit;
610153eb66SRobert Watson static u_int				 maxqlimit;
620153eb66SRobert Watson 
638f092df0SRobert Watson static char				 dispatch_policy[20];
640153eb66SRobert Watson 
650153eb66SRobert Watson static struct sysctl_netisr_proto	*proto_array;
660153eb66SRobert Watson static u_int				 proto_array_len;
670153eb66SRobert Watson 
680153eb66SRobert Watson static struct sysctl_netisr_workstream	*workstream_array;
690153eb66SRobert Watson static u_int				 workstream_array_len;
700153eb66SRobert Watson 
710153eb66SRobert Watson static struct sysctl_netisr_work	*work_array;
720153eb66SRobert Watson static u_int				 work_array_len;
730153eb66SRobert Watson 
7488737be2SRobert Watson static u_int				*nws_array;
7588737be2SRobert Watson 
7688737be2SRobert Watson static u_int				 maxprot;
7788737be2SRobert Watson 
7888737be2SRobert Watson static void
netisr_dispatch_policy_to_string(u_int policy,char * buf,size_t buflen)79321ae07fSPhilippe Charnier netisr_dispatch_policy_to_string(u_int policy, char *buf,
808f092df0SRobert Watson     size_t buflen)
818f092df0SRobert Watson {
828f092df0SRobert Watson 	const char *str;
838f092df0SRobert Watson 
84321ae07fSPhilippe Charnier 	switch (policy) {
858f092df0SRobert Watson 	case NETISR_DISPATCH_DEFAULT:
868f092df0SRobert Watson 		str = "default";
878f092df0SRobert Watson 		break;
888f092df0SRobert Watson 	case NETISR_DISPATCH_DEFERRED:
898f092df0SRobert Watson 		str = "deferred";
908f092df0SRobert Watson 		break;
918f092df0SRobert Watson 	case NETISR_DISPATCH_HYBRID:
928f092df0SRobert Watson 		str = "hybrid";
938f092df0SRobert Watson 		break;
948f092df0SRobert Watson 	case NETISR_DISPATCH_DIRECT:
958f092df0SRobert Watson 		str = "direct";
968f092df0SRobert Watson 		break;
978f092df0SRobert Watson 	default:
988f092df0SRobert Watson 		str = "unknown";
998f092df0SRobert Watson 		break;
1008f092df0SRobert Watson 	}
1018f092df0SRobert Watson 	snprintf(buf, buflen, "%s", str);
1028f092df0SRobert Watson }
1038f092df0SRobert Watson 
10488737be2SRobert Watson /*
10588737be2SRobert Watson  * Load a nul-terminated string from KVM up to 'limit', guarantee that the
10688737be2SRobert Watson  * string in local memory is nul-terminated.
10788737be2SRobert Watson  */
10888737be2SRobert Watson static void
netisr_load_kvm_string(uintptr_t addr,char * dest,u_int limit)10981dacd8bSHiroki Sato netisr_load_kvm_string(uintptr_t addr, char *dest, u_int limit)
11088737be2SRobert Watson {
11188737be2SRobert Watson 	u_int i;
11288737be2SRobert Watson 
11388737be2SRobert Watson 	for (i = 0; i < limit; i++) {
11481dacd8bSHiroki Sato 		if (kread(addr + i, &dest[i], sizeof(dest[i])) != 0)
115*95968ea7SYan-Hao Wang 			xo_errx(EX_OSERR, "%s: kread()", __func__);
11688737be2SRobert Watson 		if (dest[i] == '\0')
11788737be2SRobert Watson 			break;
11888737be2SRobert Watson 	}
11988737be2SRobert Watson 	dest[limit - 1] = '\0';
12088737be2SRobert Watson }
12188737be2SRobert Watson 
12288737be2SRobert Watson static const char *
netisr_proto2name(u_int proto)12388737be2SRobert Watson netisr_proto2name(u_int proto)
12488737be2SRobert Watson {
12588737be2SRobert Watson 	u_int i;
12688737be2SRobert Watson 
12788737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
12888737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
12988737be2SRobert Watson 			return (proto_array[i].snp_name);
13088737be2SRobert Watson 	}
13188737be2SRobert Watson 	return ("unknown");
13288737be2SRobert Watson }
13388737be2SRobert Watson 
13488737be2SRobert Watson static int
netisr_protoispresent(u_int proto)13588737be2SRobert Watson netisr_protoispresent(u_int proto)
13688737be2SRobert Watson {
13788737be2SRobert Watson 	u_int i;
13888737be2SRobert Watson 
13988737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
14088737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
14188737be2SRobert Watson 			return (1);
14288737be2SRobert Watson 	}
14388737be2SRobert Watson 	return (0);
14488737be2SRobert Watson }
14588737be2SRobert Watson 
14688737be2SRobert Watson static void
netisr_load_kvm_config(void)14781dacd8bSHiroki Sato netisr_load_kvm_config(void)
14888737be2SRobert Watson {
1498f092df0SRobert Watson 	u_int tmp;
15088737be2SRobert Watson 
15181dacd8bSHiroki Sato 	kread(nl[N_NETISR_BINDTHREADS].n_value, &bindthreads, sizeof(u_int));
15281dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXTHREADS].n_value, &maxthreads, sizeof(u_int));
15381dacd8bSHiroki Sato 	kread(nl[N_NWS_COUNT].n_value, &numthreads, sizeof(u_int));
15481dacd8bSHiroki Sato 	kread(nl[N_NETISR_DEFAULTQLIMIT].n_value, &defaultqlimit,
15581dacd8bSHiroki Sato 	    sizeof(u_int));
15681dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXQLIMIT].n_value, &maxqlimit, sizeof(u_int));
15781dacd8bSHiroki Sato 	kread(nl[N_NETISR_DISPATCH_POLICY].n_value, &tmp, sizeof(u_int));
15888737be2SRobert Watson 
1598f092df0SRobert Watson 	netisr_dispatch_policy_to_string(tmp, dispatch_policy,
1608f092df0SRobert Watson 	    sizeof(dispatch_policy));
16188737be2SRobert Watson }
16288737be2SRobert Watson 
1630153eb66SRobert Watson static void
netisr_load_sysctl_uint(const char * name,u_int * p)1640153eb66SRobert Watson netisr_load_sysctl_uint(const char *name, u_int *p)
1650153eb66SRobert Watson {
1660153eb66SRobert Watson 	size_t retlen;
1670153eb66SRobert Watson 
1680153eb66SRobert Watson 	retlen = sizeof(u_int);
1690153eb66SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
170*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "%s", name);
1710153eb66SRobert Watson 	if (retlen != sizeof(u_int))
172*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "%s: invalid len %ju", name, (uintmax_t)retlen);
1730153eb66SRobert Watson }
1740153eb66SRobert Watson 
1750153eb66SRobert Watson static void
netisr_load_sysctl_string(const char * name,char * p,size_t len)1768f092df0SRobert Watson netisr_load_sysctl_string(const char *name, char *p, size_t len)
1778f092df0SRobert Watson {
1788f092df0SRobert Watson 	size_t retlen;
1798f092df0SRobert Watson 
1808f092df0SRobert Watson 	retlen = len;
1818f092df0SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
182*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "%s", name);
1838f092df0SRobert Watson 	p[len - 1] = '\0';
1848f092df0SRobert Watson }
1858f092df0SRobert Watson 
1868f092df0SRobert Watson static void
netisr_load_sysctl_config(void)18788737be2SRobert Watson netisr_load_sysctl_config(void)
1880153eb66SRobert Watson {
1890153eb66SRobert Watson 
1900153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads);
1910153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads);
1920153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.numthreads", &numthreads);
1930153eb66SRobert Watson 
1940153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
1950153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
1960153eb66SRobert Watson 
1978f092df0SRobert Watson 	netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy,
1988f092df0SRobert Watson 	    sizeof(dispatch_policy));
1990153eb66SRobert Watson }
2000153eb66SRobert Watson 
2010153eb66SRobert Watson static void
netisr_load_kvm_proto(void)20281dacd8bSHiroki Sato netisr_load_kvm_proto(void)
20388737be2SRobert Watson {
20488737be2SRobert Watson 	struct netisr_proto *np_array, *npp;
20588737be2SRobert Watson 	u_int i, protocount;
20688737be2SRobert Watson 	struct sysctl_netisr_proto *snpp;
20788737be2SRobert Watson 	size_t len;
20888737be2SRobert Watson 
20988737be2SRobert Watson 	/*
21088737be2SRobert Watson 	 * Kernel compile-time and user compile-time definitions of
21188737be2SRobert Watson 	 * NETISR_MAXPROT must match, as we use that to size work arrays.
21288737be2SRobert Watson 	 */
21381dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXPROT].n_value, &maxprot, sizeof(u_int));
21488737be2SRobert Watson 	if (maxprot != NETISR_MAXPROT)
215*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "%s: NETISR_MAXPROT mismatch", __func__);
21688737be2SRobert Watson 	len = maxprot * sizeof(*np_array);
21788737be2SRobert Watson 	np_array = malloc(len);
21888737be2SRobert Watson 	if (np_array == NULL)
219*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "%s: malloc", __func__);
22081dacd8bSHiroki Sato 	if (kread(nl[N_NETISR_PROTO].n_value, np_array, len) != 0)
221*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "%s: kread(_netisr_proto)", __func__);
22288737be2SRobert Watson 
22388737be2SRobert Watson 	/*
22488737be2SRobert Watson 	 * Size and allocate memory to hold only live protocols.
22588737be2SRobert Watson 	 */
22688737be2SRobert Watson 	protocount = 0;
22788737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
22888737be2SRobert Watson 		if (np_array[i].np_name == NULL)
22988737be2SRobert Watson 			continue;
23088737be2SRobert Watson 		protocount++;
23188737be2SRobert Watson 	}
23288737be2SRobert Watson 	proto_array = calloc(protocount, sizeof(*proto_array));
23388737be2SRobert Watson 	if (proto_array == NULL)
234*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "malloc");
23588737be2SRobert Watson 	protocount = 0;
23688737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
23788737be2SRobert Watson 		npp = &np_array[i];
23888737be2SRobert Watson 		if (npp->np_name == NULL)
23988737be2SRobert Watson 			continue;
24088737be2SRobert Watson 		snpp = &proto_array[protocount];
24188737be2SRobert Watson 		snpp->snp_version = sizeof(*snpp);
24281dacd8bSHiroki Sato 		netisr_load_kvm_string((uintptr_t)npp->np_name,
24388737be2SRobert Watson 		    snpp->snp_name, sizeof(snpp->snp_name));
24488737be2SRobert Watson 		snpp->snp_proto = i;
24588737be2SRobert Watson 		snpp->snp_qlimit = npp->np_qlimit;
24688737be2SRobert Watson 		snpp->snp_policy = npp->np_policy;
2478f092df0SRobert Watson 		snpp->snp_dispatch = npp->np_dispatch;
24888737be2SRobert Watson 		if (npp->np_m2flow != NULL)
24988737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
25088737be2SRobert Watson 		if (npp->np_m2cpuid != NULL)
25188737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
25288737be2SRobert Watson 		if (npp->np_drainedcpu != NULL)
25388737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
25488737be2SRobert Watson 		protocount++;
25588737be2SRobert Watson 	}
25688737be2SRobert Watson 	proto_array_len = protocount;
25788737be2SRobert Watson 	free(np_array);
25888737be2SRobert Watson }
25988737be2SRobert Watson 
26088737be2SRobert Watson static void
netisr_load_sysctl_proto(void)26188737be2SRobert Watson netisr_load_sysctl_proto(void)
2620153eb66SRobert Watson {
2630153eb66SRobert Watson 	size_t len;
2640153eb66SRobert Watson 
2650153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0)
266*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.proto: query len");
2670153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
268*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.proto: invalid len");
2690153eb66SRobert Watson 	proto_array = malloc(len);
2700153eb66SRobert Watson 	if (proto_array == NULL)
271*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "malloc");
2720153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0)
273*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.proto: query data");
2740153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
275*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.proto: invalid len");
2760153eb66SRobert Watson 	proto_array_len = len / sizeof(*proto_array);
2770153eb66SRobert Watson 	if (proto_array_len < 1)
278*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.proto: no data");
2790153eb66SRobert Watson 	if (proto_array[0].snp_version != sizeof(proto_array[0]))
280*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.proto: invalid version");
2810153eb66SRobert Watson }
2820153eb66SRobert Watson 
2830153eb66SRobert Watson static void
netisr_load_kvm_workstream(void)28481dacd8bSHiroki Sato netisr_load_kvm_workstream(void)
28588737be2SRobert Watson {
28688737be2SRobert Watson 	struct netisr_workstream nws;
28788737be2SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
28888737be2SRobert Watson 	struct sysctl_netisr_work *snwp;
28988737be2SRobert Watson 	struct netisr_work *nwp;
29088737be2SRobert Watson 	u_int counter, cpuid, proto, wsid;
29188737be2SRobert Watson 	size_t len;
29288737be2SRobert Watson 
29388737be2SRobert Watson 	len = numthreads * sizeof(*nws_array);
29488737be2SRobert Watson 	nws_array = malloc(len);
29588737be2SRobert Watson 	if (nws_array == NULL)
296*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "malloc");
29781dacd8bSHiroki Sato 	if (kread(nl[N_NWS_ARRAY].n_value, nws_array, len) != 0)
298*95968ea7SYan-Hao Wang 		xo_errx(EX_OSERR, "%s: kread(_nws_array)", __func__);
29988737be2SRobert Watson 	workstream_array = calloc(numthreads, sizeof(*workstream_array));
30088737be2SRobert Watson 	if (workstream_array == NULL)
301*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "calloc");
30288737be2SRobert Watson 	workstream_array_len = numthreads;
30388737be2SRobert Watson 	work_array = calloc(numthreads * proto_array_len, sizeof(*work_array));
30488737be2SRobert Watson 	if (work_array == NULL)
305*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "calloc");
30688737be2SRobert Watson 	counter = 0;
30788737be2SRobert Watson 	for (wsid = 0; wsid < numthreads; wsid++) {
30888737be2SRobert Watson 		cpuid = nws_array[wsid];
30981dacd8bSHiroki Sato 		kset_dpcpu(cpuid);
31081dacd8bSHiroki Sato 		if (kread(nl[N_NWS].n_value, &nws, sizeof(nws)) != 0)
311*95968ea7SYan-Hao Wang 			xo_errx(EX_OSERR, "%s: kread(nw)", __func__);
31288737be2SRobert Watson 		snwsp = &workstream_array[wsid];
31388737be2SRobert Watson 		snwsp->snws_version = sizeof(*snwsp);
31488737be2SRobert Watson 		snwsp->snws_wsid = cpuid;
31588737be2SRobert Watson 		snwsp->snws_cpu = cpuid;
31688737be2SRobert Watson 		if (nws.nws_intr_event != NULL)
31788737be2SRobert Watson 			snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
31888737be2SRobert Watson 
31988737be2SRobert Watson 		/*
32088737be2SRobert Watson 		 * Extract the CPU's per-protocol work information.
32188737be2SRobert Watson 		 */
322ade9ccfeSMarcel Moolenaar 		xo_emit("counting to maxprot: {:maxprot/%u}\n", maxprot);
32388737be2SRobert Watson 		for (proto = 0; proto < maxprot; proto++) {
32488737be2SRobert Watson 			if (!netisr_protoispresent(proto))
32588737be2SRobert Watson 				continue;
32688737be2SRobert Watson 			nwp = &nws.nws_work[proto];
32788737be2SRobert Watson 			snwp = &work_array[counter];
32888737be2SRobert Watson 			snwp->snw_version = sizeof(*snwp);
32988737be2SRobert Watson 			snwp->snw_wsid = cpuid;
33088737be2SRobert Watson 			snwp->snw_proto = proto;
33188737be2SRobert Watson 			snwp->snw_len = nwp->nw_len;
33288737be2SRobert Watson 			snwp->snw_watermark = nwp->nw_watermark;
33388737be2SRobert Watson 			snwp->snw_dispatched = nwp->nw_dispatched;
33488737be2SRobert Watson 			snwp->snw_hybrid_dispatched =
33588737be2SRobert Watson 			    nwp->nw_hybrid_dispatched;
33688737be2SRobert Watson 			snwp->snw_qdrops = nwp->nw_qdrops;
33788737be2SRobert Watson 			snwp->snw_queued = nwp->nw_queued;
33888737be2SRobert Watson 			snwp->snw_handled = nwp->nw_handled;
33988737be2SRobert Watson 			counter++;
34088737be2SRobert Watson 		}
34188737be2SRobert Watson 	}
34288737be2SRobert Watson 	work_array_len = counter;
34388737be2SRobert Watson }
34488737be2SRobert Watson 
34588737be2SRobert Watson static void
netisr_load_sysctl_workstream(void)34688737be2SRobert Watson netisr_load_sysctl_workstream(void)
3470153eb66SRobert Watson {
3480153eb66SRobert Watson 	size_t len;
3490153eb66SRobert Watson 
3500153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0)
351*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.workstream: query len");
3520153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
353*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.workstream: invalid len");
3540153eb66SRobert Watson 	workstream_array = malloc(len);
3550153eb66SRobert Watson 	if (workstream_array == NULL)
356*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "malloc");
3570153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL,
3580153eb66SRobert Watson 	    0) < 0)
359*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.workstream: query data");
3600153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
361*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.workstream: invalid len");
3620153eb66SRobert Watson 	workstream_array_len = len / sizeof(*workstream_array);
3630153eb66SRobert Watson 	if (workstream_array_len < 1)
364*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.workstream: no data");
3650153eb66SRobert Watson 	if (workstream_array[0].snws_version != sizeof(workstream_array[0]))
366*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.workstream: invalid version");
3670153eb66SRobert Watson }
3680153eb66SRobert Watson 
3690153eb66SRobert Watson static void
netisr_load_sysctl_work(void)37088737be2SRobert Watson netisr_load_sysctl_work(void)
3710153eb66SRobert Watson {
3720153eb66SRobert Watson 	size_t len;
3730153eb66SRobert Watson 
3740153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0)
375*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.work: query len");
3760153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
377*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.work: invalid len");
3780153eb66SRobert Watson 	work_array = malloc(len);
3790153eb66SRobert Watson 	if (work_array == NULL)
380*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "malloc");
3810153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0)
382*95968ea7SYan-Hao Wang 		xo_err(EX_OSERR, "net.isr.work: query data");
3830153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
384*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.work: invalid len");
3850153eb66SRobert Watson 	work_array_len = len / sizeof(*work_array);
3860153eb66SRobert Watson 	if (work_array_len < 1)
387*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.work: no data");
3880153eb66SRobert Watson 	if (work_array[0].snw_version != sizeof(work_array[0]))
389*95968ea7SYan-Hao Wang 		xo_errx(EX_DATAERR, "net.isr.work: invalid version");
3900153eb66SRobert Watson }
3910153eb66SRobert Watson 
3920153eb66SRobert Watson static void
netisr_print_proto(struct sysctl_netisr_proto * snpp)3930153eb66SRobert Watson netisr_print_proto(struct sysctl_netisr_proto *snpp)
3940153eb66SRobert Watson {
3958f092df0SRobert Watson 	char tmp[20];
3960153eb66SRobert Watson 
397ade9ccfeSMarcel Moolenaar 	xo_emit("{[:-6}{k:name/%s}{]:}", snpp->snp_name);
398ade9ccfeSMarcel Moolenaar 	xo_emit(" {:protocol/%5u}", snpp->snp_proto);
399ade9ccfeSMarcel Moolenaar 	xo_emit(" {:queue-limit/%6u}", snpp->snp_qlimit);
400ade9ccfeSMarcel Moolenaar 	xo_emit(" {:policy-type/%6s}",
4010153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_SOURCE) ?  "source" :
4020153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
4030153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
4048f092df0SRobert Watson 	netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp,
4058f092df0SRobert Watson 	    sizeof(tmp));
406ade9ccfeSMarcel Moolenaar 	xo_emit(" {:policy/%8s}", tmp);
407ade9ccfeSMarcel Moolenaar 	xo_emit("   {:flags/%s%s%s}\n",
4080153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ?  "C" : "-",
4090153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ?  "D" : "-",
4100153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-");
4110153eb66SRobert Watson }
4120153eb66SRobert Watson 
4130153eb66SRobert Watson static void
netisr_print_workstream(struct sysctl_netisr_workstream * snwsp)4140153eb66SRobert Watson netisr_print_workstream(struct sysctl_netisr_workstream *snwsp)
4150153eb66SRobert Watson {
4160153eb66SRobert Watson 	struct sysctl_netisr_work *snwp;
4170153eb66SRobert Watson 	u_int i;
4180153eb66SRobert Watson 
419ade9ccfeSMarcel Moolenaar 	xo_open_list("work");
4200153eb66SRobert Watson 	for (i = 0; i < work_array_len; i++) {
4210153eb66SRobert Watson 		snwp = &work_array[i];
4220153eb66SRobert Watson 		if (snwp->snw_wsid != snwsp->snws_wsid)
4230153eb66SRobert Watson 			continue;
424ade9ccfeSMarcel Moolenaar 		xo_open_instance("work");
425ade9ccfeSMarcel Moolenaar 		xo_emit("{t:workstream/%4u} ", snwsp->snws_wsid);
426ade9ccfeSMarcel Moolenaar 		xo_emit("{t:cpu/%3u} ", snwsp->snws_cpu);
427ade9ccfeSMarcel Moolenaar 		xo_emit("{P:  }");
428ade9ccfeSMarcel Moolenaar 		xo_emit("{t:name/%-6s}", netisr_proto2name(snwp->snw_proto));
429ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:length/%5u}", snwp->snw_len);
430ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:watermark/%5u}", snwp->snw_watermark);
431ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:dispatched/%8ju}", snwp->snw_dispatched);
432ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:hybrid-dispatched/%8ju}",
433ade9ccfeSMarcel Moolenaar 		    snwp->snw_hybrid_dispatched);
434ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:queue-drops/%8ju}", snwp->snw_qdrops);
435ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:queued/%8ju}", snwp->snw_queued);
436ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:handled/%8ju}", snwp->snw_handled);
437ade9ccfeSMarcel Moolenaar 		xo_emit("\n");
438ade9ccfeSMarcel Moolenaar 		xo_close_instance("work");
4390153eb66SRobert Watson 	}
440ade9ccfeSMarcel Moolenaar 	xo_close_list("work");
4410153eb66SRobert Watson }
4420153eb66SRobert Watson 
4430153eb66SRobert Watson void
netisr_stats(void)44481dacd8bSHiroki Sato netisr_stats(void)
4450153eb66SRobert Watson {
4460153eb66SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
4470153eb66SRobert Watson 	struct sysctl_netisr_proto *snpp;
4480153eb66SRobert Watson 	u_int i;
4490153eb66SRobert Watson 
45088737be2SRobert Watson 	if (live) {
45188737be2SRobert Watson 		netisr_load_sysctl_config();
45288737be2SRobert Watson 		netisr_load_sysctl_proto();
45388737be2SRobert Watson 		netisr_load_sysctl_workstream();
45488737be2SRobert Watson 		netisr_load_sysctl_work();
45588737be2SRobert Watson 	} else {
45681dacd8bSHiroki Sato 		netisr_load_kvm_config();
45781dacd8bSHiroki Sato 		netisr_load_kvm_proto();
45881dacd8bSHiroki Sato 		netisr_load_kvm_workstream();		/* Also does work. */
45988737be2SRobert Watson 	}
4600153eb66SRobert Watson 
461ade9ccfeSMarcel Moolenaar 	xo_open_container("netisr");
4620153eb66SRobert Watson 
463ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Configuration}:\n");
464ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
465ade9ccfeSMarcel Moolenaar 	    "Setting", "Current", "Limit");
466ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
467ade9ccfeSMarcel Moolenaar 	    "Thread count", numthreads, maxthreads);
468ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
469ade9ccfeSMarcel Moolenaar 	    "Default queue limit", defaultqlimit, maxqlimit);
470ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
471ade9ccfeSMarcel Moolenaar 	    "Dispatch policy", dispatch_policy, "n/a");
472ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
473ade9ccfeSMarcel Moolenaar 	    "Threads bound to CPUs", bindthreads ? "enabled" : "disabled",
474ade9ccfeSMarcel Moolenaar 	    "n/a");
475ade9ccfeSMarcel Moolenaar 	xo_emit("\n");
476ade9ccfeSMarcel Moolenaar 
477ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Protocols}:\n");
478ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-6s} {T:/%5s} {T:/%6s} {T:/%-6s} {T:/%-8s} {T:/%-5s}\n",
479ade9ccfeSMarcel Moolenaar 	    "Name", "Proto", "QLimit", "Policy", "Dispatch", "Flags");
480ade9ccfeSMarcel Moolenaar 	xo_open_list("protocol");
4810153eb66SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
482ade9ccfeSMarcel Moolenaar 		xo_open_instance("protocol");
4830153eb66SRobert Watson 		snpp = &proto_array[i];
4840153eb66SRobert Watson 		netisr_print_proto(snpp);
485ade9ccfeSMarcel Moolenaar 		xo_close_instance("protocol");
4860153eb66SRobert Watson 	}
487ade9ccfeSMarcel Moolenaar 	xo_close_list("protocol");
488ade9ccfeSMarcel Moolenaar 	xo_emit("\n");
4890153eb66SRobert Watson 
490ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Workstreams}:\n");
491ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%4s} {T:/%3s} ", "WSID", "CPU");
492ade9ccfeSMarcel Moolenaar 	xo_emit("{P:/%2s}", "");
493ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-6s} {T:/%5s} {T:/%5s} {T:/%8s} {T:/%8s} {T:/%8s} "
494ade9ccfeSMarcel Moolenaar 	    "{T:/%8s} {T:/%8s}\n",
495ade9ccfeSMarcel Moolenaar 	    "Name", "Len", "WMark", "Disp'd", "HDisp'd", "QDrops", "Queued",
496ade9ccfeSMarcel Moolenaar 	    "Handled");
497ade9ccfeSMarcel Moolenaar 	xo_open_list("workstream");
4980153eb66SRobert Watson 	for (i = 0; i < workstream_array_len; i++) {
499ade9ccfeSMarcel Moolenaar 		xo_open_instance("workstream");
5000153eb66SRobert Watson 		snwsp = &workstream_array[i];
5010153eb66SRobert Watson 		netisr_print_workstream(snwsp);
502ade9ccfeSMarcel Moolenaar 		xo_close_instance("workstream");
5030153eb66SRobert Watson 	}
504ade9ccfeSMarcel Moolenaar 	xo_close_list("workstream");
505ade9ccfeSMarcel Moolenaar 	xo_close_container("netisr");
5060153eb66SRobert Watson }
507