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 * Contributions after 2012-01-13 are licensed under the terms of the 13 * GNU GPL, version 2 or (at your option) any later version. 14 */ 15 16 #include "net/net.h" 17 #include "net/tap.h" 18 19 #include "hw/virtio/virtio-net.h" 20 #include "net/vhost_net.h" 21 #include "qemu/error-report.h" 22 23 #include "config.h" 24 25 #ifdef CONFIG_VHOST_NET 26 #include <linux/vhost.h> 27 #include <sys/socket.h> 28 #include <linux/kvm.h> 29 #include <fcntl.h> 30 #include <sys/ioctl.h> 31 #include <linux/virtio_ring.h> 32 #include <netpacket/packet.h> 33 #include <net/ethernet.h> 34 #include <net/if.h> 35 #include <netinet/in.h> 36 37 #include <stdio.h> 38 39 #include "hw/virtio/vhost.h" 40 41 struct vhost_net { 42 struct vhost_dev dev; 43 struct vhost_virtqueue vqs[2]; 44 int backend; 45 NetClientState *nc; 46 }; 47 48 unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) 49 { 50 /* Clear features not supported by host kernel. */ 51 if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) { 52 features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY); 53 } 54 if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) { 55 features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC); 56 } 57 if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) { 58 features &= ~(1 << VIRTIO_RING_F_EVENT_IDX); 59 } 60 if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) { 61 features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); 62 } 63 return features; 64 } 65 66 void vhost_net_ack_features(struct vhost_net *net, unsigned features) 67 { 68 net->dev.acked_features = net->dev.backend_features; 69 if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) { 70 net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY); 71 } 72 if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) { 73 net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC); 74 } 75 if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) { 76 net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX); 77 } 78 if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) { 79 net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF); 80 } 81 } 82 83 static int vhost_net_get_fd(NetClientState *backend) 84 { 85 switch (backend->info->type) { 86 case NET_CLIENT_OPTIONS_KIND_TAP: 87 return tap_get_fd(backend); 88 default: 89 fprintf(stderr, "vhost-net requires tap backend\n"); 90 return -EBADFD; 91 } 92 } 93 94 struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, 95 bool force) 96 { 97 int r; 98 struct vhost_net *net = g_malloc(sizeof *net); 99 if (!backend) { 100 fprintf(stderr, "vhost-net requires backend to be setup\n"); 101 goto fail; 102 } 103 r = vhost_net_get_fd(backend); 104 if (r < 0) { 105 goto fail; 106 } 107 net->nc = backend; 108 net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 : 109 (1 << VHOST_NET_F_VIRTIO_NET_HDR); 110 net->backend = r; 111 112 net->dev.nvqs = 2; 113 net->dev.vqs = net->vqs; 114 115 r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force); 116 if (r < 0) { 117 goto fail; 118 } 119 if (!tap_has_vnet_hdr_len(backend, 120 sizeof(struct virtio_net_hdr_mrg_rxbuf))) { 121 net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); 122 } 123 if (~net->dev.features & net->dev.backend_features) { 124 fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n", 125 (uint64_t)(~net->dev.features & net->dev.backend_features)); 126 vhost_dev_cleanup(&net->dev); 127 goto fail; 128 } 129 130 /* Set sane init value. Override when guest acks. */ 131 vhost_net_ack_features(net, 0); 132 return net; 133 fail: 134 g_free(net); 135 return NULL; 136 } 137 138 bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) 139 { 140 return vhost_dev_query(&net->dev, dev); 141 } 142 143 static int vhost_net_start_one(struct vhost_net *net, 144 VirtIODevice *dev, 145 int vq_index) 146 { 147 struct vhost_vring_file file = { }; 148 int r; 149 150 if (net->dev.started) { 151 return 0; 152 } 153 154 net->dev.nvqs = 2; 155 net->dev.vqs = net->vqs; 156 net->dev.vq_index = vq_index; 157 158 r = vhost_dev_enable_notifiers(&net->dev, dev); 159 if (r < 0) { 160 goto fail_notifiers; 161 } 162 163 r = vhost_dev_start(&net->dev, dev); 164 if (r < 0) { 165 goto fail_start; 166 } 167 168 net->nc->info->poll(net->nc, false); 169 qemu_set_fd_handler(net->backend, NULL, NULL, NULL); 170 file.fd = net->backend; 171 for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 172 r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 173 if (r < 0) { 174 r = -errno; 175 goto fail; 176 } 177 } 178 return 0; 179 fail: 180 file.fd = -1; 181 while (file.index-- > 0) { 182 int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 183 assert(r >= 0); 184 } 185 net->nc->info->poll(net->nc, true); 186 vhost_dev_stop(&net->dev, dev); 187 fail_start: 188 vhost_dev_disable_notifiers(&net->dev, dev); 189 fail_notifiers: 190 return r; 191 } 192 193 static void vhost_net_stop_one(struct vhost_net *net, 194 VirtIODevice *dev) 195 { 196 struct vhost_vring_file file = { .fd = -1 }; 197 198 if (!net->dev.started) { 199 return; 200 } 201 202 for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { 203 int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); 204 assert(r >= 0); 205 } 206 net->nc->info->poll(net->nc, true); 207 vhost_dev_stop(&net->dev, dev); 208 vhost_dev_disable_notifiers(&net->dev, dev); 209 } 210 211 int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, 212 int total_queues) 213 { 214 int r, i = 0; 215 216 if (!dev->binding->set_guest_notifiers) { 217 error_report("binding does not support guest notifiers"); 218 r = -ENOSYS; 219 goto err; 220 } 221 222 for (i = 0; i < total_queues; i++) { 223 r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2); 224 225 if (r < 0) { 226 goto err; 227 } 228 } 229 230 r = dev->binding->set_guest_notifiers(dev->binding_opaque, 231 total_queues * 2, 232 true); 233 if (r < 0) { 234 error_report("Error binding guest notifier: %d", -r); 235 goto err; 236 } 237 238 return 0; 239 240 err: 241 while (--i >= 0) { 242 vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev); 243 } 244 return r; 245 } 246 247 void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, 248 int total_queues) 249 { 250 int i, r; 251 252 r = dev->binding->set_guest_notifiers(dev->binding_opaque, 253 total_queues * 2, 254 false); 255 if (r < 0) { 256 fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); 257 fflush(stderr); 258 } 259 assert(r >= 0); 260 261 for (i = 0; i < total_queues; i++) { 262 vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev); 263 } 264 } 265 266 void vhost_net_cleanup(struct vhost_net *net) 267 { 268 vhost_dev_cleanup(&net->dev); 269 g_free(net); 270 } 271 272 bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) 273 { 274 return vhost_virtqueue_pending(&net->dev, idx); 275 } 276 277 void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, 278 int idx, bool mask) 279 { 280 vhost_virtqueue_mask(&net->dev, dev, idx, mask); 281 } 282 #else 283 struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, 284 bool force) 285 { 286 error_report("vhost-net support is not compiled in"); 287 return NULL; 288 } 289 290 bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) 291 { 292 return false; 293 } 294 295 int vhost_net_start(VirtIODevice *dev, 296 NetClientState *ncs, 297 int total_queues) 298 { 299 return -ENOSYS; 300 } 301 void vhost_net_stop(VirtIODevice *dev, 302 NetClientState *ncs, 303 int total_queues) 304 { 305 } 306 307 void vhost_net_cleanup(struct vhost_net *net) 308 { 309 } 310 311 unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) 312 { 313 return features; 314 } 315 void vhost_net_ack_features(struct vhost_net *net, unsigned features) 316 { 317 } 318 319 bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) 320 { 321 return -ENOSYS; 322 } 323 324 void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, 325 int idx, bool mask) 326 { 327 } 328 #endif 329