/**
* Structure associated with each descriptor of the RX ring of a RX queue.
*/struct igb_rx_entry{
struct rte_mbuf *mbuf;/**< mbuf associated with RX descriptor. */};/**
* Structure associated with each descriptor of the TX ring of a TX queue.
*/struct igb_tx_entry{
struct rte_mbuf *mbuf;/**< mbuf associated with TX desc, if any. */
uint16_t next_id;/**< Index of next descriptor in ring. */
uint16_t last_id;/**< Index of last scattered descriptor. */};
uint16_t
eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t nb_pkts){
struct igb_rx_queue *rxq;
volatile union e1000_adv_rx_desc *rx_ring;
volatile union e1000_adv_rx_desc *rxdp;
struct igb_rx_entry *sw_ring;
struct igb_rx_entry *rxe;
struct rte_mbuf *rxm;
struct rte_mbuf *nmb;
union e1000_adv_rx_desc rxd;
uint64_t dma_addr;
uint32_t staterr;
uint32_t hlen_type_rss;
uint16_t pkt_len;
uint16_t rx_id;
uint16_t nb_rx;
uint16_t nb_hold;
uint64_t pkt_flags;
nb_rx = 0;
nb_hold = 0;
rxq = rx_queue;
rx_id = rxq->rx_tail;
rx_ring = rxq->rx_ring;
sw_ring = rxq->sw_ring;
while (nb_rx < nb_pkts){/*
* The order of operations here is important as the DD status
* bit must not be read after any other descriptor fields.
* rx_ring and rxdp are pointing to volatile data so the order
* of accesses cannot be reordered by the compiler. If they were
* not volatile, they could be reordered which could lead to
* using invalid descriptor fields when read from rxd.
*/
rxdp = &rx_ring[rx_id]; 从描述符队列中找到待被应用层最后一次接收的那个描述符位置
staterr = rxdp->wb.upper.status_error; //检查状态是否为dd, 不是则说明驱动还没有把报文放到接收队列,直接退出
// dd=0 dd=1
//dd 为描述符中的一个标志位 通过标志位来控制数据传输 net ---> dma --> e1000_adv_rx_desc --->mbuf
if (! (staterr & rte_cpu_to_le_32(E1000_RXD_STAT_DD)))
break;
rxd = *rxdp;/*
* End of packet.
*
* If the E1000_RXD_STAT_EOP flag is not set, the RX packet is
* likely to be invalid and to be dropped by the various
* validation checks performed by the network stack.
*
* Allocate a new mbuf to replenish the RX ring descriptor.
* If the allocation fails:
* - arrange for that RX descriptor to be the first one
* being parsed the next time the receive function is
* invoked [on the same queue].
*
* - Stop parsing the RX ring and return immediately.
*
* This policy do not drop the packet received in the RX
* descriptor for which the allocation of a new mbuf failed.
* Thus, it allows that packet to be later retrieved if
* mbuf have been freed in the mean time.
* As a side effect, holding RX descriptors instead of
* systematically giving them back to the NIC may lead to
* RX ring exhaustion situations.
* However, the NIC can gracefully prevent such situations
* to happen by sending specific "back-pressure" flow control
* frames to its peer(s).
*/
PMD_RX_LOG(DEBUG,"port_id=%u queue_id=%u rx_id=%u ""staterr=0x%x pkt_len=%u",(unsigned) rxq->port_id,(unsigned) rxq->queue_id,(unsigned) rx_id,(unsigned) staterr,(unsigned) rte_le_to_cpu_16(rxd.wb.upper.length));
nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
if (nmb == NULL){
PMD_RX_LOG(DEBUG,"RX mbuf alloc failed port_id=%u ""queue_id=%u",(unsigned) rxq->port_id,(unsigned) rxq->queue_id);
rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;
break;}
nb_hold++;
rxe = &sw_ring[rx_id]; // 找到软件中的sw_ring 问题一: sw_ring 与 rx_ring是否相等
//网卡的setup设置中是相等的
rx_id++;
if (rx_id == rxq->nb_rx_desc)
rx_id = 0;/* Prefetch next mbuf while processing current one. */
rte_igb_prefetch(sw_ring[rx_id].mbuf);/*
* When next RX descriptor is on a cache-line boundary,
* prefetch the next 4 RX descriptors and the next 8 pointers
* to mbufs.
*/if ((rx_id & 0x3) == 0){
rte_igb_prefetch(&rx_ring[rx_id]);
rte_igb_prefetch(&sw_ring[rx_id]);}
rxm = rxe->mbuf;
rxe->mbuf = nmb; // 置换当前的mbuf为新的空mbuf rxm用于保存数据到应用程序
dma_addr =
rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));
rxdp->read.hdr_addr = 0;
rxdp->read.pkt_addr = dma_addr; //清空当前的描述符 用与下一次写 write_back 操作
/*
* Initialize the returned mbuf.
* 1) setup generic mbuf fields:
* - number of segments,
* - next segment,
* - packet length,
* - RX port identifier.
* 2) integrate hardware offload data, if any:
* - RSS flag & hash,
* - IP checksum flag,
* - VLAN TCI, if any,
* - error flags.
*/
pkt_len = (uint16_t)(rte_le_to_cpu_16(rxd.wb.upper.length) -
rxq->crc_len);
rxm->data_off = RTE_PKTMBUF_HEADROOM;
rte_packet_prefetch((char *)rxm->buf_addr + rxm->data_off);
rxm->nb_segs = 1;
rxm->next = NULL;
rxm->pkt_len = pkt_len;
rxm->data_len = pkt_len;
rxm->port = rxq->port_id;
rxm->hash.rss = rxd.wb.lower.hi_dword.rss;
hlen_type_rss = rte_le_to_cpu_32(rxd.wb.lower.lo_dword.data);/*
* The vlan_tci field is only valid when PKT_RX_VLAN is
* set in the pkt_flags field and must be in CPU byte order.
*/if ((staterr & rte_cpu_to_le_32(E1000_RXDEXT_STATERR_LB)) &&
(rxq->flags & IGB_RXQ_FLAG_LB_BSWAP_VLAN)){
rxm->vlan_tci = rte_be_to_cpu_16(rxd.wb.upper.vlan);}else{
rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);}
pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(rxq, hlen_type_rss);
pkt_flags = pkt_flags | rx_desc_status_to_pkt_flags(staterr);
pkt_flags = pkt_flags | rx_desc_error_to_pkt_flags(staterr);
rxm->ol_flags = pkt_flags;
rxm->packet_type = igb_rxd_pkt_info_to_pkt_type(rxd.wb.lower.
lo_dword.hs_rss.pkt_info);/*
* Store the mbuf address into the next entry of the array
* of returned packets.
*/
rx_pkts[nb_rx++] = rxm; // 保存收到的数据到应用程序
}
rxq->rx_tail = rx_id;/*
* If the number of free RX descriptors is greater than the RX free
* threshold of the queue, advance the Receive Descriptor Tail (RDT)
* register.
* Update the RDT with the value of the last processed RX descriptor
* minus 1, to guarantee that the RDT register is never equal to the
* RDH register, which creates a "full" ring situtation from the
* hardware point of view...
*/
nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold);
if (nb_hold > rxq->rx_free_thresh){
PMD_RX_LOG(DEBUG,"port_id=%u queue_id=%u rx_tail=%u ""nb_hold=%u nb_rx=%u",(unsigned) rxq->port_id,(unsigned) rxq->queue_id,(unsigned) rx_id,(unsigned) nb_hold,(unsigned) nb_rx);
rx_id = (uint16_t)((rx_id == 0) ?
(rxq->nb_rx_desc - 1):(rx_id - 1));
E1000_PCI_REG_WRITE(rxq->rdt_reg_addr, rx_id);
nb_hold = 0;}
rxq->nb_rx_hold = nb_hold;
return nb_rx;}
说明: 发送函数执行完毕 收函数不是很快就能收到数据 可能经过很多个循环后才有数据
一: 关于 struct rte_mbuf 描述符的结构体原型/** * Structure associated with each descriptor of the RX ring of a RX queue. */struct igb_rx_entry { struct rte_mbuf *mbuf; /**< mbuf associated with RX descriptor. */};/** * Structure associated with each descr