xref: /freebsd/usr.bin/netstat/netisr.c (revision 321ae07f36f17c1a2b5128719eb6297337bc19f7)
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>
4988737be2SRobert Watson #include <string.h>
500153eb66SRobert Watson 
510153eb66SRobert Watson #include "netstat.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
79*321ae07fSPhilippe 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 
84*321ae07fSPhilippe 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 
1048f092df0SRobert Watson static void
105*321ae07fSPhilippe Charnier netisr_load_kvm_uint(kvm_t *kd, const char *name, u_int *p)
10688737be2SRobert Watson {
10788737be2SRobert Watson 	struct nlist nl[] = {
10888737be2SRobert Watson 		{ .n_name = name },
10988737be2SRobert Watson 		{ .n_name = NULL },
11088737be2SRobert Watson 	};
11188737be2SRobert Watson 	int ret;
11288737be2SRobert Watson 
11388737be2SRobert Watson 	ret = kvm_nlist(kd, nl);
11488737be2SRobert Watson 	if (ret < 0)
11588737be2SRobert Watson 		errx(-1, "%s: kvm_nlist(%s): %s", __func__, name,
11688737be2SRobert Watson 		    kvm_geterr(kd));
11788737be2SRobert Watson 	if (ret != 0)
11888737be2SRobert Watson 		errx(-1, "%s: kvm_nlist(%s): unresolved symbol", __func__,
11988737be2SRobert Watson 		    name);
12088737be2SRobert Watson 	if (kvm_read(kd, nl[0].n_value, p, sizeof(*p)) != sizeof(*p))
12188737be2SRobert Watson 		errx(-1, "%s: kvm_read(%s): %s", __func__, name,
12288737be2SRobert Watson 		    kvm_geterr(kd));
12388737be2SRobert Watson }
12488737be2SRobert Watson 
12588737be2SRobert Watson /*
12688737be2SRobert Watson  * Load a nul-terminated string from KVM up to 'limit', guarantee that the
12788737be2SRobert Watson  * string in local memory is nul-terminated.
12888737be2SRobert Watson  */
12988737be2SRobert Watson static void
13088737be2SRobert Watson netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit)
13188737be2SRobert Watson {
13288737be2SRobert Watson 	u_int i;
13388737be2SRobert Watson 
13488737be2SRobert Watson 	for (i = 0; i < limit; i++) {
13588737be2SRobert Watson 		if (kvm_read(kd, addr + i, &dest[i], sizeof(dest[i])) !=
13688737be2SRobert Watson 		    sizeof(dest[i]))
13788737be2SRobert Watson 			err(-1, "%s: kvm_read: %s", __func__,
13888737be2SRobert Watson 			    kvm_geterr(kd));
13988737be2SRobert Watson 		if (dest[i] == '\0')
14088737be2SRobert Watson 			break;
14188737be2SRobert Watson 	}
14288737be2SRobert Watson 	dest[limit - 1] = '\0';
14388737be2SRobert Watson }
14488737be2SRobert Watson 
14588737be2SRobert Watson static const char *
14688737be2SRobert Watson netisr_proto2name(u_int proto)
14788737be2SRobert Watson {
14888737be2SRobert Watson 	u_int i;
14988737be2SRobert Watson 
15088737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
15188737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
15288737be2SRobert Watson 			return (proto_array[i].snp_name);
15388737be2SRobert Watson 	}
15488737be2SRobert Watson 	return ("unknown");
15588737be2SRobert Watson }
15688737be2SRobert Watson 
15788737be2SRobert Watson static int
15888737be2SRobert Watson netisr_protoispresent(u_int proto)
15988737be2SRobert Watson {
16088737be2SRobert Watson 	u_int i;
16188737be2SRobert Watson 
16288737be2SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
16388737be2SRobert Watson 		if (proto_array[i].snp_proto == proto)
16488737be2SRobert Watson 			return (1);
16588737be2SRobert Watson 	}
16688737be2SRobert Watson 	return (0);
16788737be2SRobert Watson }
16888737be2SRobert Watson 
16988737be2SRobert Watson static void
17088737be2SRobert Watson netisr_load_kvm_config(kvm_t *kd)
17188737be2SRobert Watson {
1728f092df0SRobert Watson 	u_int tmp;
17388737be2SRobert Watson 
17488737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads);
17588737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads);
17688737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_nws_count", &numthreads);
17788737be2SRobert Watson 
17888737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit);
17988737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit);
18088737be2SRobert Watson 
1818f092df0SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_dispatch_policy", &tmp);
1828f092df0SRobert Watson 	netisr_dispatch_policy_to_string(tmp, dispatch_policy,
1838f092df0SRobert Watson 	    sizeof(dispatch_policy));
18488737be2SRobert Watson }
18588737be2SRobert Watson 
1860153eb66SRobert Watson static void
1870153eb66SRobert Watson netisr_load_sysctl_uint(const char *name, u_int *p)
1880153eb66SRobert Watson {
1890153eb66SRobert Watson 	size_t retlen;
1900153eb66SRobert Watson 
1910153eb66SRobert Watson 	retlen = sizeof(u_int);
1920153eb66SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
1930153eb66SRobert Watson 		err(-1, "%s", name);
1940153eb66SRobert Watson 	if (retlen != sizeof(u_int))
1950153eb66SRobert Watson 		errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen);
1960153eb66SRobert Watson }
1970153eb66SRobert Watson 
1980153eb66SRobert Watson static void
1998f092df0SRobert Watson netisr_load_sysctl_string(const char *name, char *p, size_t len)
2008f092df0SRobert Watson {
2018f092df0SRobert Watson 	size_t retlen;
2028f092df0SRobert Watson 
2038f092df0SRobert Watson 	retlen = len;
2048f092df0SRobert Watson 	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
2058f092df0SRobert Watson 		err(-1, "%s", name);
2068f092df0SRobert Watson 	p[len - 1] = '\0';
2078f092df0SRobert Watson }
2088f092df0SRobert Watson 
2098f092df0SRobert Watson static void
21088737be2SRobert Watson netisr_load_sysctl_config(void)
2110153eb66SRobert Watson {
2120153eb66SRobert Watson 
2130153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads);
2140153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads);
2150153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.numthreads", &numthreads);
2160153eb66SRobert Watson 
2170153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
2180153eb66SRobert Watson 	netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
2190153eb66SRobert Watson 
2208f092df0SRobert Watson 	netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy,
2218f092df0SRobert Watson 	    sizeof(dispatch_policy));
2220153eb66SRobert Watson }
2230153eb66SRobert Watson 
2240153eb66SRobert Watson static void
22588737be2SRobert Watson netisr_load_kvm_proto(kvm_t *kd)
22688737be2SRobert Watson {
22788737be2SRobert Watson 	struct nlist nl[] = {
22888737be2SRobert Watson #define	NLIST_NETISR_PROTO	0
22988737be2SRobert Watson 		{ .n_name = "_netisr_proto" },
23088737be2SRobert Watson 		{ .n_name = NULL },
23188737be2SRobert Watson 	};
23288737be2SRobert Watson 	struct netisr_proto *np_array, *npp;
23388737be2SRobert Watson 	u_int i, protocount;
23488737be2SRobert Watson 	struct sysctl_netisr_proto *snpp;
23588737be2SRobert Watson 	size_t len;
23688737be2SRobert Watson 	int ret;
23788737be2SRobert Watson 
23888737be2SRobert Watson 	/*
23988737be2SRobert Watson 	 * Kernel compile-time and user compile-time definitions of
24088737be2SRobert Watson 	 * NETISR_MAXPROT must match, as we use that to size work arrays.
24188737be2SRobert Watson 	 */
24288737be2SRobert Watson 	netisr_load_kvm_uint(kd, "_netisr_maxprot", &maxprot);
24388737be2SRobert Watson 	if (maxprot != NETISR_MAXPROT)
24488737be2SRobert Watson 		errx(-1, "%s: NETISR_MAXPROT mismatch", __func__);
24588737be2SRobert Watson 	len = maxprot * sizeof(*np_array);
24688737be2SRobert Watson 	np_array = malloc(len);
24788737be2SRobert Watson 	if (np_array == NULL)
24888737be2SRobert Watson 		err(-1, "%s: malloc", __func__);
24988737be2SRobert Watson 	ret = kvm_nlist(kd, nl);
25088737be2SRobert Watson 	if (ret < 0)
25188737be2SRobert Watson 		errx(-1, "%s: kvm_nlist(_netisr_proto): %s", __func__,
25288737be2SRobert Watson 		    kvm_geterr(kd));
25388737be2SRobert Watson 	if (ret != 0)
25488737be2SRobert Watson 		errx(-1, "%s: kvm_nlist(_netisr_proto): unresolved symbol",
25588737be2SRobert Watson 		    __func__);
25688737be2SRobert Watson 	if (kvm_read(kd, nl[NLIST_NETISR_PROTO].n_value, np_array, len) !=
25788737be2SRobert Watson 	    (ssize_t)len)
25888737be2SRobert Watson 		errx(-1, "%s: kvm_read(_netisr_proto): %s", __func__,
25988737be2SRobert Watson 		    kvm_geterr(kd));
26088737be2SRobert Watson 
26188737be2SRobert Watson 	/*
26288737be2SRobert Watson 	 * Size and allocate memory to hold only live protocols.
26388737be2SRobert Watson 	 */
26488737be2SRobert Watson 	protocount = 0;
26588737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
26688737be2SRobert Watson 		if (np_array[i].np_name == NULL)
26788737be2SRobert Watson 			continue;
26888737be2SRobert Watson 		protocount++;
26988737be2SRobert Watson 	}
27088737be2SRobert Watson 	proto_array = calloc(protocount, sizeof(*proto_array));
27188737be2SRobert Watson 	if (proto_array == NULL)
27288737be2SRobert Watson 		err(-1, "malloc");
27388737be2SRobert Watson 	protocount = 0;
27488737be2SRobert Watson 	for (i = 0; i < maxprot; i++) {
27588737be2SRobert Watson 		npp = &np_array[i];
27688737be2SRobert Watson 		if (npp->np_name == NULL)
27788737be2SRobert Watson 			continue;
27888737be2SRobert Watson 		snpp = &proto_array[protocount];
27988737be2SRobert Watson 		snpp->snp_version = sizeof(*snpp);
28088737be2SRobert Watson 		netisr_load_kvm_string(kd, (uintptr_t)npp->np_name,
28188737be2SRobert Watson 		    snpp->snp_name, sizeof(snpp->snp_name));
28288737be2SRobert Watson 		snpp->snp_proto = i;
28388737be2SRobert Watson 		snpp->snp_qlimit = npp->np_qlimit;
28488737be2SRobert Watson 		snpp->snp_policy = npp->np_policy;
2858f092df0SRobert Watson 		snpp->snp_dispatch = npp->np_dispatch;
28688737be2SRobert Watson 		if (npp->np_m2flow != NULL)
28788737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
28888737be2SRobert Watson 		if (npp->np_m2cpuid != NULL)
28988737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
29088737be2SRobert Watson 		if (npp->np_drainedcpu != NULL)
29188737be2SRobert Watson 			snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
29288737be2SRobert Watson 		protocount++;
29388737be2SRobert Watson 	}
29488737be2SRobert Watson 	proto_array_len = protocount;
29588737be2SRobert Watson 	free(np_array);
29688737be2SRobert Watson }
29788737be2SRobert Watson 
29888737be2SRobert Watson static void
29988737be2SRobert Watson netisr_load_sysctl_proto(void)
3000153eb66SRobert Watson {
3010153eb66SRobert Watson 	size_t len;
3020153eb66SRobert Watson 
3030153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0)
3040153eb66SRobert Watson 		err(-1, "net.isr.proto: query len");
3050153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
3060153eb66SRobert Watson 		errx(-1, "net.isr.proto: invalid len");
3070153eb66SRobert Watson 	proto_array = malloc(len);
3080153eb66SRobert Watson 	if (proto_array == NULL)
3090153eb66SRobert Watson 		err(-1, "malloc");
3100153eb66SRobert Watson 	if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0)
3110153eb66SRobert Watson 		err(-1, "net.isr.proto: query data");
3120153eb66SRobert Watson 	if (len % sizeof(*proto_array) != 0)
3130153eb66SRobert Watson 		errx(-1, "net.isr.proto: invalid len");
3140153eb66SRobert Watson 	proto_array_len = len / sizeof(*proto_array);
3150153eb66SRobert Watson 	if (proto_array_len < 1)
3160153eb66SRobert Watson 		errx(-1, "net.isr.proto: no data");
3170153eb66SRobert Watson 	if (proto_array[0].snp_version != sizeof(proto_array[0]))
3180153eb66SRobert Watson 		errx(-1, "net.isr.proto: invalid version");
3190153eb66SRobert Watson }
3200153eb66SRobert Watson 
3210153eb66SRobert Watson static void
32288737be2SRobert Watson netisr_load_kvm_workstream(kvm_t *kd)
32388737be2SRobert Watson {
32488737be2SRobert Watson 	struct nlist nl[] = {
32588737be2SRobert Watson #define	NLIST_NWS_ARRAY		0
32688737be2SRobert Watson 		{ .n_name = "_nws_array" },
32788737be2SRobert Watson 		{ .n_name = NULL },
32888737be2SRobert Watson 	};
32988737be2SRobert Watson 	struct netisr_workstream nws;
33088737be2SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
33188737be2SRobert Watson 	struct sysctl_netisr_work *snwp;
33288737be2SRobert Watson 	struct netisr_work *nwp;
33388737be2SRobert Watson 	struct nlist nl_nws[2];
33488737be2SRobert Watson 	u_int counter, cpuid, proto, wsid;
33588737be2SRobert Watson 	size_t len;
33688737be2SRobert Watson 	int ret;
33788737be2SRobert Watson 
33888737be2SRobert Watson 	len = numthreads * sizeof(*nws_array);
33988737be2SRobert Watson 	nws_array = malloc(len);
34088737be2SRobert Watson 	if (nws_array == NULL)
34188737be2SRobert Watson 		err(-1, "malloc");
34288737be2SRobert Watson 	ret = kvm_nlist(kd, nl);
34388737be2SRobert Watson 	if (ret < 0)
34488737be2SRobert Watson 		errx(-1, "%s: kvm_nlist: %s", __func__, kvm_geterr(kd));
34588737be2SRobert Watson 	if (ret != 0)
34688737be2SRobert Watson 		errx(-1, "%s: kvm_nlist: unresolved symbol", __func__);
34788737be2SRobert Watson 	if (kvm_read(kd, nl[NLIST_NWS_ARRAY].n_value, nws_array, len) !=
34888737be2SRobert Watson 	    (ssize_t)len)
34988737be2SRobert Watson 		errx(-1, "%s: kvm_read(_nws_array): %s", __func__,
35088737be2SRobert Watson 		    kvm_geterr(kd));
35188737be2SRobert Watson 	workstream_array = calloc(numthreads, sizeof(*workstream_array));
35288737be2SRobert Watson 	if (workstream_array == NULL)
35388737be2SRobert Watson 		err(-1, "calloc");
35488737be2SRobert Watson 	workstream_array_len = numthreads;
35588737be2SRobert Watson 	work_array = calloc(numthreads * proto_array_len, sizeof(*work_array));
35688737be2SRobert Watson 	if (work_array == NULL)
35788737be2SRobert Watson 		err(-1, "calloc");
35888737be2SRobert Watson 	counter = 0;
35988737be2SRobert Watson 	for (wsid = 0; wsid < numthreads; wsid++) {
36088737be2SRobert Watson 		cpuid = nws_array[wsid];
36188737be2SRobert Watson 		if (kvm_dpcpu_setcpu(kd, cpuid) < 0)
36288737be2SRobert Watson 			errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
36388737be2SRobert Watson 			    cpuid, kvm_geterr(kd));
36488737be2SRobert Watson 		bzero(nl_nws, sizeof(nl_nws));
36588737be2SRobert Watson 		nl_nws[0].n_name = "_nws";
36688737be2SRobert Watson 		ret = kvm_nlist(kd, nl_nws);
36788737be2SRobert Watson 		if (ret < 0)
36888737be2SRobert Watson 			errx(-1, "%s: kvm_nlist looking up nws on CPU %u: %s",
36988737be2SRobert Watson 			    __func__, cpuid, kvm_geterr(kd));
37088737be2SRobert Watson 		if (ret != 0)
37188737be2SRobert Watson 			errx(-1, "%s: kvm_nlist(nws): unresolved symbol on "
37288737be2SRobert Watson 			    "CPU %u", __func__, cpuid);
37388737be2SRobert Watson 		if (kvm_read(kd, nl_nws[0].n_value, &nws, sizeof(nws)) !=
37488737be2SRobert Watson 		    sizeof(nws))
37588737be2SRobert Watson 			errx(-1, "%s: kvm_read(nw): %s", __func__,
37688737be2SRobert Watson 			    kvm_geterr(kd));
37788737be2SRobert Watson 		snwsp = &workstream_array[wsid];
37888737be2SRobert Watson 		snwsp->snws_version = sizeof(*snwsp);
37988737be2SRobert Watson 		snwsp->snws_wsid = cpuid;
38088737be2SRobert Watson 		snwsp->snws_cpu = cpuid;
38188737be2SRobert Watson 		if (nws.nws_intr_event != NULL)
38288737be2SRobert Watson 			snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
38388737be2SRobert Watson 
38488737be2SRobert Watson 		/*
38588737be2SRobert Watson 		 * Extract the CPU's per-protocol work information.
38688737be2SRobert Watson 		 */
38788737be2SRobert Watson 		printf("counting to maxprot: %u\n", maxprot);
38888737be2SRobert Watson 		for (proto = 0; proto < maxprot; proto++) {
38988737be2SRobert Watson 			if (!netisr_protoispresent(proto))
39088737be2SRobert Watson 				continue;
39188737be2SRobert Watson 			nwp = &nws.nws_work[proto];
39288737be2SRobert Watson 			snwp = &work_array[counter];
39388737be2SRobert Watson 			snwp->snw_version = sizeof(*snwp);
39488737be2SRobert Watson 			snwp->snw_wsid = cpuid;
39588737be2SRobert Watson 			snwp->snw_proto = proto;
39688737be2SRobert Watson 			snwp->snw_len = nwp->nw_len;
39788737be2SRobert Watson 			snwp->snw_watermark = nwp->nw_watermark;
39888737be2SRobert Watson 			snwp->snw_dispatched = nwp->nw_dispatched;
39988737be2SRobert Watson 			snwp->snw_hybrid_dispatched =
40088737be2SRobert Watson 			    nwp->nw_hybrid_dispatched;
40188737be2SRobert Watson 			snwp->snw_qdrops = nwp->nw_qdrops;
40288737be2SRobert Watson 			snwp->snw_queued = nwp->nw_queued;
40388737be2SRobert Watson 			snwp->snw_handled = nwp->nw_handled;
40488737be2SRobert Watson 			counter++;
40588737be2SRobert Watson 		}
40688737be2SRobert Watson 	}
40788737be2SRobert Watson 	work_array_len = counter;
40888737be2SRobert Watson }
40988737be2SRobert Watson 
41088737be2SRobert Watson static void
41188737be2SRobert Watson netisr_load_sysctl_workstream(void)
4120153eb66SRobert Watson {
4130153eb66SRobert Watson 	size_t len;
4140153eb66SRobert Watson 
4150153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0)
4160153eb66SRobert Watson 		err(-1, "net.isr.workstream: query len");
4170153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
4180153eb66SRobert Watson 		errx(-1, "net.isr.workstream: invalid len");
4190153eb66SRobert Watson 	workstream_array = malloc(len);
4200153eb66SRobert Watson 	if (workstream_array == NULL)
4210153eb66SRobert Watson 		err(-1, "malloc");
4220153eb66SRobert Watson 	if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL,
4230153eb66SRobert Watson 	    0) < 0)
4240153eb66SRobert Watson 		err(-1, "net.isr.workstream: query data");
4250153eb66SRobert Watson 	if (len % sizeof(*workstream_array) != 0)
4260153eb66SRobert Watson 		errx(-1, "net.isr.workstream: invalid len");
4270153eb66SRobert Watson 	workstream_array_len = len / sizeof(*workstream_array);
4280153eb66SRobert Watson 	if (workstream_array_len < 1)
4290153eb66SRobert Watson 		errx(-1, "net.isr.workstream: no data");
4300153eb66SRobert Watson 	if (workstream_array[0].snws_version != sizeof(workstream_array[0]))
4310153eb66SRobert Watson 		errx(-1, "net.isr.workstream: invalid version");
4320153eb66SRobert Watson }
4330153eb66SRobert Watson 
4340153eb66SRobert Watson static void
43588737be2SRobert Watson netisr_load_sysctl_work(void)
4360153eb66SRobert Watson {
4370153eb66SRobert Watson 	size_t len;
4380153eb66SRobert Watson 
4390153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0)
4400153eb66SRobert Watson 		err(-1, "net.isr.work: query len");
4410153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
4420153eb66SRobert Watson 		errx(-1, "net.isr.work: invalid len");
4430153eb66SRobert Watson 	work_array = malloc(len);
4440153eb66SRobert Watson 	if (work_array == NULL)
4450153eb66SRobert Watson 		err(-1, "malloc");
4460153eb66SRobert Watson 	if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0)
4470153eb66SRobert Watson 		err(-1, "net.isr.work: query data");
4480153eb66SRobert Watson 	if (len % sizeof(*work_array) != 0)
4490153eb66SRobert Watson 		errx(-1, "net.isr.work: invalid len");
4500153eb66SRobert Watson 	work_array_len = len / sizeof(*work_array);
4510153eb66SRobert Watson 	if (work_array_len < 1)
4520153eb66SRobert Watson 		errx(-1, "net.isr.work: no data");
4530153eb66SRobert Watson 	if (work_array[0].snw_version != sizeof(work_array[0]))
4540153eb66SRobert Watson 		errx(-1, "net.isr.work: invalid version");
4550153eb66SRobert Watson }
4560153eb66SRobert Watson 
4570153eb66SRobert Watson static void
4580153eb66SRobert Watson netisr_print_proto(struct sysctl_netisr_proto *snpp)
4590153eb66SRobert Watson {
4608f092df0SRobert Watson 	char tmp[20];
4610153eb66SRobert Watson 
4620153eb66SRobert Watson 	printf("%-6s", snpp->snp_name);
4630153eb66SRobert Watson 	printf(" %5u", snpp->snp_proto);
4640153eb66SRobert Watson 	printf(" %6u", snpp->snp_qlimit);
4650153eb66SRobert Watson 	printf(" %6s",
4660153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_SOURCE) ?  "source" :
4670153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
4680153eb66SRobert Watson 	    (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
4698f092df0SRobert Watson 	netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp,
4708f092df0SRobert Watson 	    sizeof(tmp));
4718f092df0SRobert Watson 	printf(" %8s", tmp);
4720153eb66SRobert Watson 	printf("   %s%s%s\n",
4730153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ?  "C" : "-",
4740153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ?  "D" : "-",
4750153eb66SRobert Watson 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-");
4760153eb66SRobert Watson }
4770153eb66SRobert Watson 
4780153eb66SRobert Watson static void
4790153eb66SRobert Watson netisr_print_workstream(struct sysctl_netisr_workstream *snwsp)
4800153eb66SRobert Watson {
4810153eb66SRobert Watson 	struct sysctl_netisr_work *snwp;
4820153eb66SRobert Watson 	u_int i;
4830153eb66SRobert Watson 
4840153eb66SRobert Watson 	for (i = 0; i < work_array_len; i++) {
4850153eb66SRobert Watson 		snwp = &work_array[i];
4860153eb66SRobert Watson 		if (snwp->snw_wsid != snwsp->snws_wsid)
4870153eb66SRobert Watson 			continue;
4880153eb66SRobert Watson 		printf("%4u ", snwsp->snws_wsid);
4890153eb66SRobert Watson 		printf("%3u ", snwsp->snws_cpu);
4900153eb66SRobert Watson 		printf("%2s", "");
4910153eb66SRobert Watson 		printf("%-6s", netisr_proto2name(snwp->snw_proto));
4920153eb66SRobert Watson 		printf(" %5u", snwp->snw_len);
4930153eb66SRobert Watson 		printf(" %5u", snwp->snw_watermark);
4940153eb66SRobert Watson 		printf(" %8ju", snwp->snw_dispatched);
4950153eb66SRobert Watson 		printf(" %8ju", snwp->snw_hybrid_dispatched);
4960153eb66SRobert Watson 		printf(" %8ju", snwp->snw_qdrops);
4970153eb66SRobert Watson 		printf(" %8ju", snwp->snw_queued);
4980153eb66SRobert Watson 		printf(" %8ju", snwp->snw_handled);
4990153eb66SRobert Watson 		printf("\n");
5000153eb66SRobert Watson 	}
5010153eb66SRobert Watson }
5020153eb66SRobert Watson 
5030153eb66SRobert Watson void
50488737be2SRobert Watson netisr_stats(void *kvmd)
5050153eb66SRobert Watson {
5060153eb66SRobert Watson 	struct sysctl_netisr_workstream *snwsp;
5070153eb66SRobert Watson 	struct sysctl_netisr_proto *snpp;
50888737be2SRobert Watson 	kvm_t *kd = kvmd;
5090153eb66SRobert Watson 	u_int i;
5100153eb66SRobert Watson 
51188737be2SRobert Watson 	if (live) {
51288737be2SRobert Watson 		netisr_load_sysctl_config();
51388737be2SRobert Watson 		netisr_load_sysctl_proto();
51488737be2SRobert Watson 		netisr_load_sysctl_workstream();
51588737be2SRobert Watson 		netisr_load_sysctl_work();
51688737be2SRobert Watson 	} else {
51788737be2SRobert Watson 		if (kd == NULL)
51888737be2SRobert Watson 			errx(-1, "netisr_stats: !live but !kd");
51988737be2SRobert Watson 		netisr_load_kvm_config(kd);
52088737be2SRobert Watson 		netisr_load_kvm_proto(kd);
52188737be2SRobert Watson 		netisr_load_kvm_workstream(kd);		/* Also does work. */
52288737be2SRobert Watson 	}
5230153eb66SRobert Watson 
5240153eb66SRobert Watson 	printf("Configuration:\n");
525bd9e7af2SRobert Watson 	printf("%-25s %12s %12s\n", "Setting", "Current", "Limit");
5260153eb66SRobert Watson 	printf("%-25s %12u %12u\n", "Thread count", numthreads, maxthreads);
5270153eb66SRobert Watson 	printf("%-25s %12u %12u\n", "Default queue limit", defaultqlimit,
5280153eb66SRobert Watson 	    maxqlimit);
5298f092df0SRobert Watson 	printf("%-25s %12s %12s\n", "Dispatch policy", dispatch_policy,
5308f092df0SRobert Watson 	    "n/a");
5310153eb66SRobert Watson 	printf("%-25s %12s %12s\n", "Threads bound to CPUs",
5320153eb66SRobert Watson 	    bindthreads ? "enabled" : "disabled", "n/a");
5330153eb66SRobert Watson 	printf("\n");
5340153eb66SRobert Watson 
5350153eb66SRobert Watson 	printf("Protocols:\n");
5368f092df0SRobert Watson 	printf("%-6s %5s %6s %-6s %-8s %-5s\n", "Name", "Proto", "QLimit",
5378f092df0SRobert Watson 	    "Policy", "Dispatch", "Flags");
5380153eb66SRobert Watson 	for (i = 0; i < proto_array_len; i++) {
5390153eb66SRobert Watson 		snpp = &proto_array[i];
5400153eb66SRobert Watson 		netisr_print_proto(snpp);
5410153eb66SRobert Watson 	}
5420153eb66SRobert Watson 	printf("\n");
5430153eb66SRobert Watson 
5440153eb66SRobert Watson 	printf("Workstreams:\n");
5450153eb66SRobert Watson 	printf("%4s %3s ", "WSID", "CPU");
5460153eb66SRobert Watson 	printf("%2s", "");
5470153eb66SRobert Watson 	printf("%-6s %5s %5s %8s %8s %8s %8s %8s\n", "Name", "Len", "WMark",
5480153eb66SRobert Watson 	    "Disp'd", "HDisp'd", "QDrops", "Queued", "Handled");
5490153eb66SRobert Watson 	for (i = 0; i < workstream_array_len; i++) {
5500153eb66SRobert Watson 		snwsp = &workstream_array[i];
5510153eb66SRobert Watson 		netisr_print_workstream(snwsp);
5520153eb66SRobert Watson 	}
5530153eb66SRobert Watson }
554