summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2010-02-22 15:03:16 +0000
committerrwatson <rwatson@FreeBSD.org>2010-02-22 15:03:16 +0000
commitac0cbafef70fea6b297da40e08bd86b154e58079 (patch)
tree510a8ba708a854ce5dc4e8a6204b6fe733f00738
parent7028f4570c1624e31ea67864499192bb6f0cca2f (diff)
downloadFreeBSD-src-ac0cbafef70fea6b297da40e08bd86b154e58079.zip
FreeBSD-src-ac0cbafef70fea6b297da40e08bd86b154e58079.tar.gz
Export netisr configuration and statistics to userspace via sysctl(9).
MFC after: 1 week Sponsored by: Juniper Networks
-rw-r--r--sys/net/netisr.c168
-rw-r--r--sys/net/netisr.h88
2 files changed, 251 insertions, 5 deletions
diff --git a/sys/net/netisr.c b/sys/net/netisr.c
index 3574718..d74682f 100644
--- a/sys/net/netisr.c
+++ b/sys/net/netisr.c
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2007-2009 Robert N. M. Watson
+ * Copyright (c) 2010 Juniper Networks, Inc.
* All rights reserved.
*
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -1126,6 +1130,170 @@ netisr_start(void *arg)
}
SYSINIT(netisr_start, SI_SUB_SMP, SI_ORDER_MIDDLE, netisr_start, NULL);
+/*
+ * Sysctl monitoring for netisr: query a list of registered protocols.
+ */
+static int
+sysctl_netisr_proto(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_proto *snpp, *snp_array;
+ struct netisr_proto *npp;
+ u_int counter, proto;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snp_array = malloc(sizeof(*snp_array) * NETISR_MAXPROT, M_TEMP,
+ M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (proto = 0; proto < NETISR_MAXPROT; proto++) {
+ npp = &np[proto];
+ if (npp->np_name == NULL)
+ continue;
+ snpp = &snp_array[counter];
+ snpp->snp_version = sizeof(*snpp);
+ strlcpy(snpp->snp_name, npp->np_name, NETISR_NAMEMAXLEN);
+ snpp->snp_proto = proto;
+ snpp->snp_qlimit = npp->np_qlimit;
+ snpp->snp_policy = npp->np_policy;
+ if (npp->np_m2flow != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW;
+ if (npp->np_m2cpuid != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID;
+ if (npp->np_drainedcpu != NULL)
+ snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU;
+ counter++;
+ }
+ NETISR_RUNLOCK(&tracker);
+ KASSERT(counter < NETISR_MAXPROT,
+ ("sysctl_netisr_proto: counter too big (%d)", counter));
+ error = SYSCTL_OUT(req, snp_array, sizeof(*snp_array) * counter);
+ free(snp_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, proto,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_proto,
+ "S,sysctl_netisr_proto",
+ "Return list of protocols registered with netisr");
+
+/*
+ * Sysctl monitoring for netisr: query a list of workstreams.
+ */
+static int
+sysctl_netisr_workstream(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_workstream *snwsp, *snws_array;
+ struct netisr_workstream *nwsp;
+ u_int counter, cpuid;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snws_array = malloc(sizeof(*snws_array) * MAXCPU, M_TEMP,
+ M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (cpuid = 0; cpuid < MAXCPU; cpuid++) {
+ if (CPU_ABSENT(cpuid))
+ continue;
+ nwsp = DPCPU_ID_PTR(cpuid, nws);
+ if (nwsp->nws_intr_event == NULL)
+ continue;
+ NWS_LOCK(nwsp);
+ snwsp = &snws_array[counter];
+ snwsp->snws_version = sizeof(*snwsp);
+
+ /*
+ * For now, we equate workstream IDs and CPU IDs in the
+ * kernel, but expose them independently to userspace in case
+ * that assumption changes in the future.
+ */
+ snwsp->snws_wsid = cpuid;
+ snwsp->snws_cpu = cpuid;
+ if (nwsp->nws_intr_event != NULL)
+ snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR;
+ NWS_UNLOCK(nwsp);
+ counter++;
+ }
+ NETISR_RUNLOCK(&tracker);
+ KASSERT(counter < MAXCPU,
+ ("sysctl_netisr_workstream: counter too big (%d)", counter));
+ error = SYSCTL_OUT(req, snws_array, sizeof(*snws_array) * counter);
+ free(snws_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, workstream,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_workstream,
+ "S,sysctl_netisr_workstream",
+ "Return list of workstreams implemented by netisr");
+
+/*
+ * Sysctl monitoring for netisr: query per-protocol data across all
+ * workstreams.
+ */
+static int
+sysctl_netisr_work(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_netisr_work *snwp, *snw_array;
+ struct netisr_workstream *nwsp;
+ struct netisr_proto *npp;
+ struct netisr_work *nwp;
+ u_int counter, cpuid, proto;
+ int error;
+
+ if (req->newptr != NULL)
+ return (EINVAL);
+ snw_array = malloc(sizeof(*snw_array) * MAXCPU * NETISR_MAXPROT,
+ M_TEMP, M_ZERO | M_WAITOK);
+ counter = 0;
+ NETISR_RLOCK(&tracker);
+ for (cpuid = 0; cpuid < MAXCPU; cpuid++) {
+ if (CPU_ABSENT(cpuid))
+ continue;
+ nwsp = DPCPU_ID_PTR(cpuid, nws);
+ if (nwsp->nws_intr_event == NULL)
+ continue;
+ NWS_LOCK(nwsp);
+ for (proto = 0; proto < NETISR_MAXPROT; proto++) {
+ npp = &np[proto];
+ if (npp->np_name == NULL)
+ continue;
+ nwp = &nwsp->nws_work[proto];
+ snwp = &snw_array[counter];
+ snwp->snw_version = sizeof(*snwp);
+ snwp->snw_wsid = cpuid; /* See comment above. */
+ snwp->snw_proto = proto;
+ snwp->snw_len = nwp->nw_len;
+ snwp->snw_watermark = nwp->nw_watermark;
+ snwp->snw_dispatched = nwp->nw_dispatched;
+ snwp->snw_hybrid_dispatched =
+ nwp->nw_hybrid_dispatched;
+ snwp->snw_qdrops = nwp->nw_qdrops;
+ snwp->snw_queued = nwp->nw_queued;
+ snwp->snw_handled = nwp->nw_handled;
+ counter++;
+ }
+ NWS_UNLOCK(nwsp);
+ }
+ KASSERT(counter < MAXCPU * NETISR_MAXPROT,
+ ("sysctl_netisr_work: counter too big (%d)", counter));
+ NETISR_RUNLOCK(&tracker);
+ error = SYSCTL_OUT(req, snw_array, sizeof(*snw_array) * counter);
+ free(snw_array, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_net_isr, OID_AUTO, work,
+ CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_work,
+ "S,sysctl_netisr_work",
+ "Return list of per-workstream, per-protocol work in netisr");
+
#ifdef DDB
DB_SHOW_COMMAND(netisr, db_show_netisr)
{
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
index 0ab424f..e5ccbdb 100644
--- a/sys/net/netisr.h
+++ b/sys/net/netisr.h
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2007-2009 Robert N. M. Watson
+ * Copyright (c) 2010 Juniper Networks, Inc.
* All rights reserved.
*
+ * This software was developed by Robert N. M. Watson under contract
+ * to Juniper Networks, Inc.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -28,7 +32,6 @@
#ifndef _NET_NETISR_H_
#define _NET_NETISR_H_
-#ifdef _KERNEL
/*
* The netisr (network interrupt service routine) provides a deferred
@@ -39,6 +42,13 @@
* Historically, this was implemented by the BSD software ISR facility; it is
* now implemented via a software ithread (SWI).
*/
+
+/*
+ * Protocol numbers, which are encoded in monitoring applications and kernel
+ * modules. Internally, these are used in bit shift operations so must have
+ * a value 0 < proto < 32; we currently further limit at compile-time to 16
+ * for array-sizing purposes.
+ */
#define NETISR_IP 1
#define NETISR_IGMP 2 /* IGMPv3 output queue */
#define NETISR_ROUTE 3 /* routing socket */
@@ -52,6 +62,78 @@
#define NETISR_NATM 11
#define NETISR_EPAIR 12 /* if_epair(4) */
+/*
+ * Protocol ordering and affinity policy constants. See the detailed
+ * discussion of policies later in the file.
+ */
+#define NETISR_POLICY_SOURCE 1 /* Maintain source ordering. */
+#define NETISR_POLICY_FLOW 2 /* Maintain flow ordering. */
+#define NETISR_POLICY_CPU 3 /* Protocol determines CPU placement. */
+
+/*
+ * Monitoring data structures, exported by sysctl(2).
+ *
+ * Three sysctls are defined. First, a per-protocol structure exported by
+ * net.isr.proto.
+ */
+#define NETISR_NAMEMAXLEN 32
+struct sysctl_netisr_proto {
+ u_int snp_version; /* Length of struct. */
+ char snp_name[NETISR_NAMEMAXLEN]; /* nh_name */
+ u_int snp_proto; /* nh_proto */
+ u_int snp_qlimit; /* nh_qlimit */
+ u_int snp_policy; /* nh_policy */
+ u_int snp_flags; /* Various flags. */
+ u_int _snp_ispare[7];
+};
+
+/*
+ * Flags for sysctl_netisr_proto.snp_flags.
+ */
+#define NETISR_SNP_FLAGS_M2FLOW 0x00000001 /* nh_m2flow */
+#define NETISR_SNP_FLAGS_M2CPUID 0x00000002 /* nh_m2cpuid */
+#define NETISR_SNP_FLAGS_DRAINEDCPU 0x00000003 /* nh_drainedcpu */
+
+/*
+ * Next, a structure per-workstream, with per-protocol data, exported as
+ * net.isr.workstream.
+ */
+struct sysctl_netisr_workstream {
+ u_int snws_version; /* Length of struct. */
+ u_int snws_flags; /* Various flags. */
+ u_int snws_wsid; /* Workstream ID. */
+ u_int snws_cpu; /* nws_cpu */
+ u_int _snws_ispare[12];
+};
+
+/*
+ * Flags for sysctl_netisr_workstream.snws_flags
+ */
+#define NETISR_SNWS_FLAGS_INTR 0x00000001 /* nws_intr_event */
+
+/*
+ * Finally, a per-workstream-per-protocol structure, exported as
+ * net.isr.work.
+ */
+struct sysctl_netisr_work {
+ u_int snw_version; /* Length of struct. */
+ u_int snw_wsid; /* Workstream ID. */
+ u_int snw_proto; /* Protocol number. */
+ u_int snw_len; /* nw_len */
+ u_int snw_watermark; /* nw_watermark */
+ u_int _snw_ispare[3];
+
+ uint64_t snw_dispatched; /* nw_dispatched */
+ uint64_t snw_hybrid_dispatched; /* nw_hybrid_dispatched */
+ uint64_t snw_qdrops; /* nw_qdrops */
+ uint64_t snw_queued; /* nw_queued */
+ uint64_t snw_handled; /* nw_handled */
+
+ uint64_t _snw_llspare[7];
+};
+
+#ifdef _KERNEL
+
/*-
* Protocols express ordering constraints and affinity preferences by
* implementing one or neither of nh_m2flow and nh_m2cpuid, which are used by
@@ -91,10 +173,6 @@ typedef struct mbuf *netisr_m2cpuid_t(struct mbuf *m, uintptr_t source,
typedef struct mbuf *netisr_m2flow_t(struct mbuf *m, uintptr_t source);
typedef void netisr_drainedcpu_t(u_int cpuid);
-#define NETISR_POLICY_SOURCE 1 /* Maintain source ordering. */
-#define NETISR_POLICY_FLOW 2 /* Maintain flow ordering. */
-#define NETISR_POLICY_CPU 3 /* Protocol determines CPU placement. */
-
/*
* Data structure describing a protocol handler.
*/
OpenPOWER on IntegriCloud