src/sys/dev/virtio/network/if_vtnet.c
/*
 * Slow path for when LRO without mergeable buffers is negotiated.
 */
Slow path for when LRO without mergeable buffers is negotiated.
Slow path for when LRO without mergeable buffers is negotiated .
static int
vtnet_rxq_replace_lro_nomgr_buf(struct vtnet_rxq *rxq, struct mbuf *m0,
    int len0)
{
	struct vtnet_softc *sc;
	struct mbuf *m, *m_prev;
	struct mbuf *m_new, *m_tail;
	int len, clsize, nreplace, error;
	sc = rxq->vtnrx_sc;
	clsize = sc->vtnet_rx_clsize;
	m_prev = NULL;
	m_tail = NULL;
	nreplace = 0;
	m = m0;
	len = len0;
	while (len > 0) {
		if (m == NULL) {
			sc->vtnet_stats.rx_frame_too_large++;
			return (EMSGSIZE);
		}
		KASSERT(m->m_len == clsize,
		    ("%s: mbuf size %d is not the cluster size %d",
		    __func__, m->m_len, clsize));
		m->m_len = MIN(m->m_len, len);
		len -= m->m_len;
		m_prev = m;
		m = m->m_next;
		nreplace++;
	}
	KASSERT(nreplace <= sc->vtnet_rx_nmbufs,
	    ("%s: too many replacement mbufs %d max %d", __func__, nreplace,
	    sc->vtnet_rx_nmbufs));
	m_new = vtnet_rx_alloc_buf(sc, nreplace, &m_tail);
	if (m_new == NULL) {
		m_prev->m_len = clsize;
		return (ENOBUFS);
	}
	if (m_prev->m_next != NULL) {
		m_tail->m_next = m_prev->m_next;
		m_prev->m_next = NULL;
	}
	error = vtnet_rxq_enqueue_buf(rxq, m_new);
	if (error) {
		sc->vtnet_stats.rx_enq_replacement_failed++;
		if (m_tail->m_next != NULL) {
			m_prev->m_next = m_tail->m_next;
			m_tail->m_next = NULL;
		}
		m_prev->m_len = clsize;
		m_freem(m_new);
	}
	return (error);
}
static int vtnet_rxq_replace_lro_nomgr_buf ( struct vtnet_rxq * rxq , struct mbuf * m0 , int len0 ) { struct vtnet_softc * sc ; struct mbuf * m , * m_prev ; struct mbuf * m_new , * m_tail ; int len , clsize , nreplace , error ; sc = rxq -> vtnrx_sc ; clsize = sc -> vtnet_rx_clsize ; m_prev = NULL ; m_tail = NULL ; nreplace = 0 ; m = m0 ; len = len0 ; while ( len > 0 ) { if ( m == NULL ) { sc -> vtnet_stats . rx_frame_too_large ++ ; return ( EMSGSIZE ) ; } KASSERT ( m -> m_len == clsize , ( " " , __func__ , m -> m_len , clsize ) ) ; m -> m_len = MIN ( m -> m_len , len ) ; len -= m -> m_len ; m_prev = m ; m = m -> m_next ; nreplace ++ ; } KASSERT ( nreplace <= sc -> vtnet_rx_nmbufs , ( " " , __func__ , nreplace , sc -> vtnet_rx_nmbufs ) ) ; m_new = vtnet_rx_alloc_buf ( sc , nreplace , & m_tail ) ; if ( m_new == NULL ) { m_prev -> m_len = clsize ; return ( ENOBUFS ) ; } if ( m_prev -> m_next != NULL ) { m_tail -> m_next = m_prev -> m_next ; m_prev -> m_next = NULL ; } error = vtnet_rxq_enqueue_buf ( rxq , m_new ) ; if ( error ) { sc -> vtnet_stats . rx_enq_replacement_failed ++ ; if ( m_tail -> m_next != NULL ) { m_prev -> m_next = m_tail -> m_next ; m_tail -> m_next = NULL ; } m_prev -> m_len = clsize ; m_freem ( m_new ) ; } return ( error ) ; }
Slow path for when LRO without mergeable buffers is negotiated.
Slow path for when LRO without mergeable buffers is negotiated .
/*
	 * Since these mbuf chains are so large, we avoid allocating an
	 * entire replacement chain if possible. When the received frame
	 * did not consume the entire chain, the unused mbufs are moved
	 * to the replacement chain.
	 */ /*
		 * Something is seriously wrong if we received a frame
		 * larger than the chain. Drop it.
		 */ /* We always allocate the same cluster size. */ /*
	 * Move any unused mbufs from the received chain onto the end
	 * of the new chain.
	 */ /*
		 * BAD! We could not enqueue the replacement mbuf chain. We
		 * must restore the m0 chain to the original state if it was
		 * modified so we can subsequently discard it.
		 *
		 * NOTE: The replacement is suppose to be an identical copy
		 * to the one just dequeued so this is an unexpected error.
		 */