Teach netstat(1) about the new global netisr policy sysctl,
net.isr.dispatch, and about per-protocol dispatch policies.

MFC after:	3 weeks
Reviewed by:	bz
Sponsored by:	Juniper Networks, Inc.

Index: netstat/netisr.c
===================================================================
--- netstat/netisr.c	(revision 219626)
+++ netstat/netisr.c	(working copy)
@@ -60,8 +60,7 @@
 static u_int				 defaultqlimit;
 static u_int				 maxqlimit;
 
-static u_int				 direct;
-static u_int				 direct_force;
+static char				 dispatch_policy[20];
 
 static struct sysctl_netisr_proto	*proto_array;
 static u_int				 proto_array_len;
@@ -77,6 +76,32 @@
 static u_int				 maxprot;
 
 static void
+netisr_dispatch_policy_from_str(u_int dispatch_policy, char *buf,
+    size_t buflen)
+{
+	const char *str;
+
+	switch (dispatch_policy) {
+	case NETISR_DISPATCH_DEFAULT:
+		str = "default";
+		break;
+	case NETISR_DISPATCH_DEFERRED:
+		str = "deferred";
+		break;
+	case NETISR_DISPATCH_HYBRID:
+		str = "hybrid";
+		break;
+	case NETISR_DISPATCH_DIRECT:
+		str = "direct";
+		break;
+	default:
+		str = "unknown";
+		break;
+	}
+	snprintf(buf, buflen, "%s", str);
+}
+
+static void
 netisr_load_kvm_uint(kvm_t *kd, char *name, u_int *p)
 {
 	struct nlist nl[] = {
@@ -102,7 +127,8 @@
  * string in local memory is nul-terminated.
  */
 static void
-netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest, u_int limit)
+netisr_load_kvm_string(kvm_t *kd, uintptr_t addr, char *dest,
+    u_int limit)
 {
 	u_int i;
 
@@ -144,6 +170,7 @@
 static void
 netisr_load_kvm_config(kvm_t *kd)
 {
+	u_int tmp;
 
 	netisr_load_kvm_uint(kd, "_netisr_bindthreads", &bindthreads);
 	netisr_load_kvm_uint(kd, "_netisr_maxthreads", &maxthreads);
@@ -152,8 +179,9 @@
 	netisr_load_kvm_uint(kd, "_netisr_defaultqlimit", &defaultqlimit);
 	netisr_load_kvm_uint(kd, "_netisr_maxqlimit", &maxqlimit);
 
-	netisr_load_kvm_uint(kd, "_netisr_direct", &direct);
-	netisr_load_kvm_uint(kd, "_netisr_direct_force", &direct_force);
+	netisr_load_kvm_uint(kd, "_netisr_dispatch_policy", &tmp);
+	netisr_dispatch_policy_from_str(tmp, dispatch_policy,
+	    sizeof(dispatch_policy));
 }
 
 static void
@@ -169,6 +197,17 @@
 }
 
 static void
+netisr_load_sysctl_string(const char *name, char *p, size_t len)
+{
+	size_t retlen;
+
+	retlen = len;
+	if (sysctlbyname(name, p, &retlen, NULL, 0) < 0)
+		err(-1, "%s", name);
+	p[len - 1] = '\0';
+}
+
+static void
 netisr_load_sysctl_config(void)
 {
 
@@ -179,8 +218,8 @@
 	netisr_load_sysctl_uint("net.isr.defaultqlimit", &defaultqlimit);
 	netisr_load_sysctl_uint("net.isr.maxqlimit", &maxqlimit);
 
-	netisr_load_sysctl_uint("net.isr.direct", &direct);
-	netisr_load_sysctl_uint("net.isr.direct_force", &direct_force);
+	netisr_load_sysctl_string("net.isr.dispatch", dispatch_policy,
+	    sizeof(dispatch_policy));
 }
 
 static void
@@ -244,6 +283,7 @@
 		snpp->snp_proto = i;
 		snpp->snp_qlimit = npp->np_qlimit;
 		snpp->snp_policy = npp->np_policy;
+		snpp->snp_dispatch = npp->np_dispatch;
 		if (npp->np_m2flow != NULL)
 			snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
 		if (npp->np_m2cpuid != NULL)
@@ -418,6 +458,7 @@
 static void
 netisr_print_proto(struct sysctl_netisr_proto *snpp)
 {
+	char tmp[20];
 
 	printf("%-6s", snpp->snp_name);
 	printf(" %5u", snpp->snp_proto);
@@ -426,6 +467,9 @@
 	    (snpp->snp_policy == NETISR_POLICY_SOURCE) ?  "source" :
 	    (snpp->snp_policy == NETISR_POLICY_FLOW) ? "flow" :
 	    (snpp->snp_policy == NETISR_POLICY_CPU) ? "cpu" : "-");
+	netisr_dispatch_policy_from_str(snpp->snp_dispatch, tmp,
+	    sizeof(tmp));
+	printf(" %8s", tmp);
 	printf("   %s%s%s\n",
 	    (snpp->snp_flags & NETISR_SNP_FLAGS_M2CPUID) ?  "C" : "-",
 	    (snpp->snp_flags & NETISR_SNP_FLAGS_DRAINEDCPU) ?  "D" : "-",
@@ -483,17 +527,15 @@
 	printf("%-25s %12u %12u\n", "Thread count", numthreads, maxthreads);
 	printf("%-25s %12u %12u\n", "Default queue limit", defaultqlimit,
 	    maxqlimit);
-	printf("%-25s %12s %12s\n", "Direct dispatch", 
-	    direct ? "enabled" : "disabled", "n/a");
-	printf("%-25s %12s %12s\n", "Forced direct dispatch",
-	    direct_force ? "enabled" : "disabled", "n/a");
+	printf("%-25s %12s %12s\n", "Dispatch policy", dispatch_policy,
+	    "n/a");
 	printf("%-25s %12s %12s\n", "Threads bound to CPUs",
 	    bindthreads ? "enabled" : "disabled", "n/a");
 	printf("\n");
 
 	printf("Protocols:\n");
-	printf("%-6s %5s %6s %-6s %-5s\n", "Name", "Proto", "QLimit",
-	    "Policy", "Flags");
+	printf("%-6s %5s %6s %-6s %-8s %-5s\n", "Name", "Proto", "QLimit",
+	    "Policy", "Dispatch", "Flags");
 	for (i = 0; i < proto_array_len; i++) {
 		snpp = &proto_array[i];
 		netisr_print_proto(snpp);
