diff options
author | Jean-Philippe Brucker <jean-philippe.brucker@arm.com> | 2022-06-07 18:02:27 +0100 |
---|---|---|
committer | Will Deacon <will@kernel.org> | 2022-06-09 13:44:15 +0100 |
commit | b231683c336132441496060a81726305ca56b11b (patch) | |
tree | f4c24f35ae15371eb0c777d1abce268e8a82d976 | |
parent | 8b27bcff44fd4adaa1466e3198e4222816eefa06 (diff) | |
download | kvmtool-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.h | 1 | ||||
-rw-r--r-- | virtio/core.c | 2 | ||||
-rw-r--r-- | virtio/net.c | 25 |
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); } } |