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