FreeBSD/sys/dev/xen/netfront/netfront.c
/**
 * Given an mbuf chain, make sure we have enough room and then push
 * it onto the transmit ring.
 */
Given an mbuf chain, make sure we have enough room and then push
it onto the transmit ring.
Given an mbuf chain make sure we have enough room and then push it onto the transmit ring .
static int
xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head)
{
	struct mbuf *m;
	struct netfront_info *np = txq->info;
	struct ifnet *ifp = np->xn_ifp;
	u_int nfrags;
	int otherend_id;
	nfrags = xn_count_frags(m_head);
	if (nfrags > np->maxfrags) {
		m = m_defrag(m_head, M_NOWAIT);
		if (!m) {
			m_freem(m_head);
			return (EMSGSIZE);
		}
		m_head = m;
	}
	nfrags = xn_count_frags(m_head);
	if (nfrags > MAX_TX_REQ_FRAGS) {
#ifdef DEBUG
		printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback "
		       "won't be able to handle it, dropping\n",
		       __func__, nfrags, MAX_TX_REQ_FRAGS);
#endif
		m_freem(m_head);
		return (EMSGSIZE);
	}
	KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE,
		("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE "
		 "(%d)!", __func__, (int) txq->mbufs_cnt,
                    (int) nfrags, (int) NET_TX_RING_SIZE));
	m = m_head;
	otherend_id = xenbus_get_otherend_id(np->xbdev);
	for (m = m_head; m; m = m->m_next) {
		netif_tx_request_t *tx;
		uintptr_t id;
		grant_ref_t ref;
		u_long mfn; 
		tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt);
		id = get_id_from_freelist(txq->mbufs);
		if (id == 0)
			panic("%s: was allocated the freelist head!\n",
			    __func__);
		txq->mbufs_cnt++;
		if (txq->mbufs_cnt > NET_TX_RING_SIZE)
			panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n",
			    __func__);
		txq->mbufs[id] = m;
		tx->id = id;
		ref = gnttab_claim_grant_reference(&txq->gref_head);
		KASSERT((short)ref >= 0, ("Negative ref"));
		mfn = virt_to_mfn(mtod(m, vm_offset_t));
		gnttab_grant_foreign_access_ref(ref, otherend_id,
		    mfn, GNTMAP_readonly);
		tx->gref = txq->grant_ref[id] = ref;
		tx->offset = mtod(m, vm_offset_t) & (PAGE_SIZE - 1);
		tx->flags = 0;
		if (m == m_head) {
			tx->size = m->m_pkthdr.len;
			if (m->m_pkthdr.csum_flags
			    & (CSUM_DELAY_DATA | CSUM_TSO)) {
				tx->flags |= (NETTXF_csum_blank
				    | NETTXF_data_validated);
			}
			if (m->m_pkthdr.csum_flags & CSUM_TSO) {
				struct netif_extra_info *gso =
					(struct netif_extra_info *)
					RING_GET_REQUEST(&txq->ring,
							 ++txq->ring.req_prod_pvt);
				tx->flags |= NETTXF_extra_info;
				gso->u.gso.size = m->m_pkthdr.tso_segsz;
				gso->u.gso.type =
					XEN_NETIF_GSO_TYPE_TCPV4;
				gso->u.gso.pad = 0;
				gso->u.gso.features = 0;
				gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
				gso->flags = 0;
			}
		} else {
			tx->size = m->m_len;
		}
		if (m->m_next)
			tx->flags |= NETTXF_more_data;
		txq->ring.req_prod_pvt++;
	}
	BPF_MTAP(ifp, m_head);
	xn_txeof(txq);
	txq->stats.tx_bytes += m_head->m_pkthdr.len;
	txq->stats.tx_packets++;
	return (0);
}
static int xn_assemble_tx_request ( struct netfront_txq * txq , struct mbuf * m_head ) { struct mbuf * m ; struct netfront_info * np = txq -> info ; struct ifnet * ifp = np -> xn_ifp ; u_int nfrags ; int otherend_id ; nfrags = xn_count_frags ( m_head ) ; if ( nfrags > np -> maxfrags ) { m = m_defrag ( m_head , M_NOWAIT ) ; if ( ! m ) { m_freem ( m_head ) ; return ( EMSGSIZE ) ; } m_head = m ; } nfrags = xn_count_frags ( m_head ) ; if ( nfrags > MAX_TX_REQ_FRAGS ) { #ifdef DEBUG printf ( " " " \n " , __func__ , nfrags , MAX_TX_REQ_FRAGS ) ; #endif m_freem ( m_head ) ; return ( EMSGSIZE ) ; } KASSERT ( ( txq -> mbufs_cnt + nfrags ) <= NET_TX_RING_SIZE , ( " " " " , __func__ , ( int ) txq -> mbufs_cnt , ( int ) nfrags , ( int ) NET_TX_RING_SIZE ) ) ; m = m_head ; otherend_id = xenbus_get_otherend_id ( np -> xbdev ) ; for ( m = m_head ; m ; m = m -> m_next ) { netif_tx_request_t * tx ; uintptr_t id ; grant_ref_t ref ; u_long mfn ; tx = RING_GET_REQUEST ( & txq -> ring , txq -> ring . req_prod_pvt ) ; id = get_id_from_freelist ( txq -> mbufs ) ; if ( id == 0 ) panic ( " \n " , __func__ ) ; txq -> mbufs_cnt ++ ; if ( txq -> mbufs_cnt > NET_TX_RING_SIZE ) panic ( " \n " , __func__ ) ; txq -> mbufs [ id ] = m ; tx -> id = id ; ref = gnttab_claim_grant_reference ( & txq -> gref_head ) ; KASSERT ( ( short ) ref >= 0 , ( " " ) ) ; mfn = virt_to_mfn ( mtod ( m , vm_offset_t ) ) ; gnttab_grant_foreign_access_ref ( ref , otherend_id , mfn , GNTMAP_readonly ) ; tx -> gref = txq -> grant_ref [ id ] = ref ; tx -> offset = mtod ( m , vm_offset_t ) & ( PAGE_SIZE - 1 ) ; tx -> flags = 0 ; if ( m == m_head ) { tx -> size = m -> m_pkthdr . len ; if ( m -> m_pkthdr . csum_flags & ( CSUM_DELAY_DATA | CSUM_TSO ) ) { tx -> flags |= ( NETTXF_csum_blank | NETTXF_data_validated ) ; } if ( m -> m_pkthdr . csum_flags & CSUM_TSO ) { struct netif_extra_info * gso = ( struct netif_extra_info * ) RING_GET_REQUEST ( & txq -> ring , ++ txq -> ring . req_prod_pvt ) ; tx -> flags |= NETTXF_extra_info ; gso -> u . gso . size = m -> m_pkthdr . tso_segsz ; gso -> u . gso . type = XEN_NETIF_GSO_TYPE_TCPV4 ; gso -> u . gso . pad = 0 ; gso -> u . gso . features = 0 ; gso -> type = XEN_NETIF_EXTRA_TYPE_GSO ; gso -> flags = 0 ; } } else { tx -> size = m -> m_len ; } if ( m -> m_next ) tx -> flags |= NETTXF_more_data ; txq -> ring . req_prod_pvt ++ ; } BPF_MTAP ( ifp , m_head ) ; xn_txeof ( txq ) ; txq -> stats . tx_bytes += m_head -> m_pkthdr . len ; txq -> stats . tx_packets ++ ; return ( 0 ) ; }
Given an mbuf chain, make sure we have enough room and then push
 it onto the transmit ring.
Given an mbuf chain make sure we have enough room and then push it onto the transmit ring .
/**
	 * Defragment the mbuf if necessary.
	 */ /*
	 * Check to see whether this request is longer than netback
	 * can handle, and try to defrag it.
	 */ /**
	 * It is a bit lame, but the netback driver in Linux can't
	 * deal with nfrags > MAX_TX_REQ_FRAGS, which is a quirk of
	 * the Linux network stack.
	 */ /*
			 * Defrag failed, so free the mbuf and
			 * therefore drop the packet.
			 */ /* Determine how many fragments now exist */ /*
	 * Check to see whether the defragmented packet has too many
	 * segments for the Linux netback driver.
	 */ /**
	 * The FreeBSD TCP stack, with TSO enabled, can produce a chain
	 * of mbufs longer than Linux can handle.  Make sure we don't
	 * pass a too-long chain over to the other side by dropping the
	 * packet.  It doesn't look like there is currently a way to
	 * tell the TCP stack to generate a shorter chain of packets.
	 */ /*
	 * This check should be redundant.  We've already verified that we
	 * have enough slots in the ring to handle a packet of maximum
	 * size, and that our packet is less than the maximum size.  Keep
	 * it in here as an assert for now just to make certain that
	 * chain_cnt is accurate.
	 */ /*
	 * Start packing the mbufs in this chain into
	 * the fragment pointers. Stop when we run out
	 * of fragments or hit the end of the mbuf chain.
	 */ /* XXX Wrong type? */ /*
			 * The first fragment has the entire packet
			 * size, subsequent fragments have just the
			 * fragment size. The backend works out the
			 * true size of the first fragment by
			 * subtracting the sizes of the other
			 * fragments.
			 */ /*
			 * The first fragment contains the checksum flags
			 * and is optionally followed by extra data for
			 * TSO etc.
			 */ /**
			 * CSUM_TSO requires checksum offloading.
			 * Some versions of FreeBSD fail to
			 * set CSUM_TCP in the CSUM_TSO case,
			 * so we have to test for CSUM_TSO
			 * explicitly.
			 */