xref: /freebsd/usr.bin/netstat/netisr.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
10153eb66SRobert Watson /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1de7b4b8SPedro 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 #include <sys/cdefs.h>
330153eb66SRobert Watson 
340153eb66SRobert Watson __FBSDID("$FreeBSD$");
350153eb66SRobert Watson 
3688737be2SRobert Watson #include <sys/param.h>
370153eb66SRobert Watson #include <sys/sysctl.h>
380153eb66SRobert Watson 
3988737be2SRobert Watson #include <sys/_lock.h>
4088737be2SRobert Watson #include <sys/_mutex.h>
4188737be2SRobert Watson 
4288737be2SRobert Watson #define	_WANT_NETISR_INTERNAL
430153eb66SRobert Watson #include <net/netisr.h>
4488737be2SRobert Watson #include <net/netisr_internal.h>
450153eb66SRobert Watson 
460153eb66SRobert Watson #include <err.h>
470153eb66SRobert Watson #include <stdint.h>
480153eb66SRobert Watson #include <stdio.h>
490153eb66SRobert Watson #include <stdlib.h>
50ade9ccfeSMarcel Moolenaar #include <stdbool.h>
5188737be2SRobert Watson #include <string.h>
52ade9ccfeSMarcel Moolenaar #include <libxo/xo.h>
530153eb66SRobert Watson #include "netstat.h"
5481dacd8bSHiroki Sato #include "nl_defs.h"
550153eb66SRobert Watson 
560153eb66SRobert Watson /*
570153eb66SRobert Watson  * Print statistics for the kernel netisr subsystem.
580153eb66SRobert Watson  */
590153eb66SRobert Watson static u_int				 bindthreads;
600153eb66SRobert Watson static u_int				 maxthreads;
610153eb66SRobert Watson static u_int				 numthreads;
620153eb66SRobert Watson 
630153eb66SRobert Watson static u_int				 defaultqlimit;
640153eb66SRobert Watson static u_int				 maxqlimit;
650153eb66SRobert Watson 
668f092df0SRobert Watson static char				 dispatch_policy[20];
670153eb66SRobert Watson 
680153eb66SRobert Watson static struct sysctl_netisr_proto	*proto_array;
690153eb66SRobert Watson static u_int				 proto_array_len;
700153eb66SRobert Watson 
710153eb66SRobert Watson static struct sysctl_netisr_workstream	*workstream_array;
720153eb66SRobert Watson static u_int				 workstream_array_len;
730153eb66SRobert Watson 
740153eb66SRobert Watson static struct sysctl_netisr_work	*work_array;
750153eb66SRobert Watson static u_int				 work_array_len;
760153eb66SRobert Watson 
7788737be2SRobert Watson static u_int				*nws_array;
7888737be2SRobert Watson 
7988737be2SRobert Watson static u_int				 maxprot;
8088737be2SRobert Watson 
8188737be2SRobert Watson static void
82321ae07fSPhilippe Charnier netisr_dispatch_policy_to_string(u_int policy, char *buf,
838f092df0SRobert Watson     size_t buflen)
848f092df0SRobert Watson {
858f092df0SRobert Watson 	const char *str;
868f092df0SRobert Watson 
87321ae07fSPhilippe Charnier 	switch (policy) {
888f092df0SRobert Watson 	case NETISR_DISPATCH_DEFAULT:
898f092df0SRobert Watson 		str = "default";
908f092df0SRobert Watson 		break;
918f092df0SRobert Watson 	case NETISR_DISPATCH_DEFERRED:
928f092df0SRobert Watson 		str = "deferred";
938f092df0SRobert Watson 		break;
948f092df0SRobert Watson 	case NETISR_DISPATCH_HYBRID:
958f092df0SRobert Watson 		str = "hybrid";
968f092df0SRobert Watson 		break;
978f092df0SRobert Watson 	case NETISR_DISPATCH_DIRECT:
988f092df0SRobert Watson 		str = "direct";
998f092df0SRobert Watson 		break;
1008f092df0SRobert Watson 	default:
1018f092df0SRobert Watson 		str = "unknown";
1028f092df0SRobert Watson 		break;
1038f092df0SRobert Watson 	}
1048f092df0SRobert Watson 	snprintf(buf, buflen, "%s", str);
1058f092df0SRobert Watson }
1068f092df0SRobert Watson 
10788737be2SRobert Watson /*
10888737be2SRobert Watson  * Load a nul-terminated string from KVM up to 'limit', guarantee that the
10988737be2SRobert Watson  * string in local memory is nul-terminated.
11088737be2SRobert Watson  */
11188737be2SRobert Watson static void
11281dacd8bSHiroki Sato netisr_load_kvm_string(uintptr_t addr, char *dest, u_int limit)
11388737be2SRobert Watson {
11488737be2SRobert Watson 	u_int i;
11588737be2SRobert Watson 
11688737be2SRobert Watson 	for (i = 0; i < limit; i++) {
11781dacd8bSHiroki Sato 		if (kread(addr + i, &dest[i], sizeof(dest[i])) != 0)
11881dacd8bSHiroki Sato 			xo_errx(-1, "%s: kread()", __func__);
11988737be2SRobert Watson 		if (dest[i] == '\0')
12088737be2SRobert Watson 			break;
12188737be2SRobert Watson 	}
12288737be2SRobert Watson 	dest[limit - 1] = '\0';
12388737be2SRobert Watson }
12488737be2SRobert Watson 
12588737be2SRobert Watson static const char *
12688737be2SRobert Watson netisr_proto2name(u_int proto)
12788737be2SRobert Watson {
12888737be2SRobert Watson 	u_int i;
12988737be2SRobert Watson 
13088737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
13188737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
13288737be2SRobert Watson 			return (proto_array[i].snp_name);
13388737be2SRobert Watson 	}
13488737be2SRobert Watson 	return ("unknown");
13588737be2SRobert Watson }
13688737be2SRobert Watson 
13788737be2SRobert Watson static int
13888737be2SRobert Watson netisr_protoispresent(u_int proto)
13988737be2SRobert Watson {
14088737be2SRobert Watson 	u_int i;
14188737be2SRobert Watson 
14288737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
14388737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
14488737be2SRobert Watson 			return (1);
14588737be2SRobert Watson 	}
14688737be2SRobert Watson 	return (0);
14788737be2SRobert Watson }
14888737be2SRobert Watson 
14988737be2SRobert Watson static void
15081dacd8bSHiroki Sato netisr_load_kvm_config(void)
15188737be2SRobert Watson {
1528f092df0SRobert Watson 	u_int tmp;
15388737be2SRobert Watson 
15481dacd8bSHiroki Sato 	kread(nl[N_NETISR_BINDTHREADS].n_value, &bindthreads, sizeof(u_int));
15581dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXTHREADS].n_value, &maxthreads, sizeof(u_int));
15681dacd8bSHiroki Sato 	kread(nl[N_NWS_COUNT].n_value, &numthreads, sizeof(u_int));
15781dacd8bSHiroki Sato 	kread(nl[N_NETISR_DEFAULTQLIMIT].n_value, &defaultqlimit,
15881dacd8bSHiroki Sato 	    sizeof(u_int));
15981dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXQLIMIT].n_value, &maxqlimit, sizeof(u_int));
16081dacd8bSHiroki Sato 	kread(nl[N_NETISR_DISPATCH_POLICY].n_value, &tmp, sizeof(u_int));
16188737be2SRobert Watson 
1628f092df0SRobert Watson 	netisr_dispatch_policy_to_string(tmp, dispatch_policy,
1638f092df0SRobert Watson 	    sizeof(dispatch_policy));
16488737be2SRobert Watson }
16588737be2SRobert Watson 
1660153eb66SRobert Watson static void
1670153eb66SRobert Watson netisr_load_sysctl_uint(const char *name, u_int *p)
1680153eb66SRobert Watson {
1690153eb66SRobert Watson 	size_t retlen;
1700153eb66SRobert Watson 
1710153eb66SRobert Watson 	retlen = sizeof(u_int);
1720153eb66SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
173ade9ccfeSMarcel Moolenaar 		xo_err(-1, "%s", name);
1740153eb66SRobert Watson 	if (retlen != sizeof(u_int))
175ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen);
1760153eb66SRobert Watson }
1770153eb66SRobert Watson 
1780153eb66SRobert Watson static void
1798f092df0SRobert Watson netisr_load_sysctl_string(const char *name, char *p, size_t len)
1808f092df0SRobert Watson {
1818f092df0SRobert Watson 	size_t retlen;
1828f092df0SRobert Watson 
1838f092df0SRobert Watson 	retlen = len;
1848f092df0SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
185ade9ccfeSMarcel Moolenaar 		xo_err(-1, "%s", name);
1868f092df0SRobert Watson 	p[len - 1] = '\0';
1878f092df0SRobert Watson }
1888f092df0SRobert Watson 
1898f092df0SRobert Watson static void
19088737be2SRobert Watson netisr_load_sysctl_config(void)
1910153eb66SRobert Watson {
1920153eb66SRobert Watson 
1930153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads);
1940153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads);
1950153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.numthreads", &numthreads);
1960153eb66SRobert Watson 
1970153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
1980153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
1990153eb66SRobert Watson 
2008f092df0SRobert Watson 	netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy,
2018f092df0SRobert Watson 	    sizeof(dispatch_policy));
2020153eb66SRobert Watson }
2030153eb66SRobert Watson 
2040153eb66SRobert Watson static void
20581dacd8bSHiroki Sato netisr_load_kvm_proto(void)
20688737be2SRobert Watson {
20788737be2SRobert Watson 	struct netisr_proto *np_array, *npp;
20888737be2SRobert Watson 	u_int i, protocount;
20988737be2SRobert Watson 	struct sysctl_netisr_proto *snpp;
21088737be2SRobert Watson 	size_t len;
21188737be2SRobert Watson 
21288737be2SRobert Watson 	/*
21388737be2SRobert Watson 	 * Kernel compile-time and user compile-time definitions of
21488737be2SRobert Watson 	 * NETISR_MAXPROT must match, as we use that to size work arrays.
21588737be2SRobert Watson 	 */
21681dacd8bSHiroki Sato 	kread(nl[N_NETISR_MAXPROT].n_value, &maxprot, sizeof(u_int));
21788737be2SRobert Watson 	if (maxprot != NETISR_MAXPROT)
218ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "%s: NETISR_MAXPROT mismatch", __func__);
21988737be2SRobert Watson 	len = maxprot * sizeof(*np_array);
22088737be2SRobert Watson 	np_array = malloc(len);
22188737be2SRobert Watson 	if (np_array == NULL)
222ade9ccfeSMarcel Moolenaar 		xo_err(-1, "%s: malloc", __func__);
22381dacd8bSHiroki Sato 	if (kread(nl[N_NETISR_PROTO].n_value, np_array, len) != 0)
22481dacd8bSHiroki Sato 		xo_errx(-1, "%s: kread(_netisr_proto)", __func__);
22588737be2SRobert Watson 
22688737be2SRobert Watson 	/*
22788737be2SRobert Watson 	 * Size and allocate memory to hold only live protocols.
22888737be2SRobert Watson 	 */
22988737be2SRobert Watson 	protocount = 0;
23088737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
23188737be2SRobert Watson 		if (np_array[i].np_name == NULL)
23288737be2SRobert Watson 			continue;
23388737be2SRobert Watson 		protocount++;
23488737be2SRobert Watson 	}
23588737be2SRobert Watson 	proto_array = calloc(protocount, sizeof(*proto_array));
23688737be2SRobert Watson 	if (proto_array == NULL)
23788737be2SRobert Watson 		err(-1, "malloc");
23888737be2SRobert Watson 	protocount = 0;
23988737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
24088737be2SRobert Watson 		npp = &np_array[i];
24188737be2SRobert Watson 		if (npp->np_name == NULL)
24288737be2SRobert Watson 			continue;
24388737be2SRobert Watson 		snpp = &proto_array[protocount];
24488737be2SRobert Watson 		snpp->snp_version = sizeof(*snpp);
24581dacd8bSHiroki Sato 		netisr_load_kvm_string((uintptr_t)npp->np_name,
24688737be2SRobert Watson 		    snpp->snp_name, sizeof(snpp->snp_name));
24788737be2SRobert Watson 		snpp->snp_proto = i;
24888737be2SRobert Watson 		snpp->snp_qlimit = npp->np_qlimit;
24988737be2SRobert Watson 		snpp->snp_policy = npp->np_policy;
2508f092df0SRobert Watson 		snpp->snp_dispatch = npp->np_dispatch;
25188737be2SRobert Watson 		if (npp->np_m2flow != NULL)
25288737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
25388737be2SRobert Watson 		if (npp->np_m2cpuid != NULL)
25488737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
25588737be2SRobert Watson 		if (npp->np_drainedcpu != NULL)
25688737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
25788737be2SRobert Watson 		protocount++;
25888737be2SRobert Watson 	}
25988737be2SRobert Watson 	proto_array_len = protocount;
26088737be2SRobert Watson 	free(np_array);
26188737be2SRobert Watson }
26288737be2SRobert Watson 
26388737be2SRobert Watson static void
26488737be2SRobert Watson netisr_load_sysctl_proto(void)
2650153eb66SRobert Watson {
2660153eb66SRobert Watson 	size_t len;
2670153eb66SRobert Watson 
2680153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0)
269ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.proto: query len");
2700153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
271ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.proto: invalid len");
2720153eb66SRobert Watson 	proto_array = malloc(len);
2730153eb66SRobert Watson 	if (proto_array == NULL)
274ade9ccfeSMarcel Moolenaar 		xo_err(-1, "malloc");
2750153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0)
276ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.proto: query data");
2770153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
278ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.proto: invalid len");
2790153eb66SRobert Watson 	proto_array_len = len / sizeof(*proto_array);
2800153eb66SRobert Watson 	if (proto_array_len < 1)
281ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.proto: no data");
2820153eb66SRobert Watson 	if (proto_array[0].snp_version != sizeof(proto_array[0]))
283ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.proto: invalid version");
2840153eb66SRobert Watson }
2850153eb66SRobert Watson 
2860153eb66SRobert Watson static void
28781dacd8bSHiroki Sato netisr_load_kvm_workstream(void)
28888737be2SRobert Watson {
28988737be2SRobert Watson 	struct netisr_workstream nws;
29088737be2SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
29188737be2SRobert Watson 	struct sysctl_netisr_work *snwp;
29288737be2SRobert Watson 	struct netisr_work *nwp;
29388737be2SRobert Watson 	u_int counter, cpuid, proto, wsid;
29488737be2SRobert Watson 	size_t len;
29588737be2SRobert Watson 
29688737be2SRobert Watson 	len = numthreads * sizeof(*nws_array);
29788737be2SRobert Watson 	nws_array = malloc(len);
29888737be2SRobert Watson 	if (nws_array == NULL)
299ade9ccfeSMarcel Moolenaar 		xo_err(-1, "malloc");
30081dacd8bSHiroki Sato 	if (kread(nl[N_NWS_ARRAY].n_value, nws_array, len) != 0)
30181dacd8bSHiroki Sato 		xo_errx(-1, "%s: kread(_nws_array)", __func__);
30288737be2SRobert Watson 	workstream_array = calloc(numthreads, sizeof(*workstream_array));
30388737be2SRobert Watson 	if (workstream_array == NULL)
304ade9ccfeSMarcel Moolenaar 		xo_err(-1, "calloc");
30588737be2SRobert Watson 	workstream_array_len = numthreads;
30688737be2SRobert Watson 	work_array = calloc(numthreads * proto_array_len, sizeof(*work_array));
30788737be2SRobert Watson 	if (work_array == NULL)
308ade9ccfeSMarcel Moolenaar 		xo_err(-1, "calloc");
30988737be2SRobert Watson 	counter = 0;
31088737be2SRobert Watson 	for (wsid = 0; wsid < numthreads; wsid++) {
31188737be2SRobert Watson 		cpuid = nws_array[wsid];
31281dacd8bSHiroki Sato 		kset_dpcpu(cpuid);
31381dacd8bSHiroki Sato 		if (kread(nl[N_NWS].n_value, &nws, sizeof(nws)) != 0)
31481dacd8bSHiroki Sato 			xo_errx(-1, "%s: kread(nw)", __func__);
31588737be2SRobert Watson 		snwsp = &workstream_array[wsid];
31688737be2SRobert Watson 		snwsp->snws_version = sizeof(*snwsp);
31788737be2SRobert Watson 		snwsp->snws_wsid = cpuid;
31888737be2SRobert Watson 		snwsp->snws_cpu = cpuid;
31988737be2SRobert Watson 		if (nws.nws_intr_event != NULL)
32088737be2SRobert Watson 			snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
32188737be2SRobert Watson 
32288737be2SRobert Watson 		/*
32388737be2SRobert Watson 		 * Extract the CPU's per-protocol work information.
32488737be2SRobert Watson 		 */
325ade9ccfeSMarcel Moolenaar 		xo_emit("counting to maxprot: {:maxprot/%u}\n", maxprot);
32688737be2SRobert Watson 		for (proto = 0; proto < maxprot; proto++) {
32788737be2SRobert Watson 			if (!netisr_protoispresent(proto))
32888737be2SRobert Watson 				continue;
32988737be2SRobert Watson 			nwp = &nws.nws_work[proto];
33088737be2SRobert Watson 			snwp = &work_array[counter];
33188737be2SRobert Watson 			snwp->snw_version = sizeof(*snwp);
33288737be2SRobert Watson 			snwp->snw_wsid = cpuid;
33388737be2SRobert Watson 			snwp->snw_proto = proto;
33488737be2SRobert Watson 			snwp->snw_len = nwp->nw_len;
33588737be2SRobert Watson 			snwp->snw_watermark = nwp->nw_watermark;
33688737be2SRobert Watson 			snwp->snw_dispatched = nwp->nw_dispatched;
33788737be2SRobert Watson 			snwp->snw_hybrid_dispatched =
33888737be2SRobert Watson 			    nwp->nw_hybrid_dispatched;
33988737be2SRobert Watson 			snwp->snw_qdrops = nwp->nw_qdrops;
34088737be2SRobert Watson 			snwp->snw_queued = nwp->nw_queued;
34188737be2SRobert Watson 			snwp->snw_handled = nwp->nw_handled;
34288737be2SRobert Watson 			counter++;
34388737be2SRobert Watson 		}
34488737be2SRobert Watson 	}
34588737be2SRobert Watson 	work_array_len = counter;
34688737be2SRobert Watson }
34788737be2SRobert Watson 
34888737be2SRobert Watson static void
34988737be2SRobert Watson netisr_load_sysctl_workstream(void)
3500153eb66SRobert Watson {
3510153eb66SRobert Watson 	size_t len;
3520153eb66SRobert Watson 
3530153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0)
354ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.workstream: query len");
3550153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
356ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.workstream: invalid len");
3570153eb66SRobert Watson 	workstream_array = malloc(len);
3580153eb66SRobert Watson 	if (workstream_array == NULL)
359ade9ccfeSMarcel Moolenaar 		xo_err(-1, "malloc");
3600153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL,
3610153eb66SRobert Watson 	    0) < 0)
362ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.workstream: query data");
3630153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
364ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.workstream: invalid len");
3650153eb66SRobert Watson 	workstream_array_len = len / sizeof(*workstream_array);
3660153eb66SRobert Watson 	if (workstream_array_len < 1)
367ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.workstream: no data");
3680153eb66SRobert Watson 	if (workstream_array[0].snws_version != sizeof(workstream_array[0]))
369ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.workstream: invalid version");
3700153eb66SRobert Watson }
3710153eb66SRobert Watson 
3720153eb66SRobert Watson static void
37388737be2SRobert Watson netisr_load_sysctl_work(void)
3740153eb66SRobert Watson {
3750153eb66SRobert Watson 	size_t len;
3760153eb66SRobert Watson 
3770153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0)
378ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.work: query len");
3790153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
380ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.work: invalid len");
3810153eb66SRobert Watson 	work_array = malloc(len);
3820153eb66SRobert Watson 	if (work_array == NULL)
383ade9ccfeSMarcel Moolenaar 		xo_err(-1, "malloc");
3840153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0)
385ade9ccfeSMarcel Moolenaar 		xo_err(-1, "net.isr.work: query data");
3860153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
387ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.work: invalid len");
3880153eb66SRobert Watson 	work_array_len = len / sizeof(*work_array);
3890153eb66SRobert Watson 	if (work_array_len < 1)
390ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.work: no data");
3910153eb66SRobert Watson 	if (work_array[0].snw_version != sizeof(work_array[0]))
392ade9ccfeSMarcel Moolenaar 		xo_errx(-1, "net.isr.work: invalid version");
3930153eb66SRobert Watson }
3940153eb66SRobert Watson 
3950153eb66SRobert Watson static void
3960153eb66SRobert Watson netisr_print_proto(struct sysctl_netisr_proto *snpp)
3970153eb66SRobert Watson {
3988f092df0SRobert Watson 	char tmp[20];
3990153eb66SRobert Watson 
400ade9ccfeSMarcel Moolenaar 	xo_emit("{[:-6}{k:name/%s}{]:}", snpp->snp_name);
401ade9ccfeSMarcel Moolenaar 	xo_emit(" {:protocol/%5u}", snpp->snp_proto);
402ade9ccfeSMarcel Moolenaar 	xo_emit(" {:queue-limit/%6u}", snpp->snp_qlimit);
403ade9ccfeSMarcel Moolenaar 	xo_emit(" {:policy-type/%6s}",
4040153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_SOURCE) ?  "source" :
4050153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
4060153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
4078f092df0SRobert Watson 	netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp,
4088f092df0SRobert Watson 	    sizeof(tmp));
409ade9ccfeSMarcel Moolenaar 	xo_emit(" {:policy/%8s}", tmp);
410ade9ccfeSMarcel Moolenaar 	xo_emit("   {:flags/%s%s%s}\n",
4110153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ?  "C" : "-",
4120153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ?  "D" : "-",
4130153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-");
4140153eb66SRobert Watson }
4150153eb66SRobert Watson 
4160153eb66SRobert Watson static void
4170153eb66SRobert Watson netisr_print_workstream(struct sysctl_netisr_workstream *snwsp)
4180153eb66SRobert Watson {
4190153eb66SRobert Watson 	struct sysctl_netisr_work *snwp;
4200153eb66SRobert Watson 	u_int i;
4210153eb66SRobert Watson 
422ade9ccfeSMarcel Moolenaar 	xo_open_list("work");
4230153eb66SRobert Watson 	for (i = 0; i < work_array_len; i++) {
4240153eb66SRobert Watson 		snwp = &work_array[i];
4250153eb66SRobert Watson 		if (snwp->snw_wsid != snwsp->snws_wsid)
4260153eb66SRobert Watson 			continue;
427ade9ccfeSMarcel Moolenaar 		xo_open_instance("work");
428ade9ccfeSMarcel Moolenaar 		xo_emit("{t:workstream/%4u} ", snwsp->snws_wsid);
429ade9ccfeSMarcel Moolenaar 		xo_emit("{t:cpu/%3u} ", snwsp->snws_cpu);
430ade9ccfeSMarcel Moolenaar 		xo_emit("{P:  }");
431ade9ccfeSMarcel Moolenaar 		xo_emit("{t:name/%-6s}", netisr_proto2name(snwp->snw_proto));
432ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:length/%5u}", snwp->snw_len);
433ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:watermark/%5u}", snwp->snw_watermark);
434ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:dispatched/%8ju}", snwp->snw_dispatched);
435ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:hybrid-dispatched/%8ju}",
436ade9ccfeSMarcel Moolenaar 		    snwp->snw_hybrid_dispatched);
437ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:queue-drops/%8ju}", snwp->snw_qdrops);
438ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:queued/%8ju}", snwp->snw_queued);
439ade9ccfeSMarcel Moolenaar 		xo_emit(" {t:handled/%8ju}", snwp->snw_handled);
440ade9ccfeSMarcel Moolenaar 		xo_emit("\n");
441ade9ccfeSMarcel Moolenaar 		xo_close_instance("work");
4420153eb66SRobert Watson 	}
443ade9ccfeSMarcel Moolenaar 	xo_close_list("work");
4440153eb66SRobert Watson }
4450153eb66SRobert Watson 
4460153eb66SRobert Watson void
44781dacd8bSHiroki Sato netisr_stats(void)
4480153eb66SRobert Watson {
4490153eb66SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
4500153eb66SRobert Watson 	struct sysctl_netisr_proto *snpp;
4510153eb66SRobert Watson 	u_int i;
4520153eb66SRobert Watson 
45388737be2SRobert Watson 	if (live) {
45488737be2SRobert Watson 		netisr_load_sysctl_config();
45588737be2SRobert Watson 		netisr_load_sysctl_proto();
45688737be2SRobert Watson 		netisr_load_sysctl_workstream();
45788737be2SRobert Watson 		netisr_load_sysctl_work();
45888737be2SRobert Watson 	} else {
45981dacd8bSHiroki Sato 		netisr_load_kvm_config();
46081dacd8bSHiroki Sato 		netisr_load_kvm_proto();
46181dacd8bSHiroki Sato 		netisr_load_kvm_workstream();		/* Also does work. */
46288737be2SRobert Watson 	}
4630153eb66SRobert Watson 
464ade9ccfeSMarcel Moolenaar 	xo_open_container("netisr");
4650153eb66SRobert Watson 
466ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Configuration}:\n");
467ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
468ade9ccfeSMarcel Moolenaar 	    "Setting", "Current", "Limit");
469ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
470ade9ccfeSMarcel Moolenaar 	    "Thread count", numthreads, maxthreads);
471ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
472ade9ccfeSMarcel Moolenaar 	    "Default queue limit", defaultqlimit, maxqlimit);
473ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
474ade9ccfeSMarcel Moolenaar 	    "Dispatch policy", dispatch_policy, "n/a");
475ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
476ade9ccfeSMarcel Moolenaar 	    "Threads bound to CPUs", bindthreads ? "enabled" : "disabled",
477ade9ccfeSMarcel Moolenaar 	    "n/a");
478ade9ccfeSMarcel Moolenaar 	xo_emit("\n");
479ade9ccfeSMarcel Moolenaar 
480ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Protocols}:\n");
481ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-6s} {T:/%5s} {T:/%6s} {T:/%-6s} {T:/%-8s} {T:/%-5s}\n",
482ade9ccfeSMarcel Moolenaar 	    "Name", "Proto", "QLimit", "Policy", "Dispatch", "Flags");
483ade9ccfeSMarcel Moolenaar 	xo_open_list("protocol");
4840153eb66SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
485ade9ccfeSMarcel Moolenaar 		xo_open_instance("protocol");
4860153eb66SRobert Watson 		snpp = &proto_array[i];
4870153eb66SRobert Watson 		netisr_print_proto(snpp);
488ade9ccfeSMarcel Moolenaar 		xo_close_instance("protocol");
4890153eb66SRobert Watson 	}
490ade9ccfeSMarcel Moolenaar 	xo_close_list("protocol");
491ade9ccfeSMarcel Moolenaar 	xo_emit("\n");
4920153eb66SRobert Watson 
493ade9ccfeSMarcel Moolenaar 	xo_emit("{T:Workstreams}:\n");
494ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%4s} {T:/%3s} ", "WSID", "CPU");
495ade9ccfeSMarcel Moolenaar 	xo_emit("{P:/%2s}", "");
496ade9ccfeSMarcel Moolenaar 	xo_emit("{T:/%-6s} {T:/%5s} {T:/%5s} {T:/%8s} {T:/%8s} {T:/%8s} "
497ade9ccfeSMarcel Moolenaar 	    "{T:/%8s} {T:/%8s}\n",
498ade9ccfeSMarcel Moolenaar 	    "Name", "Len", "WMark", "Disp'd", "HDisp'd", "QDrops", "Queued",
499ade9ccfeSMarcel Moolenaar 	    "Handled");
500ade9ccfeSMarcel Moolenaar 	xo_open_list("workstream");
5010153eb66SRobert Watson 	for (i = 0; i < workstream_array_len; i++) {
502ade9ccfeSMarcel Moolenaar 		xo_open_instance("workstream");
5030153eb66SRobert Watson 		snwsp = &workstream_array[i];
5040153eb66SRobert Watson 		netisr_print_workstream(snwsp);
505ade9ccfeSMarcel Moolenaar 		xo_close_instance("workstream");
5060153eb66SRobert Watson 	}
507ade9ccfeSMarcel Moolenaar 	xo_close_list("workstream");
508ade9ccfeSMarcel Moolenaar 	xo_close_container("netisr");
5090153eb66SRobert Watson }
510