Skip to content
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

Open
wants to merge 6 commits into
base: staging
Choose a base branch
from

Conversation

mschlumpp
Copy link
Member

@mschlumpp mschlumpp commented Feb 26, 2024

Prerequisite checklist

  • Read the contribution guidelines regarding submitting new changes to the project;
  • Tested your changes against relevant architectures and platforms;
  • Ran the checkpatch.uk on your commit series before opening this PR;
  • Updated relevant documentation.

Base target

  • Architecture(s): [e.g. x86_64 or N/A]
  • Platform(s): [e.g. kvm, xen or N/A]
  • Application(s): [e.g. 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.

@mschlumpp mschlumpp requested review from a team as code owners February 26, 2024 13:13
@github-actions github-actions bot added area/lib Internal Unikraft Microlibrary lang/c Issues or PRs to do with C/C++ lib/uknetdev labels Feb 26, 2024
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch 2 times, most recently from 3e61377 to 01bc03c Compare February 26, 2024 13:33
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch from 01bc03c to e26cf57 Compare March 5, 2024 15:49
@razvand razvand added this to the v0.17.0 (Calypso) milestone Mar 17, 2024
@razvand razvand requested review from Krechals, mogasergiu and mariapana and removed request for a team March 17, 2024 18:17
Copy link
Member

@mogasergiu mogasergiu left a 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.

struct virtio_net_device *vndev;
__u64 drv_features = 0;
__u64 host_features;
int rc = 0;
Copy link
Member

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.

{
struct virtio_net_device *vndev;
__u64 host_features;
int rc = 0;
Copy link
Member

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 Show resolved Hide resolved
drivers/virtio/net/virtio_net.c Show resolved Hide resolved
drivers/virtio/net/virtio_net.c Show resolved Hide resolved
drivers/virtio/net/virtio_net.c Show resolved Hide resolved
* burden on the allocator).
*/
if (conf->lro) {
if (VIRTIO_FEATURE_HAS(vndev->vdev->features,
Copy link
Member

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? 🤔

Copy link
Member Author

@mschlumpp mschlumpp Mar 18, 2024

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.

@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch 2 times, most recently from 322c5dc to b749bcf Compare March 18, 2024 13:25
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch from b749bcf to 67fbea9 Compare March 18, 2024 13:44
Copy link

@mariapana mariapana left a 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

Copy link
Contributor

@Krechals Krechals left a 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?

@@ -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
Copy link
Contributor

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);
Copy link
Contributor

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?

Copy link
Member Author

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));
Copy link
Contributor

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.

Copy link
Member Author

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 memmoves)
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>
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch 2 times, most recently from c85be7d to 5e7f311 Compare April 29, 2024 07:46
@mschlumpp
Copy link
Member Author

Updated and rebased the PR

Copy link
Member

@mogasergiu mogasergiu left a 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 Show resolved Hide resolved
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(
Copy link
Member

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.

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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@@ -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)
Copy link
Member

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 🤷‍♂️.


while (num_buffers > 1) {
ret = virtqueue_buffer_dequeue(rxq->vq, (void **) &chain, &len);
if (ret < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unlikely? 🤔

*/
if (conf->lro) {
if (unlikely(
!VIRTIO_FEATURE_HAS(vndev->vdev->features,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

}
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_GUEST_TSO4))
VIRTIO_FEATURE_SET(vndev->vdev->features,
VIRTIO_NET_F_GUEST_TSO4);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paranthesis alignment?

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);
Copy link
Member

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert for conf?

drivers/virtio/net/virtio_net.c Show resolved Hide resolved
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>
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch from 5e7f311 to e71299a Compare May 22, 2024 12:26
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>
@mschlumpp mschlumpp force-pushed the mschlumpp/feature/virtio-mrg-rxbuf branch from e71299a to b0313e4 Compare May 22, 2024 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/lib Internal Unikraft Microlibrary lang/c Issues or PRs to do with C/C++ lib/uknetdev
Projects
Status: 🏗 In Progress
Development

Successfully merging this pull request may close these issues.

None yet

6 participants