Export netisr configuration and statistics to userspace via sysctl(9).

MFC after:	1 week
Sponsored by:	Juniper Networks
This commit is contained in:
Robert Watson 2010-02-22 15:03:16 +00:00
parent 4cd0801096
commit 2d22f334ea
2 changed files with 251 additions and 5 deletions

View File

@ -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)
{

View File

@ -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.
*/