1 /*- 2 * Copyright (c) 2010 Juniper Networks, Inc. 3 * All rights reserved. 4 * 5 * This software was developed by Robert N. M. Watson under contract 6 * to Juniper Networks, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/types.h> 35 #include <sys/sysctl.h> 36 37 #include <net/netisr.h> 38 39 #include <err.h> 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 44 #include "netstat.h" 45 46 /* 47 * Print statistics for the kernel netisr subsystem. 48 */ 49 static u_int bindthreads; 50 static u_int maxthreads; 51 static u_int numthreads; 52 53 static u_int defaultqlimit; 54 static u_int maxqlimit; 55 56 static u_int direct; 57 static u_int direct_force; 58 59 static struct sysctl_netisr_proto *proto_array; 60 static u_int proto_array_len; 61 62 static struct sysctl_netisr_workstream *workstream_array; 63 static u_int workstream_array_len; 64 65 static struct sysctl_netisr_work *work_array; 66 static u_int work_array_len; 67 68 static void 69 netisr_load_sysctl_uint(const char *name, u_int *p) 70 { 71 size_t retlen; 72 73 retlen = sizeof(u_int); 74 if (sysctlbyname(name, p, &retlen, NULL, 0) < 0) 75 err(-1, "%s", name); 76 if (retlen != sizeof(u_int)) 77 errx(-1, "%s: invalid len %ju", name, (uintmax_t)retlen); 78 } 79 80 static void 81 netisr_load_config(void) 82 { 83 84 netisr_load_sysctl_uint("net.isr.bindthreads", &bindthreads); 85 netisr_load_sysctl_uint("net.isr.maxthreads", &maxthreads); 86 netisr_load_sysctl_uint("net.isr.numthreads", &numthreads); 87 88 netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit); 89 netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit); 90 91 netisr_load_sysctl_uint("net.isr.direct", &direct); 92 netisr_load_sysctl_uint("net.isr.direct_force", &direct_force); 93 } 94 95 static void 96 netisr_load_proto(void) 97 { 98 size_t len; 99 100 if (sysctlbyname("net.isr.proto", NULL, &len, NULL, 0) < 0) 101 err(-1, "net.isr.proto: query len"); 102 if (len % sizeof(*proto_array) != 0) 103 errx(-1, "net.isr.proto: invalid len"); 104 proto_array = malloc(len); 105 if (proto_array == NULL) 106 err(-1, "malloc"); 107 if (sysctlbyname("net.isr.proto", proto_array, &len, NULL, 0) < 0) 108 err(-1, "net.isr.proto: query data"); 109 if (len % sizeof(*proto_array) != 0) 110 errx(-1, "net.isr.proto: invalid len"); 111 proto_array_len = len / sizeof(*proto_array); 112 if (proto_array_len < 1) 113 errx(-1, "net.isr.proto: no data"); 114 if (proto_array[0].snp_version != sizeof(proto_array[0])) 115 errx(-1, "net.isr.proto: invalid version"); 116 } 117 118 static void 119 netisr_load_workstream(void) 120 { 121 size_t len; 122 123 if (sysctlbyname("net.isr.workstream", NULL, &len, NULL, 0) < 0) 124 err(-1, "net.isr.workstream: query len"); 125 if (len % sizeof(*workstream_array) != 0) 126 errx(-1, "net.isr.workstream: invalid len"); 127 workstream_array = malloc(len); 128 if (workstream_array == NULL) 129 err(-1, "malloc"); 130 if (sysctlbyname("net.isr.workstream", workstream_array, &len, NULL, 131 0) < 0) 132 err(-1, "net.isr.workstream: query data"); 133 if (len % sizeof(*workstream_array) != 0) 134 errx(-1, "net.isr.workstream: invalid len"); 135 workstream_array_len = len / sizeof(*workstream_array); 136 if (workstream_array_len < 1) 137 errx(-1, "net.isr.workstream: no data"); 138 if (workstream_array[0].snws_version != sizeof(workstream_array[0])) 139 errx(-1, "net.isr.workstream: invalid version"); 140 } 141 142 static void 143 netisr_load_work(void) 144 { 145 size_t len; 146 147 if (sysctlbyname("net.isr.work", NULL, &len, NULL, 0) < 0) 148 err(-1, "net.isr.work: query len"); 149 if (len % sizeof(*work_array) != 0) 150 errx(-1, "net.isr.work: invalid len"); 151 work_array = malloc(len); 152 if (work_array == NULL) 153 err(-1, "malloc"); 154 if (sysctlbyname("net.isr.work", work_array, &len, NULL, 0) < 0) 155 err(-1, "net.isr.work: query data"); 156 if (len % sizeof(*work_array) != 0) 157 errx(-1, "net.isr.work: invalid len"); 158 work_array_len = len / sizeof(*work_array); 159 if (work_array_len < 1) 160 errx(-1, "net.isr.work: no data"); 161 if (work_array[0].snw_version != sizeof(work_array[0])) 162 errx(-1, "net.isr.work: invalid version"); 163 } 164 165 static void 166 netisr_print_proto(struct sysctl_netisr_proto *snpp) 167 { 168 169 printf("%-6s", snpp->snp_name); 170 printf(" %5u", snpp->snp_proto); 171 printf(" %6u", snpp->snp_qlimit); 172 printf(" %6s", 173 (snpp->snp_policy == NETISR_POLICY_SOURCE) ? "source" : 174 (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" : 175 (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-"); 176 printf(" %s%s%s\n", 177 (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ? "C" : "-", 178 (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ? "D" : "-", 179 (snpp->snp_flags & NETISR_SNP_FLAGS_M2FLOW) ? "F" : "-"); 180 } 181 182 static const char * 183 netisr_proto2name(u_int proto) 184 { 185 u_int i; 186 187 for (i = 0; i < proto_array_len; i++) { 188 if (proto_array[i].snp_proto == proto) 189 return (proto_array[i].snp_name); 190 } 191 return ("unknown"); 192 } 193 194 static void 195 netisr_print_workstream(struct sysctl_netisr_workstream *snwsp) 196 { 197 struct sysctl_netisr_work *snwp; 198 int first; 199 u_int i; 200 201 first = 1; 202 for (i = 0; i < work_array_len; i++) { 203 snwp = &work_array[i]; 204 if (snwp->snw_wsid != snwsp->snws_wsid) 205 continue; 206 if (first) { 207 printf("%4u", snwsp->snws_wsid); 208 printf(" %3u", snwsp->snws_cpu); 209 first = 0; 210 } else 211 printf("%4s %3s", "", ""); 212 printf("%2s", ""); 213 printf("%-6s", netisr_proto2name(snwp->snw_proto)); 214 printf(" %5u", snwp->snw_len); 215 printf(" %5u", snwp->snw_watermark); 216 printf(" %8ju", snwp->snw_dispatched); 217 printf(" %8ju", snwp->snw_hybrid_dispatched); 218 printf(" %8ju", snwp->snw_qdrops); 219 printf(" %8ju", snwp->snw_queued); 220 printf(" %8ju", snwp->snw_handled); 221 printf("\n"); 222 } 223 } 224 225 void 226 netisr_stats(void) 227 { 228 struct sysctl_netisr_workstream *snwsp; 229 struct sysctl_netisr_proto *snpp; 230 u_int i; 231 232 netisr_load_config(); 233 netisr_load_proto(); 234 netisr_load_workstream(); 235 netisr_load_work(); 236 237 printf("Configuration:\n"); 238 printf("%-25s %12s %12s\n", "Setting", "Value", "Maximum"); 239 printf("%-25s %12u %12u\n", "Thread count", numthreads, maxthreads); 240 printf("%-25s %12u %12u\n", "Default queue limit", defaultqlimit, 241 maxqlimit); 242 printf("%-25s %12s %12s\n", "Direct dispatch", 243 direct ? "enabled" : "disabled", "n/a"); 244 printf("%-25s %12s %12s\n", "Forced direct dispatch", 245 direct_force ? "enabled" : "disabled", "n/a"); 246 printf("%-25s %12s %12s\n", "Threads bound to CPUs", 247 bindthreads ? "enabled" : "disabled", "n/a"); 248 printf("\n"); 249 250 printf("Protocols:\n"); 251 printf("%-6s %5s %6s %-6s %-5s\n", "Name", "Proto", "QLimit", 252 "Policy", "Flags"); 253 for (i = 0; i < proto_array_len; i++) { 254 snpp = &proto_array[i]; 255 netisr_print_proto(snpp); 256 } 257 printf("\n"); 258 259 printf("Workstreams:\n"); 260 printf("%4s %3s ", "WSID", "CPU"); 261 printf("%2s", ""); 262 printf("%-6s %5s %5s %8s %8s %8s %8s %8s\n", "Name", "Len", "WMark", 263 "Disp'd", "HDisp'd", "QDrops", "Queued", "Handled"); 264 for (i = 0; i < workstream_array_len; i++) { 265 snwsp = &workstream_array[i]; 266 netisr_print_workstream(snwsp); 267 } 268 } 269