Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 5 Feb 2010 03:51:12 +0100
From:      Max Laier <max@love2party.net>
To:        freebsd-stable@freebsd.org
Cc:        pyunyh@gmail.com, Nick Rogers <ncrogers@gmail.com>, jfv@freebsd.org, Jack Vogel <jfvogel@gmail.com>
Subject:   Re: em(4) + ALTQ broken
Message-ID:  <201002050351.12270.max@love2party.net>
In-Reply-To: <2a41acea1002021447t1067ee42gc59b25216270459b@mail.gmail.com>
References:  <147432021001310037n1b67f01bx4b4e8781321cea8@mail.gmail.com> <2a41acea1002021443t1c298528i2df3cf40269c733@mail.gmail.com> <2a41acea1002021447t1067ee42gc59b25216270459b@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
--Boundary-00=_ge4aL9vBl3gxbuc
Content-Type: Text/Plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Okay ... attached is a patch to fix this for em(4) (and lay the groundwork to 
fix it for other drbr_* consumer as well).  I have tested it in VirtualBox, 
but don't have real hardware to check for non-ALTQ performance or other 
regressions.

Test, comments and review appreciated.

--
  Max

--Boundary-00=_ge4aL9vBl3gxbuc
Content-Type: text/x-patch;
  charset="ISO-8859-1";
  name="drbr_altq.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="drbr_altq.diff"

Index: sys/dev/e1000/if_em.c
===================================================================
--- sys/dev/e1000/if_em.c	(revision 203362)
+++ sys/dev/e1000/if_em.c	(working copy)
@@ -943,7 +943,7 @@
 {
 	struct adapter	*adapter = ifp->if_softc;
 	struct mbuf	*next;
-	int error = E1000_SUCCESS;
+	int ret, error = E1000_SUCCESS;
 
 	EM_TX_LOCK_ASSERT(adapter);
 	/* To allow being called from a tasklet */
@@ -955,28 +955,34 @@
 	    || (!adapter->link_active)) {
 		error = drbr_enqueue(ifp, adapter->br, m);
 		return (error);
-	} else if (drbr_empty(ifp, adapter->br) &&
-	    (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
-		if ((error = em_xmit(adapter, &m)) != 0) {
-			if (m)
-				error = drbr_enqueue(ifp, adapter->br, m);
+	}
+	ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+	if (ret == 0) {
+		if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+			if ((error = em_xmit(adapter, &m)) != 0) {
+				if (m)
+					error = drbr_enqueue(ifp, adapter->br,
+					    m);
+				return (error);
+			} else {
+				/*
+				 * We've bypassed the buf ring so we need to
+				 * update ifp directly
+				 */
+				drbr_stats_update(ifp, m->m_pkthdr.len,
+				    m->m_flags);
+				/*
+				** Send a copy of the frame to the BPF
+				** listener and set the watchdog on.
+				*/
+				ETHER_BPF_MTAP(ifp, m);
+				adapter->watchdog_check = TRUE;
+			}
+		} else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
 			return (error);
-		} else {
-			/*
-			 * We've bypassed the buf ring so we need to update
-			 * ifp directly
-			 */
-			drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
-			/*
-			** Send a copy of the frame to the BPF
-			** listener and set the watchdog on.
-			*/
-			ETHER_BPF_MTAP(ifp, m);
-			adapter->watchdog_check = TRUE;
-		}
-	} else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
-		return (error);
-	
+	} else if (ret < 0)
+		return (-ret);
+
 process:
 	if (drbr_empty(ifp, adapter->br))
 		return(error);
@@ -989,7 +995,7 @@
                         break;
                 if ((error = em_xmit(adapter, &next)) != 0) {
 			if (next != NULL)
-				error = drbr_enqueue(ifp, adapter->br, next);
+				error = drbr_requeue(ifp, adapter->br, next);
                         break;
 		}
 		drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h	(revision 203362)
+++ sys/net/if_var.h	(working copy)
@@ -597,18 +597,26 @@
 	return (error);
 }
 
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+		IFQ_DRV_PREPEND(&ifp->if_snd, m);
+		return (0);
+	}
+#endif
+	return drbr_enqueue(ifp, br, m);
+}
+
 static __inline void
 drbr_flush(struct ifnet *ifp, struct buf_ring *br)
 {
 	struct mbuf *m;
 
 #ifdef ALTQ
-	if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
-		while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
-			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
-			m_freem(m);
-		}
-	}
+	if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+		IFQ_DRV_PURGE(&ifp->if_snd);
 #endif	
 	while ((m = buf_ring_dequeue_sc(br)) != NULL)
 		m_freem(m);
@@ -642,11 +650,12 @@
 {
 	struct mbuf *m;
 #ifdef ALTQ
-	/*
-	 * XXX need to evaluate / requeue 
-	 */
 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {	
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+		if (m != NULL && func(m, arg) == 0) {
+			IFQ_DRV_PREPEND(&ifp->if_snd, m);
+			return (NULL);
+		}
 		return (m);
 	}
 #endif
@@ -668,6 +677,24 @@
 }
 
 static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+	int error;
+
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+	    	IFQ_ENQUEUE(&ifp->if_snd, m, error);
+		return error ? -error : 1;
+	}
+#endif
+	if (drbr_empty(ifp, br))
+		return 0;
+
+	error = drbr_enqueue(ifp, br, m);
+	return error ? -error : 1;
+}
+
+static __inline int
 drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
 {
 #ifdef ALTQ

--Boundary-00=_ge4aL9vBl3gxbuc
Content-Type: text/x-patch; charset="ISO-8859-1";
	name="drbr_altq.stable_8.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="drbr_altq.stable_8.diff"

diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 7a2dbad..94ad229 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1020,7 +1020,7 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
 {
 	struct adapter	*adapter = ifp->if_softc;
 	struct mbuf	*next;
-	int error = E1000_SUCCESS;
+	int ret, error = E1000_SUCCESS;
 
 	EM_TX_LOCK_ASSERT(adapter);
 	/* To allow being called from a tasklet */
@@ -1032,28 +1032,34 @@ em_mq_start_locked(struct ifnet *ifp, struct mbuf *m)
 	    || (!adapter->link_active)) {
 		error = drbr_enqueue(ifp, adapter->br, m);
 		return (error);
-	} else if (drbr_empty(ifp, adapter->br) &&
-	    (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD)) {
-		if ((error = em_xmit(adapter, &m)) != 0) {
-			if (m != NULL)
-				error = drbr_enqueue(ifp, adapter->br, m);
-			return (error);
-		} else {
-			/*
-			 * We've bypassed the buf ring so we need to update
-			 * ifp directly
-			 */
-			drbr_stats_update(ifp, m->m_pkthdr.len, m->m_flags);
-			/*
-			** Send a copy of the frame to the BPF
-			** listener and set the watchdog on.
-			*/
-			ETHER_BPF_MTAP(ifp, m);
-			adapter->watchdog_timer = EM_TX_TIMEOUT;
-		}
-	} else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
-		return (error);
-	
+	}
+	ret = drbr_maybe_enqueue(ifp, adapter->br, m);
+	if (ret == 0) {
+		if (adapter->num_tx_desc_avail > EM_TX_OP_THRESHOLD) {
+			if ((error = em_xmit(adapter, &m)) != 0) {
+				if (m)
+					error = drbr_enqueue(ifp, adapter->br,
+					    m);
+				return (error);
+			} else {
+				/*
+				 * We've bypassed the buf ring so we need to
+				 * update ifp directly
+				 */
+				drbr_stats_update(ifp, m->m_pkthdr.len,
+				    m->m_flags);
+				/*
+				** Send a copy of the frame to the BPF
+				** listener and set the watchdog on.
+				*/
+				ETHER_BPF_MTAP(ifp, m);
+				adapter->watchdog_timer = EM_TX_TIMEOUT;
+			}
+		} else if ((error = drbr_enqueue(ifp, adapter->br, m)) != 0)
+  			return (error);
+	} else if (ret < 0)
+		return (-ret);
+
 process:
 	if (drbr_empty(ifp, adapter->br))
 		return(error);
@@ -1066,7 +1072,7 @@ process:
                         break;
                 if ((error = em_xmit(adapter, &next)) != 0) {
 			if (next != NULL)
-				error = drbr_enqueue(ifp, adapter->br, next);
+				error = drbr_requeue(ifp, adapter->br, next);
                         break;
 		}
 		drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index eac7dbf..1d59402 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -595,18 +595,26 @@ drbr_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
 	return (error);
 }
 
+static __inline int
+drbr_requeue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+		IFQ_DRV_PREPEND(&ifp->if_snd, m);
+		return (0);
+	}
+#endif
+	return drbr_enqueue(ifp, br, m);
+}
+
 static __inline void
 drbr_flush(struct ifnet *ifp, struct buf_ring *br)
 {
 	struct mbuf *m;
 
 #ifdef ALTQ
-	if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
-		while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
-			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
-			m_freem(m);
-		}
-	}
+	if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd))
+		IFQ_DRV_PURGE(&ifp->if_snd);
 #endif	
 	while ((m = buf_ring_dequeue_sc(br)) != NULL)
 		m_freem(m);
@@ -640,11 +648,12 @@ drbr_dequeue_cond(struct ifnet *ifp, struct buf_ring *br,
 {
 	struct mbuf *m;
 #ifdef ALTQ
-	/*
-	 * XXX need to evaluate / requeue 
-	 */
 	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {	
 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+		if (m != NULL && func(m, arg) == 0) {
+			IFQ_DRV_PREPEND(&ifp->if_snd, m);
+			return (NULL);
+		}
 		return (m);
 	}
 #endif
@@ -666,6 +675,24 @@ drbr_empty(struct ifnet *ifp, struct buf_ring *br)
 }
 
 static __inline int
+drbr_maybe_enqueue(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m)
+{
+	int error;
+
+#ifdef ALTQ
+	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
+	    	IFQ_ENQUEUE(&ifp->if_snd, m, error);
+		return error ? -error : 1;
+	}
+#endif
+	if (drbr_empty(ifp, br))
+		return 0;
+
+	error = drbr_enqueue(ifp, br, m);
+	return error ? -error : 1;
+}
+
+static __inline int
 drbr_inuse(struct ifnet *ifp, struct buf_ring *br)
 {
 #ifdef ALTQ

--Boundary-00=_ge4aL9vBl3gxbuc--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201002050351.12270.max>