aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>2022-06-07 18:02:27 +0100
committerWill Deacon <will@kernel.org>2022-06-09 13:44:15 +0100
commitb231683c336132441496060a81726305ca56b11b (patch)
treef4c24f35ae15371eb0c777d1abce268e8a82d976
parent8b27bcff44fd4adaa1466e3198e4222816eefa06 (diff)
downloadkvmtool-b231683c336132441496060a81726305ca56b11b.tar.gz
virtio/net: Prepare for modern virtio
The virtio_net header contains a 'num_buffers' field, used when the VIRTIO_NET_F_MRG_RXBUF feature is negotiated. The legacy driver does not present this field when the feature is not negotiated. In that case the header is 2 bytes smaller. When using the modern virtio transport, the header always contains the field and in addition the device MUST set it to 1 when the VIRTIO_NET_F_MRG_RXBUF is not negotiated. Prepare for modern virtio support by enabling this case once the 'legacy' flag is switched off. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> Link: https://lore.kernel.org/r/20220607170239.120084-13-jean-philippe.brucker@arm.com Signed-off-by: Will Deacon <will@kernel.org>
-rw-r--r--include/kvm/virtio.h1
-rw-r--r--virtio/core.c2
-rw-r--r--virtio/net.c25
3 files changed, 21 insertions, 7 deletions
diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 2da5e4f6..8c05bae2 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -198,6 +198,7 @@ enum virtio_trans {
};
struct virtio_device {
+ bool legacy;
bool use_vhost;
void *virtio;
struct virtio_ops *ops;
diff --git a/virtio/core.c b/virtio/core.c
index 568667f2..09abbf40 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -330,6 +330,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
switch (trans) {
case VIRTIO_PCI:
+ vdev->legacy = true;
virtio = calloc(sizeof(struct virtio_pci), 1);
if (!virtio)
return -ENOMEM;
@@ -343,6 +344,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
r = vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break;
case VIRTIO_MMIO:
+ vdev->legacy = true;
virtio = calloc(sizeof(struct virtio_mmio), 1);
if (!virtio)
return -ENOMEM;
diff --git a/virtio/net.c b/virtio/net.c
index 70002f72..985642f6 100644
--- a/virtio/net.c
+++ b/virtio/net.c
@@ -81,6 +81,15 @@ static bool has_virtio_feature(struct net_dev *ndev, u32 feature)
return ndev->vdev.features & (1 << feature);
}
+static int virtio_net_hdr_len(struct net_dev *ndev)
+{
+ if (has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF) ||
+ !ndev->vdev.legacy)
+ return sizeof(struct virtio_net_hdr_mrg_rxbuf);
+
+ return sizeof(struct virtio_net_hdr);
+}
+
static void *virtio_net_rx_thread(void *p)
{
struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
@@ -133,7 +142,13 @@ static void *virtio_net_rx_thread(void *p)
head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
}
- if (has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF))
+ /*
+ * The device MUST set num_buffers, except in the case
+ * where the legacy driver did not negotiate
+ * VIRTIO_NET_F_MRG_RXBUF and the field does not exist.
+ */
+ if (has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF) ||
+ !ndev->vdev.legacy)
hdr->num_buffers = virtio_host_to_guest_u16(vq, num_buffers);
virt_queue__used_idx_advance(vq, num_buffers);
@@ -301,9 +316,7 @@ static bool virtio_net__tap_init(struct net_dev *ndev)
const struct virtio_net_params *params = ndev->params;
bool skipconf = !!params->tapif;
- hdr_len = has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF) ?
- sizeof(struct virtio_net_hdr_mrg_rxbuf) :
- sizeof(struct virtio_net_hdr);
+ hdr_len = virtio_net_hdr_len(ndev);
if (ioctl(ndev->tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0)
pr_warning("Config tap device TUNSETVNETHDRSZ error");
@@ -521,9 +534,7 @@ static void virtio_net_start(struct net_dev *ndev)
virtio_net__vhost_set_features(ndev) != 0)
die_perror("VHOST_SET_FEATURES failed");
} else {
- ndev->info.vnet_hdr_len = has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF) ?
- sizeof(struct virtio_net_hdr_mrg_rxbuf) :
- sizeof(struct virtio_net_hdr);
+ ndev->info.vnet_hdr_len = virtio_net_hdr_len(ndev);
uip_init(&ndev->info);
}
}