misc/72183: em driver em_poll doesn't start send if pending packets

Mark Gooderum mark at verniernetworks.com
Wed Sep 29 14:10:23 PDT 2004

>Number:         72183
>Category:       misc
>Synopsis:       em driver em_poll doesn't start send if pending packets
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 29 21:10:22 GMT 2004
>Originator:     Mark Gooderum
>Release:        5.3 Beta 4
Vernier Networks, Inc.
FreeBSD 5.3-BETA4 FreeBSD 5.3-BETA4 #6: Tue Sep 28 21:35:19 PDT 2004     root at eagle.jumpadmin.net:/usr/build/ambit2/freebsd5/sys/i386/compile/VNISMP  i386

     The em driver has a reversed bit of logic in em_intr() - it will only restart transmission if the queue is empty, not if it is full.  em_poll DTRT.  Under high enough loads you can wedge a particular instance of an em interface although an ifconfig down/up will clear the condition.  The bug is still present in Beta 6.

      Blast a _lot_ of packets at the system with very little local activity.  We flushed this problem doing GigE<->GigE throughput tests with an Ixia.  Once the queue is full the interface will wedge on transmit because ifq_handoff() will never tickled if_start/em_start and em_intr() will incorrectly not call em_start_locked().  Downing/uping the interface will recover because the queue will be flushed - switching to polled will too as em_poll() DTRT.

If there is enough local activity the local sends will tickled em_start often enough to keep the queue from filling.  It's hard to reproduce the lockup without a piece of gear like an Ixia or Smartbits but the flaw in th elogic is obvious.

      The following patch has fixed the problem for us:

--- /tmp/tmp.44554.0    Wed Sep 29 15:52:32 2004
+++ /data/work/mark/5.3B4A1.i386/usr/build/ambit2/freebsd5/sys/dev/em/if_em.c   Wed Sep 29 15:51:31 2004
@@ -986,11 +986,11 @@

-        if (ifp->if_flags & IFF_RUNNING && IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+        if (ifp->if_flags & IFF_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd))



More information about the freebsd-bugs mailing list