虛擬隊列(Virtqueue)是連接guest操作系統中virtio前端驅動和宿主機vhostuser後端驅動的實際數據鏈路。網絡設備有 2 個 virtqueue,一個用於發送數據包,一個用於接收數據包。
每個虛擬隊列主要由三部分組成:
- 描述符數組(descriptor table)用於存儲一些關聯的描述符,每個描述符都是一個對 buffer 的描述,包含一個address/length 的配對。
- 可用的 ring(available ring)用於 guest 端表示那些描述符鏈當前是可用的。
- 使用過的 ring(used ring)用於表示 Host 端表示那些描述符已經使用。
描述符列表指向實際要傳輸的數據,兩個環表指向描述符列表,標記前端和後端驅動對描述符列表中的描述符處理進度。
當virtqueue用於發送報文時,前端驅動將待發送報文加入avail ring等待後端的處理,後端處理完後,會將其放入used ring,並由前端將其釋放desc中,最後通過try_fill_recv重新裝入avail ring中; 當virtqueue用於接收報文時,前端將空白物理塊加入avail ring中,提供給後端用來接收報文,後端接收完報文會放入used ring。
整個收包流程如下:
- 前端填充好desc(addr/len),並更新vring->avail(ring[0])
- 後端讀取avail ring索引,拿到desc(if ring[0]=2,then desctable[2] 記錄的就是一個邏輯buffer的首個物理塊的信息),填充buffer數據;將buffer索引存在desc,將desc索引存放在used ring中
- 前端讀取used ring索引,找到desc,獲取buffer數據