1 /* 2 * vhost-net support 3 * 4 * Copyright Red Hat, Inc. 2010 5 * 6 * Authors: 7 * Michael S. Tsirkin <mst@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 */ 12 13 #include "net.h" 14 #include "net/tap.h" 15 16 #include "virtio-net.h" 17 #include "vhost_net.h" 18 19 #include "config.h" 20 21 #ifdef CONFIG_VHOST_NET 22 #include <linux/vhost.h> 23 #include <sys/socket.h> 24 #include <linux/kvm.h> 25 #include <fcntl.h> 26 #include <sys/ioctl.h> 27 #include <linux/virtio_ring.h> 28 #include <netpacket/packet.h> 29 #include <net/ethernet.h> 30 #include <net/if.h> 31 #include <netinet/in.h> 32 33 #include <stdio.h> 34 35 #include "vhost.h" 36 37 struct vhost_net { 38 struct vhost_dev dev; 39 struct vhost_virtqueue vqs[2]; 40 int backend; 41 VLANClientState *vc; 42 }; 43 44 unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) 45 { 46 /* Clear features not supported by host kernel. */ 47 if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) { 48 features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY); 49 } 50 if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) { 51 features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC); 52 } 53 if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) { 54 features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); 55 } 56 return features; 57 } 58 59 void vhost_net_ack_features(struct vhost_net *net, unsigned features) 60 { 61 net->dev.acked_features = net->dev.backend_features; 62 if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) { 63 net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); 64 } 65 if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) { 66 net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC); 67 } 68 if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 69 net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF); 70 } 71 } 72 73 static int vhost_net_get_fd(VLANClientState *backend) 74 { 75 switch (backend->info->type) { 76 case NET_CLIENT_TYPE_TAP: 77 return tap_get_fd(backend); 78 default: 79 fprintf(stderr, "vhost-net requires tap backend\n"); 80 return -EBADFD; 81 } 82 } 83 84 struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd, 85 bool force) 86 { 87 int r; 88 struct vhost_net *net = qemu_malloc(sizeof *net); 89 if (!backend) { 90 fprintf(stderr, "vhost-net requires backend to be setup\n"); 91 goto fail; 92 } 93 r = vhost_net_get_fd(backend); 94 if (r < 0) { 95 goto fail; 96 } 97 net->vc = backend; 98 net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 : 99 (1 << VHOST_NET_F_VIRTIO_NET_HDR); 100 net->backend = r; 101 102 r = vhost_dev_init(&net->dev, devfd, force); 103 if (r < 0) { 104 goto fail; 105 } 106 if (!tap_has_vnet_hdr_len(backend, 107 sizeof(struct virtio_net_hdr_mrg_rxbuf))) { 108 net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); 109 } 110 if (~net->dev.features & net->dev.backend_features) { 111 fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n", 112 (uint64_t)(~net->dev.features & net->dev.backend_features)); 113 vhost_dev_cleanup(&net->dev); 114 goto fail; 115 } 116 117 /* Set sane init value. Override when guest acks. */ 118 vhost_net_ack_features(net, 0); 119 return net; 120 fail: 121 qemu_free(net); 122 return NULL; 123 } 124 125 bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) 126 { 127 return vhost_dev_query(&net->dev, dev); 128 } 129 130 int vhost_net_start(struct vhost_net *net, 131 VirtIODevice *dev) 132 { 133 struct vhost_vring_file file = { }; 134 int r; 135 if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 136 tap_set_vnet_hdr_len(net->vc, 137 sizeof(struct virtio_net_hdr_mrg_rxbuf)); 138 } 139 140 net->dev.nvqs = 2; 141 net->dev.vqs = net->vqs; 142 r = vhost_dev_start(&net->dev, dev); 143 if (r < 0) { 144 return r; 145 } 146 147 net->vc->info->poll(net->vc, false); 148 qemu_set_fd_handler(net->backend, NULL, NULL, NULL); 149 file.fd = net->backend; 150 for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 151 r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 152 if (r < 0) { 153 r = -errno; 154 goto fail; 155 } 156 } 157 return 0; 158 fail: 159 file.fd = -1; 160 while (file.index-- > 0) { 161 int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 162 assert(r >= 0); 163 } 164 net->vc->info->poll(net->vc, true); 165 vhost_dev_stop(&net->dev, dev); 166 if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 167 tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr)); 168 } 169 return r; 170 } 171 172 void vhost_net_stop(struct vhost_net *net, 173 VirtIODevice *dev) 174 { 175 struct vhost_vring_file file = { .fd = -1 }; 176 177 for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 178 int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 179 assert(r >= 0); 180 } 181 net->vc->info->poll(net->vc, true); 182 vhost_dev_stop(&net->dev, dev); 183 if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 184 tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr)); 185 } 186 } 187 188 void vhost_net_cleanup(struct vhost_net *net) 189 { 190 vhost_dev_cleanup(&net->dev); 191 if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 192 tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr)); 193 } 194 qemu_free(net); 195 } 196 #else 197 struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd, 198 bool force) 199 { 200 return NULL; 201 } 202 203 bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) 204 { 205 return false; 206 } 207 208 int vhost_net_start(struct vhost_net *net, 209 VirtIODevice *dev) 210 { 211 return -ENOSYS; 212 } 213 void vhost_net_stop(struct vhost_net *net, 214 VirtIODevice *dev) 215 { 216 } 217 218 void vhost_net_cleanup(struct vhost_net *net) 219 { 220 } 221 222 unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) 223 { 224 return features; 225 } 226 void vhost_net_ack_features(struct vhost_net *net, unsigned features) 227 { 228 } 229 #endif 230