Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Feb 2010 15:03:16 +0000 (UTC)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r204199 - head/sys/net
Message-ID:  <201002221503.o1MF3GiU077539@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rwatson
Date: Mon Feb 22 15:03:16 2010
New Revision: 204199
URL: http://svn.freebsd.org/changeset/base/204199

Log:
  Export netisr configuration and statistics to userspace via sysctl(9).
  
  MFC after:	1 week
  Sponsored by:	Juniper Networks

Modified:
  head/sys/net/netisr.c
  head/sys/net/netisr.h

Modified: head/sys/net/netisr.c
==============================================================================
--- head/sys/net/netisr.c	Mon Feb 22 14:49:52 2010	(r204198)
+++ head/sys/net/netisr.c	Mon Feb 22 15:03:16 2010	(r204199)
@@ -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)
 {

Modified: head/sys/net/netisr.h
==============================================================================
--- head/sys/net/netisr.h	Mon Feb 22 14:49:52 2010	(r204198)
+++ head/sys/net/netisr.h	Mon Feb 22 15:03:16 2010	(r204199)
@@ -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(st
 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.
  */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002221503.o1MF3GiU077539>