diff --git a/sys/net/ifq.c b/sys/net/ifq.c --- a/sys/net/ifq.c +++ b/sys/net/ifq.c @@ -62,16 +62,21 @@ void drbr_putback(struct ifnet *ifp, struct buf_ring *br, struct mbuf *m_new) { + int error = 0; /* * The top of the list needs to be swapped - * for this one. + * for this one. + * In case the mbuf was taken from interface queue + * the buf_ring is empty and enqueue needs to be used. */ - if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { + if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd) && buf_ring_empty(br)) { /* * Peek in altq case dequeued it * so put it back. */ - IFQ_DRV_PREPEND(&ifp->if_snd, m_new); + error = buf_ring_enqueue(br, m_new); + if (error) + m_freem(m_new); return; } buf_ring_putback_sc(br, m_new); @@ -80,18 +85,18 @@ struct mbuf * drbr_peek(struct ifnet *ifp, struct buf_ring *br) { - struct mbuf *m; - if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { + struct mbuf *m = ((struct mbuf *)buf_ring_peek_clear_sc(br)); + if (m == NULL && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { /* * Pull it off like a dequeue * since drbr_advance() does nothing * for altq and drbr_putback() will - * use the old prepend function. + * use the buf_ring for storing frames. */ IFQ_DEQUEUE(&ifp->if_snd, m); return (m); } - return ((struct mbuf *)buf_ring_peek_clear_sc(br)); + return (m); } void @@ -108,21 +113,22 @@ struct mbuf * drbr_dequeue(struct ifnet *ifp, struct buf_ring *br) { - struct mbuf *m; + struct mbuf *m = ((struct mbuf *)buf_ring_dequeue_sc(br)); - if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { + if (m == NULL && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { IFQ_DEQUEUE(&ifp->if_snd, m); return (m); } - return ((struct mbuf *)buf_ring_dequeue_sc(br)); + return (m); } void drbr_advance(struct ifnet *ifp, struct buf_ring *br) { - /* Nothing to do here since peek dequeues in altq case */ - if (ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) - return; + /* + * Always try to advance buf_ring as it could have been used for putback + * and then peek (it does nothing on empty buf_ring) + */ return (buf_ring_advance_sc(br)); } @@ -130,8 +136,8 @@ drbr_dequeue_cond(struct ifnet *ifp, struct buf_ring *br, int (*func) (struct mbuf *, void *), void *arg) { - struct mbuf *m; - if (ALTQ_IS_ENABLED(&ifp->if_snd)) { + struct mbuf *m = (struct mbuf *)buf_ring_peek(br); + if (m == NULL && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) { IFQ_LOCK(&ifp->if_snd); IFQ_POLL_NOLOCK(&ifp->if_snd, m); if (m != NULL && func(m, arg) == 0) { @@ -142,7 +148,6 @@ IFQ_UNLOCK(&ifp->if_snd); return (m); } - m = (struct mbuf *)buf_ring_peek(br); if (m == NULL || func(m, arg) == 0) return (NULL); @@ -152,9 +157,10 @@ int drbr_empty(struct ifnet *ifp, struct buf_ring *br) { - if (ALTQ_IS_ENABLED(&ifp->if_snd)) + bool empty = buf_ring_empty(br); + if (empty && ALTQ_IS_ENABLED(&ifp->if_snd)) return (IFQ_IS_EMPTY(&ifp->if_snd)); - return (buf_ring_empty(br)); + return (empty); } int @@ -168,8 +174,9 @@ int drbr_inuse(struct ifnet *ifp, struct buf_ring *br) { + int count = buf_ring_count(br); if (ALTQ_IS_ENABLED(&ifp->if_snd)) - return (ifp->if_snd.ifq_len); - return (buf_ring_count(br)); + count += (ifp->if_snd.ifq_len); + return (count); }