>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
     r...@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:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to