[dpdk-dev] [PATCH] virtio: Fix enqueue/dequeue can't handle chained vring descriptors.

Xie, Huawei huawei.xie at intel.com
Wed May 20 07:26:21 CEST 2015


On 5/18/2015 9:23 PM, Ouyang, Changchun wrote:
> Hi Huawei,
>
>> -----Original Message-----
>> From: Xie, Huawei
>> Sent: Monday, May 18, 2015 5:39 PM
>> To: Ouyang, Changchun; dev at dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH] virtio: Fix enqueue/dequeue can't handle
>> chained vring descriptors.
>>
>> On 5/4/2015 2:27 PM, Ouyang Changchun wrote:
>>> Vring enqueue need consider the 2 cases:
>>>  1. Vring descriptors chained together, the first one is for virtio
>>> header, the rest are for real data;  2. Only one descriptor, virtio
>>> header and real data share one single descriptor;
>>>
>>> So does vring dequeue.
>>>
>>> Signed-off-by: Changchun Ouyang <changchun.ouyang at intel.com>
>>> ---
>>>  lib/librte_vhost/vhost_rxtx.c | 60
>>> +++++++++++++++++++++++++++++++------------
>>>  1 file changed, 44 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/lib/librte_vhost/vhost_rxtx.c
>>> b/lib/librte_vhost/vhost_rxtx.c index 510ffe8..3135883 100644
>>> --- a/lib/librte_vhost/vhost_rxtx.c
>>> +++ b/lib/librte_vhost/vhost_rxtx.c
>>> @@ -59,7 +59,7 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t
>> queue_id,
>>>  	struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 0};
>>>  	uint64_t buff_addr = 0;
>>>  	uint64_t buff_hdr_addr = 0;
>>> -	uint32_t head[MAX_PKT_BURST], packet_len = 0;
>>> +	uint32_t head[MAX_PKT_BURST];
>>>  	uint32_t head_idx, packet_success = 0;
>>>  	uint16_t avail_idx, res_cur_idx;
>>>  	uint16_t res_base_idx, res_end_idx;
>>> @@ -113,6 +113,10 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t
>> queue_id,
>>>  	rte_prefetch0(&vq->desc[head[packet_success]]);
>>>
>>>  	while (res_cur_idx != res_end_idx) {
>>> +		uint32_t offset = 0;
>>> +		uint32_t data_len, len_to_cpy;
>>> +		uint8_t plus_hdr = 0;
>>> +
>>>  		/* Get descriptor from available ring */
>>>  		desc = &vq->desc[head[packet_success]];
>>>
>>> @@ -125,7 +129,6 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t
>>> queue_id,
>>>
>>>  		/* Copy virtio_hdr to packet and increment buffer address */
>>>  		buff_hdr_addr = buff_addr;
>>> -		packet_len = rte_pktmbuf_data_len(buff) + vq->vhost_hlen;
>>>
>>>  		/*
>>>  		 * If the descriptors are chained the header and data are @@
>>> -136,24 +139,44 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t
>> queue_id,
>>>  			desc = &vq->desc[desc->next];
>>>  			/* Buffer address translation. */
>>>  			buff_addr = gpa_to_vva(dev, desc->addr);
>>> -			desc->len = rte_pktmbuf_data_len(buff);
>>>  		} else {
>>>  			buff_addr += vq->vhost_hlen;
>>> -			desc->len = packet_len;
>>> +			plus_hdr = 1;
>>>  		}
>>>
>>> +		data_len = rte_pktmbuf_data_len(buff);
>>> +		len_to_cpy = RTE_MIN(data_len, desc->len);
>>> +		do {
>>> +			if (len_to_cpy > 0) {
>>> +				/* Copy mbuf data to buffer */
>>> +				rte_memcpy((void *)(uintptr_t)buff_addr,
>>> +					(const void
>> *)(rte_pktmbuf_mtod(buff, const char *) + offset),
>>> +					len_to_cpy);
>>> +				PRINT_PACKET(dev, (uintptr_t)buff_addr,
>>> +					len_to_cpy, 0);
>>> +
>>> +				desc->len = len_to_cpy + (plus_hdr ? vq-
>>> vhost_hlen : 0);
>> Do we really need to rewrite the desc->len again and again?  At least we only
>> have the possibility to change the value of desc->len of the last descriptor.
> Well, I think we need change each descriptor's len in the chain here,
> If aggregate all len to the last descriptor's len, it is possibly the length will exceed its original len,
> e.g. use 8 descriptor(each has len of 1024) chained to recv a 8K packet, then last descriptor's len
> will be 8K, and all other descriptor is 0, I don't think this situation make sense.  
Let me explain this way.
We receive a packet with 350 bytes size, and we have descriptor chain of
10 descs, each with  100 byte size.
At least we don't need to change the len field of first three descriptors.
Whether we need to change the 4th len field to 50, and the rest of them
to zero is still a question(used->len is updated to 350).
We need check the VIRTIO spec.
>>> +				offset += len_to_cpy;
>>> +				if (desc->flags & VRING_DESC_F_NEXT) {
>>> +					desc = &vq->desc[desc->next];
>>> +					buff_addr = gpa_to_vva(dev, desc-
>>> addr);
>>> +					len_to_cpy = RTE_MIN(data_len -
>> offset, desc->len);
>>> +				} else
>>> +					break;
>> Still there are two issues here.
>> a) If the data couldn't be fully copied to chain of guest buffers, we shouldn't
>> do any copy.
> Why don't copy any data is better than the current implementation?
We don't need to pass part of a packet to guest.
>
>> b) scatter mbuf isn't considered.
> If we also consider scatter mbuf here, then this function will have exactly same logic with mergeable_rx,
> Do you want to totally remove this function, just keep the mergeable rx function for all cases?
>
> Changchun
>
>
>



More information about the dev mailing list