kern/156769: netisr: SMP patch for 7.x and 6.x
Alexandr
alter at alter.org.ua
Mon May 2 16:10:10 UTC 2011
>Number: 156769
>Category: kern
>Synopsis: netisr: SMP patch for 7.x and 6.x
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Mon May 02 16:10:09 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: Alexandr
>Release: 7.2-RELEASE-p8
>Organization:
NetAssist
>Environment:
FreeBSD homecat.alter.org.ua 7.2-RELEASE-p8 FreeBSD 7.2-RELEASE-p8 #6: Sat Apr 23 12:52:20 EEST 2011
root at homecat.alter.org.ua:/usr/src/sys/i386/compile/CAT_v14c i386
>Description:
Network dispatch netisr can now be paralellized on SMP machines. Since netisr was not changed for a long time, this patch may bu suitable for earlier versions of kernel. Netisr behavior is now managed via sysctl:
net.isr.maxthreads=NNN
Also added one specific option:
net.isr.direct_arp=[0|1]
>How-To-Repeat:
>Fix:
http://alter.org.ua/soft/fbsd/netisr/netisr_smp.7x.20110501.patch.gz
Patch attached with submission follows:
diff -crN orig/sys/net/netisr.c new/sys/net/netisr.c
*** orig/sys/net/netisr.c Wed Apr 15 06:14:26 2009
--- new/sys/net/netisr.c Wed Apr 13 15:13:22 2011
***************
*** 55,61 ****
#include <net/if_var.h>
#include <net/netisr.h>
! volatile unsigned int netisr; /* scheduling bits for network */
struct netisr {
netisr_t *ni_handler;
--- 55,71 ----
#include <net/if_var.h>
#include <net/netisr.h>
! static MALLOC_DEFINE(M_NETISR, "netisr", "Net ISR dispatch");
!
! #ifdef SMP
! unsigned int netisrmask[MAXCPU+1]; /* scheduling bits for network */
! volatile unsigned int current_netisr; /* current isr thread */
! unsigned int unsafe_netisr_mask=0; /* unsafe isr nums */
! static void *net_ihs[MAXCPU];
! #else
! volatile unsigned int netisrmask; /* scheduling bits for network */
! static void *net_ih;
! #endif /* SMP */
struct netisr {
netisr_t *ni_handler;
***************
*** 63,76 ****
int ni_flags;
} netisrs[32];
- static void *net_ih;
-
- void
- legacy_setsoftnet(void)
- {
- swi_sched(net_ih, 0);
- }
-
void
netisr_register(int num, netisr_t *handler, struct ifqueue *inq, int flags)
{
--- 73,78 ----
***************
*** 80,85 ****
--- 82,94 ----
netisrs[num].ni_handler = handler;
netisrs[num].ni_queue = inq;
netisrs[num].ni_flags = flags;
+ #ifdef SMP
+ if(flags & NETISR_MPSAFE) {
+ unsafe_netisr_mask &= ~(1 << num);
+ } else {
+ unsafe_netisr_mask |= (1 << num);
+ }
+ #endif /* SMP */
}
void
***************
*** 94,99 ****
--- 103,111 ----
if (ni->ni_queue != NULL)
IF_DRAIN(ni->ni_queue);
ni->ni_queue = NULL;
+ #ifdef SMP
+ unsafe_netisr_mask &= ~(1 << num);
+ #endif /* SMP */
}
struct isrstat {
***************
*** 101,108 ****
--- 113,123 ----
int isrs_directed; /* ...directly dispatched */
int isrs_deferred; /* ...queued instead */
int isrs_queued; /* intentionally queueued */
+ int isrs_giant_queued;
+ int isrs_dequeued; /* dequeueued */
int isrs_drop; /* dropped 'cuz no handler */
int isrs_swi_count; /* swi_net handlers called */
+ int isrs_swi_retry_count; /* swi_net handlers loop retries */
};
static struct isrstat isrstat;
***************
*** 113,118 ****
--- 128,169 ----
&netisr_direct, 0, "enable direct dispatch");
TUNABLE_INT("net.isr.direct", &netisr_direct);
+ static int netisr_direct_arp = 1;
+ SYSCTL_INT(_net_isr, OID_AUTO, direct_arp, CTLFLAG_RW,
+ &netisr_direct_arp, 0, "enable direct ARP dispatch");
+ TUNABLE_INT("net.isr.direct_arp", &netisr_direct_arp);
+
+ #ifdef SMP
+ //static int netisr_active_threads = 1;
+ static int netisr_threads = 1;
+ static int max_netisr = MAXCPU;
+
+ static int
+ sysctl_netisr_threads(SYSCTL_HANDLER_ARGS)
+ {
+ int error, new_val;
+
+ if((netisr_threads > max_netisr) || (netisr_threads <= 0)) {
+ netisr_threads = max_netisr;
+ }
+ new_val = netisr_threads;
+
+ error = sysctl_handle_int(oidp, &new_val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if((new_val > max_netisr) || (new_val <= 0)) {
+ return (EINVAL);
+ }
+ netisr_threads = new_val;
+ return (0);
+ }
+
+ SYSCTL_PROC(_net_isr, OID_AUTO, maxthreads, CTLTYPE_INT|CTLFLAG_RW,
+ 0, sizeof(netisr_threads), sysctl_netisr_threads, "I",
+ "parallel NET-ISR threads");
+ //TUNABLE_INT("net.isr.maxthreads", &netisr_threads);
+ #endif /* SMP */
+
SYSCTL_INT(_net_isr, OID_AUTO, count, CTLFLAG_RD,
&isrstat.isrs_count, 0, "");
SYSCTL_INT(_net_isr, OID_AUTO, directed, CTLFLAG_RD,
***************
*** 121,130 ****
--- 172,187 ----
&isrstat.isrs_deferred, 0, "");
SYSCTL_INT(_net_isr, OID_AUTO, queued, CTLFLAG_RD,
&isrstat.isrs_queued, 0, "");
+ SYSCTL_INT(_net_isr, OID_AUTO, giant_queued, CTLFLAG_RD,
+ &isrstat.isrs_giant_queued, 0, "");
+ SYSCTL_INT(_net_isr, OID_AUTO, dequeued, CTLFLAG_RD,
+ &isrstat.isrs_dequeued, 0, "");
SYSCTL_INT(_net_isr, OID_AUTO, drop, CTLFLAG_RD,
&isrstat.isrs_drop, 0, "");
SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD,
&isrstat.isrs_swi_count, 0, "");
+ /*SYSCTL_INT(_net_isr, OID_AUTO, swi_retry_count, CTLFLAG_RD,
+ &isrs_swi_retry_count, 0, "");*/
/*
* Process all packets currently present in a netisr queue. Used to
***************
*** 140,149 ****
--- 197,229 ----
IF_DEQUEUE(ni->ni_queue, m);
if (m == NULL)
break;
+ isrstat.isrs_dequeued++;
ni->ni_handler(m);
}
}
+ void
+ legacy_setsoftnet(int isrbits)
+ {
+ #ifdef SMP
+ int i;
+ if(isrbits == (1 << NETISR_IP)) {
+ if(netisr_threads > max_netisr) {
+ netisr_threads = max_netisr;
+ }
+ i = current_netisr % netisr_threads;
+ current_netisr++;
+ } else {
+ i = 0;
+ }
+ atomic_set_rel_int(&(netisrmask[i]), isrbits);
+ swi_sched(net_ihs[i], 0);
+ #else
+ atomic_set_rel_int(&(netisrmask), isrbits);
+ swi_sched(net_ih, 0);
+ #endif /* SMP */
+ }
+
/*
* Call the netisr directly instead of queueing the packet, if possible.
*/
***************
*** 173,180 ****
* between multiple places in the system (e.g. IP
* dispatched from interfaces vs. IP queued from IPSec).
*/
! if (netisr_direct && (ni->ni_flags & NETISR_MPSAFE)) {
! isrstat.isrs_directed++;
/*
* NB: We used to drain the queue before handling
* the packet but now do not. Doing so here will
--- 253,263 ----
* between multiple places in the system (e.g. IP
* dispatched from interfaces vs. IP queued from IPSec).
*/
! if ((netisr_direct ||
! (netisr_direct_arp && (num == NETISR_ARP)))
! &&
! (ni->ni_flags & NETISR_MPSAFE)) {
! isrstat.isrs_directed++;
/*
* NB: We used to drain the queue before handling
* the packet but now do not. Doing so here will
***************
*** 211,216 ****
--- 294,302 ----
return (ENXIO);
}
isrstat.isrs_queued++;
+ if ((ni->ni_flags & NETISR_MPSAFE) == 0) {
+ isrstat.isrs_giant_queued++;
+ }
if (!IF_HANDOFF(ni->ni_queue, m, NULL))
return (ENOBUFS); /* IF_HANDOFF has free'd the mbuf */
schednetisr(num);
***************
*** 230,236 ****
#endif
do {
! bits = atomic_readandclear_int(&netisr);
if (bits == 0)
break;
while ((i = ffs(bits)) != 0) {
--- 316,326 ----
#endif
do {
! #ifdef SMP
! bits = atomic_readandclear_int((volatile int*)dummy);
! #else
! bits = atomic_readandclear_int(&netisrmask);
! #endif /* SMP */
if (bits == 0)
break;
while ((i = ffs(bits)) != 0) {
***************
*** 244,253 ****
}
if ((ni->ni_flags & NETISR_MPSAFE) == 0) {
mtx_lock(&Giant);
! if (ni->ni_queue == NULL)
ni->ni_handler(NULL);
! else
netisr_processqueue(ni);
mtx_unlock(&Giant);
} else {
if (ni->ni_queue == NULL)
--- 334,349 ----
}
if ((ni->ni_flags & NETISR_MPSAFE) == 0) {
mtx_lock(&Giant);
! if (ni->ni_queue == NULL) {
ni->ni_handler(NULL);
! } else {
! /*if(netisr_giant_workaround) {
! netisr_processqueue_gwa(ni);
! } else {
! netisr_processqueue(ni);
! }*/
netisr_processqueue(ni);
+ }
mtx_unlock(&Giant);
} else {
if (ni->ni_queue == NULL)
***************
*** 262,269 ****
static void
start_netisr(void *dummy)
{
!
! if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih))
! panic("start_netisr");
}
SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL);
--- 358,379 ----
static void
start_netisr(void *dummy)
{
! #ifdef SMP
! int i;
! char swiname[] = "netNNxxxx";
! current_netisr = 0;
! void *t;
!
! for(i=0; i<MAXCPU; i++) {
! netisrmask[i] = 0;
! sprintf(swiname, "net%d", i);
! t = &(netisrmask[i]);
! if (swi_add(NULL, swiname, swi_net, t, SWI_NET, INTR_MPSAFE, &(net_ihs[i])))
! panic("start_netisr");
! }
! #else
! if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih))
! panic("start_netisr");
! #endif /* SMP */
}
SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL);
diff -crN orig/sys/net/netisr.h new/sys/net/netisr.h
*** orig/sys/net/netisr.h Wed Apr 15 06:14:26 2009
--- new/sys/net/netisr.h Sat Oct 9 21:19:38 2010
***************
*** 63,79 ****
#ifndef LOCORE
#ifdef _KERNEL
! void legacy_setsoftnet(void);
extern volatile unsigned int netisr; /* scheduling bits for network */
#define schednetisr(anisr) do { \
! atomic_set_rel_int(&netisr, 1 << (anisr)); \
! legacy_setsoftnet(); \
} while (0)
/* used to atomically schedule multiple netisrs */
#define schednetisrbits(isrbits) do { \
! atomic_set_rel_int(&netisr, isrbits); \
! legacy_setsoftnet(); \
} while (0)
struct ifqueue;
--- 63,77 ----
#ifndef LOCORE
#ifdef _KERNEL
! void legacy_setsoftnet(int isrbits);
extern volatile unsigned int netisr; /* scheduling bits for network */
#define schednetisr(anisr) do { \
! legacy_setsoftnet(1 << (anisr)); \
} while (0)
/* used to atomically schedule multiple netisrs */
#define schednetisrbits(isrbits) do { \
! legacy_setsoftnet(isrbits); \
} while (0)
struct ifqueue;
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list