-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers/virtio: Implement LRO and RX buffer merging #1339
base: staging
Are you sure you want to change the base?
drivers/virtio: Implement LRO and RX buffer merging #1339
Conversation
3e61377
to
01bc03c
Compare
01bc03c
to
e26cf57
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @mschlumpp 🌵 👋 ! Thank you for the super useful feature 💪! I had quick diagonal look trying to spot what I would describe as nitpicks. I will try to have a deeper look in the next round.
drivers/virtio/net/virtio_net.c
Outdated
struct virtio_net_device *vndev; | ||
__u64 drv_features = 0; | ||
__u64 host_features; | ||
int rc = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I see in case of success you return 0;
regardless. So this early initialization is probably not needed.
drivers/virtio/net/virtio_net.c
Outdated
{ | ||
struct virtio_net_device *vndev; | ||
__u64 host_features; | ||
int rc = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto? rc
does not seem to be set anywhere.
drivers/virtio/net/virtio_net.c
Outdated
* burden on the allocator). | ||
*/ | ||
if (conf->lro) { | ||
if (VIRTIO_FEATURE_HAS(vndev->vdev->features, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth adding a likely
here? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually let's also reorder the whole section ^^
Then we can remove one level of indentation on the success case.
322c5dc
to
b749bcf
Compare
b749bcf
to
67fbea9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from @mogasergiu 's remarks, it looks good. Moreover, I haven't found any problems during testing. Seems to work as expected 👍
Reviewed-by: Maria Pana maria.pana4@gmail.com
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greetings, Marco! Thank you for adding this feature! I only managed to go over it briefly, but I'll look into it more thoroughly in the coming days.
I expect this feature will boost network throughput by a bit. Though I haven't had a chance to test this yet, have you noticed any improvements?
drivers/virtio/net/virtio_net.c
Outdated
@@ -322,9 +328,9 @@ static int virtio_netdev_rx_fillup(struct virtio_net_device *vndev, | |||
* Because we using 2 descriptor for a single netbuf, our effective |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should update the comment from above.
@@ -322,9 +328,9 @@ static int virtio_netdev_rx_fillup(struct virtio_net_device *vndev, | |||
* Because we using 2 descriptor for a single netbuf, our effective | |||
* queue size is just the half. | |||
*/ | |||
nb_desc = ALIGN_DOWN(nb_desc, 2); | |||
nb_desc = ALIGN_DOWN(nb_desc, vndev->buf_descr_count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it guaranteed that vndev->buf_descr_count
is a power of 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now yes, but I'll insert an assert in front of it.
/* Appending the header buffer to the sglist */ | ||
uk_sglist_append(sg, rxhdr, virtio_net_hdr_size(vndev)); | ||
if (vndev->buf_descr_count == VIRTIO_NET_BUF_DESCR_COUNT_INLINE) { | ||
rc = uk_netbuf_header(netbuf, virtio_net_hdr_size(vndev)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please help me understand what this branch covers?
I'm a bit lost in understanding the use case and why we are not using the padding from VTNET_HDR_SIZE_PADDED
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modern virtio devices (or legacy devices with negotiated ANY_LAYOUT, but we don't consider those) do not need to have the header in a separate descriptor. And if we put header and payload into the same descriptor then there must not be any padding between them.
Additionally, if we use mergeable RX buffers the resulting buffers would contain non-continuous payloads for the additional buffers (fixing that up would require memmove
s)
Also this usually wastes one less descriptor.
This also allows us to properly keep track of the index we last notified the host of. This is necessary to properly check against the hosts' notification index. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
This allows network stacks to query the LRO support and enable it if supported by the stack. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
c85be7d
to
5e7f311
Compare
Updated and rebased the PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Marco, had another look 👋
drivers/virtio/net/virtio_net.c
Outdated
buf->len = len + (VTNET_HDR_SIZE_PADDED(vndev) - | ||
virtio_net_hdr_size(vndev)); | ||
/* Shift the position forward to remove the header */ | ||
rc = uk_netbuf_header( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paranthesis alignment: buf on this line and the second argument on the next.
drivers/virtio/net/virtio_net.c
Outdated
rc = uk_netbuf_header(buf, -((__s16)VTNET_HDR_SIZE_PADDED(vndev))); | ||
if (vndev->buf_descr_count == VIRTIO_NET_BUF_DESCR_COUNT_INLINE) { | ||
buf->len = len; | ||
rc = uk_netbuf_header( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
drivers/virtio/net/virtio_net.c
Outdated
@@ -1007,6 +1043,16 @@ static int virtio_netdev_probe(struct uk_netdev *n) | |||
*/ | |||
vndev->vdev->features = drv_features; | |||
|
|||
if (vndev->vdev->features & (1ULL << VIRTIO_F_VERSION_1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would place paranthesis around both these bitwise &
's just to be double sure 🤷♂️.
drivers/virtio/net/virtio_net.c
Outdated
|
||
while (num_buffers > 1) { | ||
ret = virtqueue_buffer_dequeue(rxq->vq, (void **) &chain, &len); | ||
if (ret < 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unlikely
? 🤔
drivers/virtio/net/virtio_net.c
Outdated
*/ | ||
if (conf->lro) { | ||
if (unlikely( | ||
!VIRTIO_FEATURE_HAS(vndev->vdev->features, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
drivers/virtio/net/virtio_net.c
Outdated
} | ||
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_GUEST_TSO4)) | ||
VIRTIO_FEATURE_SET(vndev->vdev->features, | ||
VIRTIO_NET_F_GUEST_TSO4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Paranthesis alignment?
drivers/virtio/net/virtio_net.c
Outdated
VIRTIO_NET_F_GUEST_TSO4); | ||
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_GUEST_TSO6)) | ||
VIRTIO_FEATURE_SET(vndev->vdev->features, | ||
VIRTIO_NET_F_GUEST_TSO6); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
* descriptors (needing indirect descriptors and putting a large | ||
* burden on the allocator). | ||
*/ | ||
if (conf->lro) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert for conf?
This allows delaying the announcement of driver features to the configure step. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
For modern virtio devices the header can be put into the same descriptor as the data. This also now correctly removes the padded header from the packets. The previous code added junk data at the end because it did not consider the header part of the reported data length. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
This allows the device to merge smaller buffers into a larger one when a single buffer is not large enough for a particular packet. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
5e7f311
to
e71299a
Compare
Expose device support over uknetdev and allow larger packets when one of the LRO features is enabled. Signed-off-by: Marco Schlumpp <marco@unikraft.io>
e71299a
to
b0313e4
Compare
Prerequisite checklist
checkpatch.uk
on your commit series before opening this PR;Base target
x86_64
or N/A]kvm
,xen
or N/A]app-python3
or N/A]Additional configuration
To test this PR you can use the corresponding LWIP PR: unikraft/lib-lwip#53
When receiving large enough payloads via TCP, QEMU/Linux should then pass on packets size much larger than the configured MTU to the VM.
Description of changes
This PR adds LRO support to the virtio net driver and the necessary abstraction in uknetdev. To avoid having to allocate huge buffers it also implements support for the RX buffer merge feature. This feature allows the device to join multiple receive buffers together for packets larger than the buffer size.
Because this feature triggered a bug in the event notification code, it also includes a fix for that problem.