11eaf0ac3Slogwang /*-
222ce4affSfengbojiang * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
322ce4affSfengbojiang *
41eaf0ac3Slogwang * Copyright (c) 2010-2011 Juniper Networks, Inc.
51eaf0ac3Slogwang * All rights reserved.
61eaf0ac3Slogwang *
71eaf0ac3Slogwang * This software was developed by Robert N. M. Watson under contract
81eaf0ac3Slogwang * to Juniper Networks, Inc.
91eaf0ac3Slogwang *
101eaf0ac3Slogwang * Redistribution and use in source and binary forms, with or without
111eaf0ac3Slogwang * modification, are permitted provided that the following conditions
121eaf0ac3Slogwang * are met:
131eaf0ac3Slogwang * 1. Redistributions of source code must retain the above copyright
141eaf0ac3Slogwang * notice, this list of conditions and the following disclaimer.
151eaf0ac3Slogwang * 2. Redistributions in binary form must reproduce the above copyright
161eaf0ac3Slogwang * notice, this list of conditions and the following disclaimer in the
171eaf0ac3Slogwang * documentation and/or other materials provided with the distribution.
181eaf0ac3Slogwang *
191eaf0ac3Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
201eaf0ac3Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211eaf0ac3Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221eaf0ac3Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
231eaf0ac3Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241eaf0ac3Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251eaf0ac3Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261eaf0ac3Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271eaf0ac3Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281eaf0ac3Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291eaf0ac3Slogwang * SUCH DAMAGE.
301eaf0ac3Slogwang */
311eaf0ac3Slogwang
321eaf0ac3Slogwang #include <sys/cdefs.h>
331eaf0ac3Slogwang
341eaf0ac3Slogwang __FBSDID("$FreeBSD$");
351eaf0ac3Slogwang
361eaf0ac3Slogwang #include <sys/param.h>
371eaf0ac3Slogwang #include <sys/sysctl.h>
381eaf0ac3Slogwang
391eaf0ac3Slogwang #include <sys/_lock.h>
401eaf0ac3Slogwang #include <sys/_mutex.h>
411eaf0ac3Slogwang
421eaf0ac3Slogwang #define _WANT_NETISR_INTERNAL
431eaf0ac3Slogwang #include <net/netisr.h>
441eaf0ac3Slogwang #include <net/netisr_internal.h>
451eaf0ac3Slogwang
461eaf0ac3Slogwang #include <err.h>
471eaf0ac3Slogwang #include <stdint.h>
481eaf0ac3Slogwang #include <stdio.h>
491eaf0ac3Slogwang #include <stdlib.h>
501eaf0ac3Slogwang #include <stdbool.h>
511eaf0ac3Slogwang #include <string.h>
521eaf0ac3Slogwang #include <libxo/xo.h>
531eaf0ac3Slogwang #include "netstat.h"
541eaf0ac3Slogwang #include "nl_defs.h"
551eaf0ac3Slogwang
561eaf0ac3Slogwang /*
571eaf0ac3Slogwang * Print statistics for the kernel netisr subsystem.
581eaf0ac3Slogwang */
591eaf0ac3Slogwang static u_int bindthreads;
601eaf0ac3Slogwang static u_int maxthreads;
611eaf0ac3Slogwang static u_int numthreads;
621eaf0ac3Slogwang
631eaf0ac3Slogwang static u_int defaultqlimit;
641eaf0ac3Slogwang static u_int maxqlimit;
651eaf0ac3Slogwang
661eaf0ac3Slogwang static char dispatch_policy[20];
671eaf0ac3Slogwang
681eaf0ac3Slogwang static struct sysctl_netisr_proto *proto_array;
691eaf0ac3Slogwang static u_int proto_array_len;
701eaf0ac3Slogwang
711eaf0ac3Slogwang static struct sysctl_netisr_workstream *workstream_array;
721eaf0ac3Slogwang static u_int workstream_array_len;
731eaf0ac3Slogwang
741eaf0ac3Slogwang static struct sysctl_netisr_work *work_array;
751eaf0ac3Slogwang static u_int work_array_len;
761eaf0ac3Slogwang
77*d4a07e70Sfengbojiang #ifndef FSTACK
781eaf0ac3Slogwang static u_int *nws_array;
791eaf0ac3Slogwang
801eaf0ac3Slogwang static u_int maxprot;
81*d4a07e70Sfengbojiang #endif
821eaf0ac3Slogwang
831eaf0ac3Slogwang static void
netisr_dispatch_policy_to_string(u_int policy,char * buf,size_t buflen)841eaf0ac3Slogwang netisr_dispatch_policy_to_string(u_int policy, char *buf,
851eaf0ac3Slogwang size_t buflen)
861eaf0ac3Slogwang {
871eaf0ac3Slogwang const char *str;
881eaf0ac3Slogwang
891eaf0ac3Slogwang switch (policy) {
901eaf0ac3Slogwang case NETISR_DISPATCH_DEFAULT:
911eaf0ac3Slogwang str = "default";
921eaf0ac3Slogwang break;
931eaf0ac3Slogwang case NETISR_DISPATCH_DEFERRED:
941eaf0ac3Slogwang str = "deferred";
951eaf0ac3Slogwang break;
961eaf0ac3Slogwang case NETISR_DISPATCH_HYBRID:
971eaf0ac3Slogwang str = "hybrid";
981eaf0ac3Slogwang break;
991eaf0ac3Slogwang case NETISR_DISPATCH_DIRECT:
1001eaf0ac3Slogwang str = "direct";
1011eaf0ac3Slogwang break;
1021eaf0ac3Slogwang default:
1031eaf0ac3Slogwang str = "unknown";
1041eaf0ac3Slogwang break;
1051eaf0ac3Slogwang }
1061eaf0ac3Slogwang snprintf(buf, buflen, "%s", str);
1071eaf0ac3Slogwang }
1081eaf0ac3Slogwang
109*d4a07e70Sfengbojiang #ifndef FSTACK
1101eaf0ac3Slogwang /*
1111eaf0ac3Slogwang * Load a nul-terminated string from KVM up to 'limit', guarantee that the
1121eaf0ac3Slogwang * string in local memory is nul-terminated.
1131eaf0ac3Slogwang */
1141eaf0ac3Slogwang static void
netisr_load_kvm_string(uintptr_t addr,char * dest,u_int limit)1151eaf0ac3Slogwang netisr_load_kvm_string(uintptr_t addr, char *dest, u_int limit)
1161eaf0ac3Slogwang {
1171eaf0ac3Slogwang u_int i;
1181eaf0ac3Slogwang
1191eaf0ac3Slogwang for (i = 0; i < limit; i++) {
1201eaf0ac3Slogwang if (kread(addr + i, &dest[i], sizeof(dest[i])) != 0)
1211eaf0ac3Slogwang xo_errx(-1, "%s: kread()", __func__);
1221eaf0ac3Slogwang if (dest[i] == '\0')
1231eaf0ac3Slogwang break;
1241eaf0ac3Slogwang }
1251eaf0ac3Slogwang dest[limit - 1] = '\0';
1261eaf0ac3Slogwang }
127*d4a07e70Sfengbojiang #endif
1281eaf0ac3Slogwang
1291eaf0ac3Slogwang static const char *
netisr_proto2name(u_int proto)1301eaf0ac3Slogwang netisr_proto2name(u_int proto)
1311eaf0ac3Slogwang {
1321eaf0ac3Slogwang u_int i;
1331eaf0ac3Slogwang
1341eaf0ac3Slogwang for (i = 0; i < proto_array_len; i++) {
1351eaf0ac3Slogwang if (proto_array[i].snp_proto == proto)
1361eaf0ac3Slogwang return (proto_array[i].snp_name);
1371eaf0ac3Slogwang }
1381eaf0ac3Slogwang return ("unknown");
1391eaf0ac3Slogwang }
1401eaf0ac3Slogwang
141*d4a07e70Sfengbojiang #ifndef FSTACK
1421eaf0ac3Slogwang static int
netisr_protoispresent(u_int proto)1431eaf0ac3Slogwang netisr_protoispresent(u_int proto)
1441eaf0ac3Slogwang {
1451eaf0ac3Slogwang u_int i;
1461eaf0ac3Slogwang
1471eaf0ac3Slogwang for (i = 0; i < proto_array_len; i++) {
1481eaf0ac3Slogwang if (proto_array[i].snp_proto == proto)
1491eaf0ac3Slogwang return (1);
1501eaf0ac3Slogwang }
1511eaf0ac3Slogwang return (0);
1521eaf0ac3Slogwang }
1531eaf0ac3Slogwang
1541eaf0ac3Slogwang static void
netisr_load_kvm_config(void)1551eaf0ac3Slogwang netisr_load_kvm_config(void)
1561eaf0ac3Slogwang {
1571eaf0ac3Slogwang u_int tmp;
1581eaf0ac3Slogwang
1591eaf0ac3Slogwang kread(nl[N_NETISR_BINDTHREADS].n_value, &bindthreads, sizeof(u_int));
1601eaf0ac3Slogwang kread(nl[N_NETISR_MAXTHREADS].n_value, &maxthreads, sizeof(u_int));
1611eaf0ac3Slogwang kread(nl[N_NWS_COUNT].n_value, &numthreads, sizeof(u_int));
1621eaf0ac3Slogwang kread(nl[N_NETISR_DEFAULTQLIMIT].n_value, &defaultqlimit,
1631eaf0ac3Slogwang sizeof(u_int));
1641eaf0ac3Slogwang kread(nl[N_NETISR_MAXQLIMIT].n_value, &maxqlimit, sizeof(u_int));
1651eaf0ac3Slogwang kread(nl[N_NETISR_DISPATCH_POLICY].n_value, &tmp, sizeof(u_int));
1661eaf0ac3Slogwang
1671eaf0ac3Slogwang netisr_dispatch_policy_to_string(tmp, dispatch_policy,
1681eaf0ac3Slogwang sizeof(dispatch_policy));
1691eaf0ac3Slogwang }
170*d4a07e70Sfengbojiang #endif
1711eaf0ac3Slogwang
1721eaf0ac3Slogwang static void
netisr_load_sysctl_uint(const char * name,u_int * p)1731eaf0ac3Slogwang netisr_load_sysctl_uint(const char *name, u_int *p)
1741eaf0ac3Slogwang {
1751eaf0ac3Slogwang size_t retlen;
1761eaf0ac3Slogwang
1771eaf0ac3Slogwang retlen = sizeof(u_int);
1781eaf0ac3Slogwang if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
1791eaf0ac3Slogwang xo_err(-1, "%s", name);
1801eaf0ac3Slogwang if (retlen != sizeof(u_int))
1811eaf0ac3Slogwang xo_errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen);
1821eaf0ac3Slogwang }
1831eaf0ac3Slogwang
1841eaf0ac3Slogwang static void
netisr_load_sysctl_string(const char * name,char * p,size_t len)1851eaf0ac3Slogwang netisr_load_sysctl_string(const char *name, char *p, size_t len)
1861eaf0ac3Slogwang {
1871eaf0ac3Slogwang size_t retlen;
1881eaf0ac3Slogwang
1891eaf0ac3Slogwang retlen = len;
1901eaf0ac3Slogwang if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
1911eaf0ac3Slogwang xo_err(-1, "%s", name);
1921eaf0ac3Slogwang p[len - 1] = '\0';
1931eaf0ac3Slogwang }
1941eaf0ac3Slogwang
1951eaf0ac3Slogwang static void
netisr_load_sysctl_config(void)1961eaf0ac3Slogwang netisr_load_sysctl_config(void)
1971eaf0ac3Slogwang {
1981eaf0ac3Slogwang
1991eaf0ac3Slogwang netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads);
2001eaf0ac3Slogwang netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads);
2011eaf0ac3Slogwang netisr_load_sysctl_uint("net.isr.numthreads", &numthreads);
2021eaf0ac3Slogwang
2031eaf0ac3Slogwang netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
2041eaf0ac3Slogwang netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
2051eaf0ac3Slogwang
2061eaf0ac3Slogwang netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy,
2071eaf0ac3Slogwang sizeof(dispatch_policy));
2081eaf0ac3Slogwang }
2091eaf0ac3Slogwang
210*d4a07e70Sfengbojiang #ifndef FSTACK
2111eaf0ac3Slogwang static void
netisr_load_kvm_proto(void)2121eaf0ac3Slogwang netisr_load_kvm_proto(void)
2131eaf0ac3Slogwang {
2141eaf0ac3Slogwang struct netisr_proto *np_array, *npp;
2151eaf0ac3Slogwang u_int i, protocount;
2161eaf0ac3Slogwang struct sysctl_netisr_proto *snpp;
2171eaf0ac3Slogwang size_t len;
2181eaf0ac3Slogwang
2191eaf0ac3Slogwang /*
2201eaf0ac3Slogwang * Kernel compile-time and user compile-time definitions of
2211eaf0ac3Slogwang * NETISR_MAXPROT must match, as we use that to size work arrays.
2221eaf0ac3Slogwang */
2231eaf0ac3Slogwang kread(nl[N_NETISR_MAXPROT].n_value, &maxprot, sizeof(u_int));
2241eaf0ac3Slogwang if (maxprot != NETISR_MAXPROT)
2251eaf0ac3Slogwang xo_errx(-1, "%s: NETISR_MAXPROT mismatch", __func__);
2261eaf0ac3Slogwang len = maxprot * sizeof(*np_array);
2271eaf0ac3Slogwang np_array = malloc(len);
2281eaf0ac3Slogwang if (np_array == NULL)
2291eaf0ac3Slogwang xo_err(-1, "%s: malloc", __func__);
2301eaf0ac3Slogwang if (kread(nl[N_NETISR_PROTO].n_value, np_array, len) != 0)
2311eaf0ac3Slogwang xo_errx(-1, "%s: kread(_netisr_proto)", __func__);
2321eaf0ac3Slogwang
2331eaf0ac3Slogwang /*
2341eaf0ac3Slogwang * Size and allocate memory to hold only live protocols.
2351eaf0ac3Slogwang */
2361eaf0ac3Slogwang protocount = 0;
2371eaf0ac3Slogwang for (i = 0; i < maxprot; i++) {
2381eaf0ac3Slogwang if (np_array[i].np_name == NULL)
2391eaf0ac3Slogwang continue;
2401eaf0ac3Slogwang protocount++;
2411eaf0ac3Slogwang }
2421eaf0ac3Slogwang proto_array = calloc(protocount, sizeof(*proto_array));
2431eaf0ac3Slogwang if (proto_array == NULL)
2441eaf0ac3Slogwang err(-1, "malloc");
2451eaf0ac3Slogwang protocount = 0;
2461eaf0ac3Slogwang for (i = 0; i < maxprot; i++) {
2471eaf0ac3Slogwang npp = &np_array[i];
2481eaf0ac3Slogwang if (npp->np_name == NULL)
2491eaf0ac3Slogwang continue;
2501eaf0ac3Slogwang snpp = &proto_array[protocount];
2511eaf0ac3Slogwang snpp->snp_version = sizeof(*snpp);
2521eaf0ac3Slogwang netisr_load_kvm_string((uintptr_t)npp->np_name,
2531eaf0ac3Slogwang snpp->snp_name, sizeof(snpp->snp_name));
2541eaf0ac3Slogwang snpp->snp_proto = i;
2551eaf0ac3Slogwang snpp->snp_qlimit = npp->np_qlimit;
2561eaf0ac3Slogwang snpp->snp_policy = npp->np_policy;
2571eaf0ac3Slogwang snpp->snp_dispatch = npp->np_dispatch;
2581eaf0ac3Slogwang if (npp->np_m2flow != NULL)
2591eaf0ac3Slogwang snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
2601eaf0ac3Slogwang if (npp->np_m2cpuid != NULL)
2611eaf0ac3Slogwang snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
2621eaf0ac3Slogwang if (npp->np_drainedcpu != NULL)
2631eaf0ac3Slogwang snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
2641eaf0ac3Slogwang protocount++;
2651eaf0ac3Slogwang }
2661eaf0ac3Slogwang proto_array_len = protocount;
2671eaf0ac3Slogwang free(np_array);
2681eaf0ac3Slogwang }
269*d4a07e70Sfengbojiang #endif
2701eaf0ac3Slogwang
2711eaf0ac3Slogwang static void
netisr_load_sysctl_proto(void)2721eaf0ac3Slogwang netisr_load_sysctl_proto(void)
2731eaf0ac3Slogwang {
2741eaf0ac3Slogwang size_t len;
2751eaf0ac3Slogwang
2761eaf0ac3Slogwang if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0)
2771eaf0ac3Slogwang xo_err(-1, "net.isr.proto: query len");
2781eaf0ac3Slogwang if (len % sizeof(*proto_array) != 0)
2791eaf0ac3Slogwang xo_errx(-1, "net.isr.proto: invalid len");
2801eaf0ac3Slogwang proto_array = malloc(len);
2811eaf0ac3Slogwang if (proto_array == NULL)
2821eaf0ac3Slogwang xo_err(-1, "malloc");
2831eaf0ac3Slogwang if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0)
2841eaf0ac3Slogwang xo_err(-1, "net.isr.proto: query data");
2851eaf0ac3Slogwang if (len % sizeof(*proto_array) != 0)
2861eaf0ac3Slogwang xo_errx(-1, "net.isr.proto: invalid len");
2871eaf0ac3Slogwang proto_array_len = len / sizeof(*proto_array);
2881eaf0ac3Slogwang if (proto_array_len < 1)
2891eaf0ac3Slogwang xo_errx(-1, "net.isr.proto: no data");
2901eaf0ac3Slogwang if (proto_array[0].snp_version != sizeof(proto_array[0]))
2911eaf0ac3Slogwang xo_errx(-1, "net.isr.proto: invalid version");
2921eaf0ac3Slogwang }
2931eaf0ac3Slogwang
294*d4a07e70Sfengbojiang #ifndef FSTACK
2951eaf0ac3Slogwang static void
netisr_load_kvm_workstream(void)2961eaf0ac3Slogwang netisr_load_kvm_workstream(void)
2971eaf0ac3Slogwang {
2981eaf0ac3Slogwang struct netisr_workstream nws;
2991eaf0ac3Slogwang struct sysctl_netisr_workstream *snwsp;
3001eaf0ac3Slogwang struct sysctl_netisr_work *snwp;
3011eaf0ac3Slogwang struct netisr_work *nwp;
3021eaf0ac3Slogwang u_int counter, cpuid, proto, wsid;
3031eaf0ac3Slogwang size_t len;
3041eaf0ac3Slogwang
3051eaf0ac3Slogwang len = numthreads * sizeof(*nws_array);
3061eaf0ac3Slogwang nws_array = malloc(len);
3071eaf0ac3Slogwang if (nws_array == NULL)
3081eaf0ac3Slogwang xo_err(-1, "malloc");
3091eaf0ac3Slogwang if (kread(nl[N_NWS_ARRAY].n_value, nws_array, len) != 0)
3101eaf0ac3Slogwang xo_errx(-1, "%s: kread(_nws_array)", __func__);
3111eaf0ac3Slogwang workstream_array = calloc(numthreads, sizeof(*workstream_array));
3121eaf0ac3Slogwang if (workstream_array == NULL)
3131eaf0ac3Slogwang xo_err(-1, "calloc");
3141eaf0ac3Slogwang workstream_array_len = numthreads;
3151eaf0ac3Slogwang work_array = calloc(numthreads * proto_array_len, sizeof(*work_array));
3161eaf0ac3Slogwang if (work_array == NULL)
3171eaf0ac3Slogwang xo_err(-1, "calloc");
3181eaf0ac3Slogwang counter = 0;
3191eaf0ac3Slogwang for (wsid = 0; wsid < numthreads; wsid++) {
3201eaf0ac3Slogwang cpuid = nws_array[wsid];
3211eaf0ac3Slogwang kset_dpcpu(cpuid);
3221eaf0ac3Slogwang if (kread(nl[N_NWS].n_value, &nws, sizeof(nws)) != 0)
3231eaf0ac3Slogwang xo_errx(-1, "%s: kread(nw)", __func__);
3241eaf0ac3Slogwang snwsp = &workstream_array[wsid];
3251eaf0ac3Slogwang snwsp->snws_version = sizeof(*snwsp);
3261eaf0ac3Slogwang snwsp->snws_wsid = cpuid;
3271eaf0ac3Slogwang snwsp->snws_cpu = cpuid;
3281eaf0ac3Slogwang if (nws.nws_intr_event != NULL)
3291eaf0ac3Slogwang snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
3301eaf0ac3Slogwang
3311eaf0ac3Slogwang /*
3321eaf0ac3Slogwang * Extract the CPU's per-protocol work information.
3331eaf0ac3Slogwang */
3341eaf0ac3Slogwang xo_emit("counting to maxprot: {:maxprot/%u}\n", maxprot);
3351eaf0ac3Slogwang for (proto = 0; proto < maxprot; proto++) {
3361eaf0ac3Slogwang if (!netisr_protoispresent(proto))
3371eaf0ac3Slogwang continue;
3381eaf0ac3Slogwang nwp = &nws.nws_work[proto];
3391eaf0ac3Slogwang snwp = &work_array[counter];
3401eaf0ac3Slogwang snwp->snw_version = sizeof(*snwp);
3411eaf0ac3Slogwang snwp->snw_wsid = cpuid;
3421eaf0ac3Slogwang snwp->snw_proto = proto;
3431eaf0ac3Slogwang snwp->snw_len = nwp->nw_len;
3441eaf0ac3Slogwang snwp->snw_watermark = nwp->nw_watermark;
3451eaf0ac3Slogwang snwp->snw_dispatched = nwp->nw_dispatched;
3461eaf0ac3Slogwang snwp->snw_hybrid_dispatched =
3471eaf0ac3Slogwang nwp->nw_hybrid_dispatched;
3481eaf0ac3Slogwang snwp->snw_qdrops = nwp->nw_qdrops;
3491eaf0ac3Slogwang snwp->snw_queued = nwp->nw_queued;
3501eaf0ac3Slogwang snwp->snw_handled = nwp->nw_handled;
3511eaf0ac3Slogwang counter++;
3521eaf0ac3Slogwang }
3531eaf0ac3Slogwang }
3541eaf0ac3Slogwang work_array_len = counter;
3551eaf0ac3Slogwang }
356*d4a07e70Sfengbojiang #endif
3571eaf0ac3Slogwang
3581eaf0ac3Slogwang static void
netisr_load_sysctl_workstream(void)3591eaf0ac3Slogwang netisr_load_sysctl_workstream(void)
3601eaf0ac3Slogwang {
3611eaf0ac3Slogwang size_t len;
3621eaf0ac3Slogwang
3631eaf0ac3Slogwang if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0)
3641eaf0ac3Slogwang xo_err(-1, "net.isr.workstream: query len");
3651eaf0ac3Slogwang if (len % sizeof(*workstream_array) != 0)
3661eaf0ac3Slogwang xo_errx(-1, "net.isr.workstream: invalid len");
3671eaf0ac3Slogwang workstream_array = malloc(len);
3681eaf0ac3Slogwang if (workstream_array == NULL)
3691eaf0ac3Slogwang xo_err(-1, "malloc");
3701eaf0ac3Slogwang if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL,
3711eaf0ac3Slogwang 0) < 0)
3721eaf0ac3Slogwang xo_err(-1, "net.isr.workstream: query data");
3731eaf0ac3Slogwang if (len % sizeof(*workstream_array) != 0)
3741eaf0ac3Slogwang xo_errx(-1, "net.isr.workstream: invalid len");
3751eaf0ac3Slogwang workstream_array_len = len / sizeof(*workstream_array);
3761eaf0ac3Slogwang if (workstream_array_len < 1)
3771eaf0ac3Slogwang xo_errx(-1, "net.isr.workstream: no data");
3781eaf0ac3Slogwang if (workstream_array[0].snws_version != sizeof(workstream_array[0]))
3791eaf0ac3Slogwang xo_errx(-1, "net.isr.workstream: invalid version");
3801eaf0ac3Slogwang }
3811eaf0ac3Slogwang
3821eaf0ac3Slogwang static void
netisr_load_sysctl_work(void)3831eaf0ac3Slogwang netisr_load_sysctl_work(void)
3841eaf0ac3Slogwang {
3851eaf0ac3Slogwang size_t len;
3861eaf0ac3Slogwang
3871eaf0ac3Slogwang if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0)
3881eaf0ac3Slogwang xo_err(-1, "net.isr.work: query len");
3891eaf0ac3Slogwang if (len % sizeof(*work_array) != 0)
3901eaf0ac3Slogwang xo_errx(-1, "net.isr.work: invalid len");
3911eaf0ac3Slogwang work_array = malloc(len);
3921eaf0ac3Slogwang if (work_array == NULL)
3931eaf0ac3Slogwang xo_err(-1, "malloc");
3941eaf0ac3Slogwang if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0)
3951eaf0ac3Slogwang xo_err(-1, "net.isr.work: query data");
3961eaf0ac3Slogwang if (len % sizeof(*work_array) != 0)
3971eaf0ac3Slogwang xo_errx(-1, "net.isr.work: invalid len");
3981eaf0ac3Slogwang work_array_len = len / sizeof(*work_array);
3991eaf0ac3Slogwang if (work_array_len < 1)
4001eaf0ac3Slogwang xo_errx(-1, "net.isr.work: no data");
4011eaf0ac3Slogwang if (work_array[0].snw_version != sizeof(work_array[0]))
4021eaf0ac3Slogwang xo_errx(-1, "net.isr.work: invalid version");
4031eaf0ac3Slogwang }
4041eaf0ac3Slogwang
4051eaf0ac3Slogwang static void
netisr_print_proto(struct sysctl_netisr_proto * snpp)4061eaf0ac3Slogwang netisr_print_proto(struct sysctl_netisr_proto *snpp)
4071eaf0ac3Slogwang {
4081eaf0ac3Slogwang char tmp[20];
4091eaf0ac3Slogwang
4101eaf0ac3Slogwang xo_emit("{[:-6}{k:name/%s}{]:}", snpp->snp_name);
4111eaf0ac3Slogwang xo_emit(" {:protocol/%5u}", snpp->snp_proto);
4121eaf0ac3Slogwang xo_emit(" {:queue-limit/%6u}", snpp->snp_qlimit);
4131eaf0ac3Slogwang xo_emit(" {:policy-type/%6s}",
4141eaf0ac3Slogwang (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" :
4151eaf0ac3Slogwang (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
4161eaf0ac3Slogwang (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
4171eaf0ac3Slogwang netisr_dispatch_policy_to_string(snpp->snp_dispatch, tmp,
4181eaf0ac3Slogwang sizeof(tmp));
4191eaf0ac3Slogwang xo_emit(" {:policy/%8s}", tmp);
4201eaf0ac3Slogwang xo_emit(" {:flags/%s%s%s}\n",
4211eaf0ac3Slogwang (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-",
4221eaf0ac3Slogwang (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-",
4231eaf0ac3Slogwang (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-");
4241eaf0ac3Slogwang }
4251eaf0ac3Slogwang
4261eaf0ac3Slogwang static void
netisr_print_workstream(struct sysctl_netisr_workstream * snwsp)4271eaf0ac3Slogwang netisr_print_workstream(struct sysctl_netisr_workstream *snwsp)
4281eaf0ac3Slogwang {
4291eaf0ac3Slogwang struct sysctl_netisr_work *snwp;
4301eaf0ac3Slogwang u_int i;
4311eaf0ac3Slogwang
4321eaf0ac3Slogwang xo_open_list("work");
4331eaf0ac3Slogwang for (i = 0; i < work_array_len; i++) {
4341eaf0ac3Slogwang snwp = &work_array[i];
4351eaf0ac3Slogwang if (snwp->snw_wsid != snwsp->snws_wsid)
4361eaf0ac3Slogwang continue;
4371eaf0ac3Slogwang xo_open_instance("work");
4381eaf0ac3Slogwang xo_emit("{t:workstream/%4u} ", snwsp->snws_wsid);
4391eaf0ac3Slogwang xo_emit("{t:cpu/%3u} ", snwsp->snws_cpu);
4401eaf0ac3Slogwang xo_emit("{P: }");
4411eaf0ac3Slogwang xo_emit("{t:name/%-6s}", netisr_proto2name(snwp->snw_proto));
4421eaf0ac3Slogwang xo_emit(" {t:length/%5u}", snwp->snw_len);
4431eaf0ac3Slogwang xo_emit(" {t:watermark/%5u}", snwp->snw_watermark);
4441eaf0ac3Slogwang xo_emit(" {t:dispatched/%8ju}", snwp->snw_dispatched);
4451eaf0ac3Slogwang xo_emit(" {t:hybrid-dispatched/%8ju}",
4461eaf0ac3Slogwang snwp->snw_hybrid_dispatched);
4471eaf0ac3Slogwang xo_emit(" {t:queue-drops/%8ju}", snwp->snw_qdrops);
4481eaf0ac3Slogwang xo_emit(" {t:queued/%8ju}", snwp->snw_queued);
4491eaf0ac3Slogwang xo_emit(" {t:handled/%8ju}", snwp->snw_handled);
4501eaf0ac3Slogwang xo_emit("\n");
4511eaf0ac3Slogwang xo_close_instance("work");
4521eaf0ac3Slogwang }
4531eaf0ac3Slogwang xo_close_list("work");
4541eaf0ac3Slogwang }
4551eaf0ac3Slogwang
4561eaf0ac3Slogwang void
netisr_stats(void)4571eaf0ac3Slogwang netisr_stats(void)
4581eaf0ac3Slogwang {
4591eaf0ac3Slogwang struct sysctl_netisr_workstream *snwsp;
4601eaf0ac3Slogwang struct sysctl_netisr_proto *snpp;
4611eaf0ac3Slogwang u_int i;
4621eaf0ac3Slogwang
4631eaf0ac3Slogwang if (live) {
4641eaf0ac3Slogwang netisr_load_sysctl_config();
4651eaf0ac3Slogwang netisr_load_sysctl_proto();
4661eaf0ac3Slogwang netisr_load_sysctl_workstream();
4671eaf0ac3Slogwang netisr_load_sysctl_work();
4681eaf0ac3Slogwang } else {
469*d4a07e70Sfengbojiang #ifndef FSTACK
4701eaf0ac3Slogwang netisr_load_kvm_config();
4711eaf0ac3Slogwang netisr_load_kvm_proto();
4721eaf0ac3Slogwang netisr_load_kvm_workstream(); /* Also does work. */
473*d4a07e70Sfengbojiang #endif
4741eaf0ac3Slogwang }
4751eaf0ac3Slogwang
4761eaf0ac3Slogwang xo_open_container("netisr");
4771eaf0ac3Slogwang
4781eaf0ac3Slogwang xo_emit("{T:Configuration}:\n");
4791eaf0ac3Slogwang xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
4801eaf0ac3Slogwang "Setting", "Current", "Limit");
4811eaf0ac3Slogwang xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
4821eaf0ac3Slogwang "Thread count", numthreads, maxthreads);
4831eaf0ac3Slogwang xo_emit("{T:/%-25s} {T:/%12u} {T:/%12u}\n",
4841eaf0ac3Slogwang "Default queue limit", defaultqlimit, maxqlimit);
4851eaf0ac3Slogwang xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
4861eaf0ac3Slogwang "Dispatch policy", dispatch_policy, "n/a");
4871eaf0ac3Slogwang xo_emit("{T:/%-25s} {T:/%12s} {T:/%12s}\n",
4881eaf0ac3Slogwang "Threads bound to CPUs", bindthreads ? "enabled" : "disabled",
4891eaf0ac3Slogwang "n/a");
4901eaf0ac3Slogwang xo_emit("\n");
4911eaf0ac3Slogwang
4921eaf0ac3Slogwang xo_emit("{T:Protocols}:\n");
4931eaf0ac3Slogwang xo_emit("{T:/%-6s} {T:/%5s} {T:/%6s} {T:/%-6s} {T:/%-8s} {T:/%-5s}\n",
4941eaf0ac3Slogwang "Name", "Proto", "QLimit", "Policy", "Dispatch", "Flags");
4951eaf0ac3Slogwang xo_open_list("protocol");
4961eaf0ac3Slogwang for (i = 0; i < proto_array_len; i++) {
4971eaf0ac3Slogwang xo_open_instance("protocol");
4981eaf0ac3Slogwang snpp = &proto_array[i];
4991eaf0ac3Slogwang netisr_print_proto(snpp);
5001eaf0ac3Slogwang xo_close_instance("protocol");
5011eaf0ac3Slogwang }
5021eaf0ac3Slogwang xo_close_list("protocol");
5031eaf0ac3Slogwang xo_emit("\n");
5041eaf0ac3Slogwang
5051eaf0ac3Slogwang xo_emit("{T:Workstreams}:\n");
5061eaf0ac3Slogwang xo_emit("{T:/%4s} {T:/%3s} ", "WSID", "CPU");
5071eaf0ac3Slogwang xo_emit("{P:/%2s}", "");
5081eaf0ac3Slogwang xo_emit("{T:/%-6s} {T:/%5s} {T:/%5s} {T:/%8s} {T:/%8s} {T:/%8s} "
5091eaf0ac3Slogwang "{T:/%8s} {T:/%8s}\n",
5101eaf0ac3Slogwang "Name", "Len", "WMark", "Disp'd", "HDisp'd", "QDrops", "Queued",
5111eaf0ac3Slogwang "Handled");
5121eaf0ac3Slogwang xo_open_list("workstream");
5131eaf0ac3Slogwang for (i = 0; i < workstream_array_len; i++) {
5141eaf0ac3Slogwang xo_open_instance("workstream");
5151eaf0ac3Slogwang snwsp = &workstream_array[i];
5161eaf0ac3Slogwang netisr_print_workstream(snwsp);
5171eaf0ac3Slogwang xo_close_instance("workstream");
5181eaf0ac3Slogwang }
5191eaf0ac3Slogwang xo_close_list("workstream");
5201eaf0ac3Slogwang xo_close_container("netisr");
5211eaf0ac3Slogwang }
522