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