+ pkt_len = rte_pktmbuf_pkt_len(buff);
+ data_len = rte_pktmbuf_data_len(buff);
+ len_to_cpy = RTE_MIN(data_len,
+ hdr ? desc->len - vq->vhost_hlen : desc->len);
+ while (total_copied < pkt_len) {
+ /* Copy mbuf data to buffer */
+ rte_memcpy((void *)(uintptr_t)(buff_addr + vb_offset),
+ (const void *)(rte_pktmbuf_mtod(buff, const char *) + offset),
+ len_to_cpy);
+ PRINT_PACKET(dev, (uintptr_t)(buff_addr + vb_offset),
+ len_to_cpy, 0);
+
+ offset += len_to_cpy;
+ vb_offset += len_to_cpy;
+ total_copied += len_to_cpy;
+
+ /* The whole packet completes */
+ if (total_copied == pkt_len)
+ break;
+
+ /* The current segment completes */
+ if (offset == data_len) {
+ buff = buff->next;
+ offset = 0;
+ data_len = rte_pktmbuf_data_len(buff);
+ }
+
+ /* The current vring descriptor done */
+ if (vb_offset == desc->len) {
+ if (desc->flags & VRING_DESC_F_NEXT) {
+ desc = &vq->desc[desc->next];
+ buff_addr = gpa_to_vva(dev, desc->addr);
+ vb_offset = 0;
+ } else {
+ /* Room in vring buffer is not enough */
+ uncompleted_pkt = 1;
+ break;
+ }
+ }
+ len_to_cpy = RTE_MIN(data_len - offset, desc->len - vb_offset);
+ };
+