32位网卡驱动 2008_DPDK之网卡收包流程
1.導讀
一個網絡報文從網卡接收到被應用處理,中間主要需要經歷兩個階段:
- 階段一:網卡通過其DMA硬件將收到的報文寫入到收包隊列中(入隊)
- 階段二:應用從收包隊列中讀取報文(出隊)
下面以ixgbe網卡在dpdk框架下工作為例,分別介紹下收包隊列的構造、啟動和收包三個流程。
2.構造
收包隊列的構造主要是通過調用網卡隊列設置函數rte_eth_rx_queue_setup(dpdk rte_ethdev.h)來完成。
收包隊列的結構體為ixgbe_rx_queue,該結構體里包含兩個重要的環形隊列rx_ring和sw_ring,rx_ring和sw_ring的關系可以簡單如下認為。
- rx_ring主要存儲報文數據的物理地址,物理地址供網卡DMA使用,也稱為DMA地址(硬件使用物理地址,將報文copy到報文物理位置上)。
- sw_ring主要存儲報文數據的虛擬地址,虛擬地址供應用使用(軟件使用虛擬地址,讀取報文)。
其中,報文數據的物理地址可以由報文數據的虛擬地址轉化得到。下面詳細介紹下rx_ring與sw_ring兩個隊列的構成。
2.1.rx_ring
ixgbe_adv_rx_desc
ixgbe_adv_rx_desc
......
ixgbe_adv_rx_desc
rx_ring是由一個動態申請的數組構建的環形隊列,隊列的元素是ixgbe_adv_rx_desc類型,隊列的長度為(4096+4-1)。
- pkt_addr:報文數據的物理地址,網卡DMA將報文數據通過該物理地址寫入對應的內存空間。
- hdr_addr:報文的頭信息,hdr_addr的最后一個bit為DD位,因為是union結構,即status_error的最后一個bit也對應DD位。
DD位(Descriptor Done Status)用于標志標識一個描述符buf是否可用。
- 網卡每次來了新的數據包,就檢查rx_ring當前這個buf的DD位是否為0,如果為0那么表示當前buf可以使用,就讓DMA將數據包copy到這個buf中,然后設置DD為1。如果為1,那么網卡就認為rx_ring隊列滿了,直接會將這個包給丟棄掉,記錄一次imiss。(0->1)
- 對于應用而言,DD位使用恰恰相反,在讀取數據包時,先檢查DD位是否為1,如果為1,表示網卡已經把數據包放到了內存中,可以讀取,讀取完后,再放入一個新的buf并把對應DD位設置為0。如果為0,就表示沒有數據包可讀。(1->0)
2.2.sw_ring
ixgbe_rx_entry
ixgbe_rx_entry
……
ixgbe_rx_entry
sw_ring是由一個動態申請的數組構建的環形隊列,隊列的元素是ixgbe_rx_entry類型,隊列的大小可配,一般最大可配4096。
- mbuf:報文mbuf結構指針,mbuf用于管理一個報文,主要包含報文相關信息和報文數據。
3.啟動
收包隊列的啟動主要是通過調用rte_eth_dev_start(dpdk rte_ethdev.h)函數完成,收包隊列初始化的核心流程如下。
循環從mbuf pool中申請mbuf,從mbuf中得到報文數據對應的物理地址,物理地址存入rx_ring中,mbuf指針存入sw_ring中。其中通過rxd->read.hdr_addr = 0,完成了DD位設置為0。
一切ok后,就可以開始收包了。
3.收包
收包由網卡入隊和應用出隊兩個操作完成。
3.1入隊
入隊的操作是由網卡DMA來完成的,DMA(Direct Memory Access,直接存儲器訪問)是系統和網卡(外設)打交道的一種方式,該種方式允許在網卡(外部設備)和系統內存之間直接讀寫數據,這樣能有效減輕CPU的工作。
網卡收到報文后,先存于網卡本地的buffer-Rx(Rx FIFO)中,然后由DMA通過PCI總線將報文數據寫入操作系統的內存中,即數據報文完成入隊操作。(PS:PCIe總線可能成為網卡帶寬的瓶頸)
3.2.出隊
應用調用rte_eth_rx_burst(dpdk rte_ethdev.h)函數開始批量收包,最大收包數量由參數nb_pkts決定(比如設置為64)。其核心流程由ixgbe_recv_pkts(dpdk ixgbe_rxtx.c)實現,從收包隊列rx_tail位置開始收,循環讀取一個報文、填空一個報文(空報文數據),讀取64個后,重新標記rx_tail的位置,完成出隊操作,將收取的報文作返回供應用處理。代碼簡化如下。
-------------------------------------------------
struct rte_mbuf *rxm;
//從隊列的tail位置開始取包
rx_id = rxq->rx_tail;
//循環獲取nb_pkts個包
while (nb_rx < nb_pkts)
{
......
rxdp = &rx_ring[rx_id];
//檢查DD位是否為1,是1則說明該位置已放入數據包,否則表示沒有報文,退出
staterr=rxdp->
wb.upper.status_error;
if(!(staterr
&rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD)))
break;
rxd = *rxdp;
//申請一個mbuf(nmb),用于交換
nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
//從sw_ring中讀取一個報文mbuf(存入rxm)
rxe = &sw_ring[rx_id];
rxm = rxe->mbuf;
//往sw_ring中填空一個新報文mbuf(nmb)
rxe->mbuf = nmb;
//新mbuf對應的報文數據物理地址填入rx_ring對應位置,并將hdr_addr置0(DD位置0)
dma_addr =rte_cpu_to_le_64
(rte_mbuf_data_dma_addr_default(nmb));
rxdp->read.hdr_addr = 0;
rxdp->read.pkt_addr = dma_addr;
//對讀取mbuf的報文信息進行初始化
rxm->pkt_len = pkt_len;
rxm->data_len = pkt_len;
rxm->port = rxq->port_id;
......
//讀取的報文mbuf存入rx_pkts
rx_pkts[nb_rx++] = rxm;
}
//重新標記rx_tail位置
rxq->rx_tail = rx_id;
-------------------------------------------------
推薦閱讀
- 棧 vs 隊列
- Intel 82599網卡光模塊使用的坑
總結
以上是生活随笔為你收集整理的32位网卡驱动 2008_DPDK之网卡收包流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maya刷权重时有个叉_抖音账号养号技巧
- 下一篇: activiti 条件表达式json报错