1 /* 2 * vhost-user.c 3 * 4 * Copyright (c) 2013 Virtual Open Systems Sarl. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 #include "clients.h" 13 #include "net/vhost_net.h" 14 #include "net/vhost-user.h" 15 #include "hw/virtio/vhost.h" 16 #include "hw/virtio/vhost-user.h" 17 #include "standard-headers/linux/virtio_net.h" 18 #include "chardev/char-fe.h" 19 #include "qapi/error.h" 20 #include "qapi/qapi-commands-net.h" 21 #include "qapi/qapi-events-net.h" 22 #include "qemu/config-file.h" 23 #include "qemu/error-report.h" 24 #include "qemu/option.h" 25 #include "trace.h" 26 27 static const int user_feature_bits[] = { 28 VIRTIO_F_NOTIFY_ON_EMPTY, 29 VIRTIO_F_NOTIFICATION_DATA, 30 VIRTIO_RING_F_INDIRECT_DESC, 31 VIRTIO_RING_F_EVENT_IDX, 32 33 VIRTIO_F_ANY_LAYOUT, 34 VIRTIO_F_VERSION_1, 35 VIRTIO_NET_F_CSUM, 36 VIRTIO_NET_F_GUEST_CSUM, 37 VIRTIO_NET_F_GSO, 38 VIRTIO_NET_F_GUEST_TSO4, 39 VIRTIO_NET_F_GUEST_TSO6, 40 VIRTIO_NET_F_GUEST_ECN, 41 VIRTIO_NET_F_GUEST_UFO, 42 VIRTIO_NET_F_HOST_TSO4, 43 VIRTIO_NET_F_HOST_TSO6, 44 VIRTIO_NET_F_HOST_ECN, 45 VIRTIO_NET_F_HOST_UFO, 46 VIRTIO_NET_F_MRG_RXBUF, 47 VIRTIO_NET_F_MTU, 48 VIRTIO_F_IOMMU_PLATFORM, 49 VIRTIO_F_RING_PACKED, 50 VIRTIO_F_RING_RESET, 51 VIRTIO_F_IN_ORDER, 52 VIRTIO_NET_F_RSS, 53 VIRTIO_NET_F_RSC_EXT, 54 VIRTIO_NET_F_HASH_REPORT, 55 VIRTIO_NET_F_GUEST_USO4, 56 VIRTIO_NET_F_GUEST_USO6, 57 VIRTIO_NET_F_HOST_USO, 58 59 /* This bit implies RARP isn't sent by QEMU out of band */ 60 VIRTIO_NET_F_GUEST_ANNOUNCE, 61 62 VIRTIO_NET_F_MQ, 63 64 VHOST_INVALID_FEATURE_BIT 65 }; 66 67 typedef struct NetVhostUserState { 68 NetClientState nc; 69 CharBackend chr; /* only queue index 0 */ 70 VhostUserState *vhost_user; 71 VHostNetState *vhost_net; 72 guint watch; 73 uint64_t acked_features; 74 bool started; 75 } NetVhostUserState; 76 77 static struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc) 78 { 79 NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); 80 assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); 81 return s->vhost_net; 82 } 83 84 uint64_t vhost_user_get_acked_features(NetClientState *nc) 85 { 86 NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); 87 assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); 88 return s->acked_features; 89 } 90 91 void vhost_user_save_acked_features(NetClientState *nc) 92 { 93 NetVhostUserState *s; 94 95 s = DO_UPCAST(NetVhostUserState, nc, nc); 96 if (s->vhost_net) { 97 uint64_t features = vhost_net_get_acked_features(s->vhost_net); 98 if (features) { 99 s->acked_features = features; 100 } 101 } 102 } 103 104 static void vhost_user_stop(int queues, NetClientState *ncs[]) 105 { 106 int i; 107 NetVhostUserState *s; 108 109 for (i = 0; i < queues; i++) { 110 assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); 111 112 s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); 113 114 if (s->vhost_net) { 115 vhost_user_save_acked_features(ncs[i]); 116 vhost_net_cleanup(s->vhost_net); 117 } 118 } 119 } 120 121 static int vhost_user_start(int queues, NetClientState *ncs[], 122 VhostUserState *be) 123 { 124 VhostNetOptions options; 125 struct vhost_net *net = NULL; 126 NetVhostUserState *s; 127 int max_queues; 128 int i; 129 130 options.backend_type = VHOST_BACKEND_TYPE_USER; 131 132 for (i = 0; i < queues; i++) { 133 assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); 134 135 s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); 136 137 options.net_backend = ncs[i]; 138 options.opaque = be; 139 options.busyloop_timeout = 0; 140 options.nvqs = 2; 141 options.feature_bits = user_feature_bits; 142 net = vhost_net_init(&options); 143 if (!net) { 144 error_report("failed to init vhost_net for queue %d", i); 145 goto err; 146 } 147 148 if (i == 0) { 149 max_queues = vhost_net_get_max_queues(net); 150 if (queues > max_queues) { 151 error_report("you are asking more queues than supported: %d", 152 max_queues); 153 goto err; 154 } 155 } 156 157 if (s->vhost_net) { 158 vhost_net_cleanup(s->vhost_net); 159 g_free(s->vhost_net); 160 } 161 s->vhost_net = net; 162 } 163 164 return 0; 165 166 err: 167 if (net) { 168 vhost_net_cleanup(net); 169 g_free(net); 170 } 171 vhost_user_stop(i, ncs); 172 return -1; 173 } 174 175 static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf, 176 size_t size) 177 { 178 /* In case of RARP (message size is 60) notify backup to send a fake RARP. 179 This fake RARP will be sent by backend only for guest 180 without GUEST_ANNOUNCE capability. 181 */ 182 if (size == 60) { 183 NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); 184 int r; 185 static int display_rarp_failure = 1; 186 char mac_addr[6]; 187 188 /* extract guest mac address from the RARP message */ 189 memcpy(mac_addr, &buf[6], 6); 190 191 r = vhost_net_notify_migration_done(s->vhost_net, mac_addr); 192 193 if ((r != 0) && (display_rarp_failure)) { 194 fprintf(stderr, 195 "Vhost user backend fails to broadcast fake RARP\n"); 196 fflush(stderr); 197 display_rarp_failure = 0; 198 } 199 } 200 201 return size; 202 } 203 204 static void net_vhost_user_cleanup(NetClientState *nc) 205 { 206 NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc); 207 208 if (s->vhost_net) { 209 vhost_net_cleanup(s->vhost_net); 210 g_free(s->vhost_net); 211 s->vhost_net = NULL; 212 } 213 if (nc->queue_index == 0) { 214 if (s->watch) { 215 g_source_remove(s->watch); 216 s->watch = 0; 217 } 218 qemu_chr_fe_deinit(&s->chr, true); 219 if (s->vhost_user) { 220 vhost_user_cleanup(s->vhost_user); 221 g_free(s->vhost_user); 222 s->vhost_user = NULL; 223 } 224 } 225 226 qemu_purge_queued_packets(nc); 227 } 228 229 static int vhost_user_set_vnet_endianness(NetClientState *nc, 230 bool enable) 231 { 232 /* Nothing to do. If the server supports 233 * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the 234 * vnet header endianness from there. If it doesn't, negotiation 235 * fails. 236 */ 237 return 0; 238 } 239 240 static bool vhost_user_has_vnet_hdr(NetClientState *nc) 241 { 242 assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); 243 244 return true; 245 } 246 247 static bool vhost_user_has_ufo(NetClientState *nc) 248 { 249 assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); 250 251 return true; 252 } 253 254 static bool vhost_user_check_peer_type(NetClientState *nc, ObjectClass *oc, 255 Error **errp) 256 { 257 const char *driver = object_class_get_name(oc); 258 259 if (!g_str_has_prefix(driver, "virtio-net-")) { 260 error_setg(errp, "vhost-user requires frontend driver virtio-net-*"); 261 return false; 262 } 263 264 return true; 265 } 266 267 static NetClientInfo net_vhost_user_info = { 268 .type = NET_CLIENT_DRIVER_VHOST_USER, 269 .size = sizeof(NetVhostUserState), 270 .receive = vhost_user_receive, 271 .cleanup = net_vhost_user_cleanup, 272 .has_vnet_hdr = vhost_user_has_vnet_hdr, 273 .has_ufo = vhost_user_has_ufo, 274 .set_vnet_be = vhost_user_set_vnet_endianness, 275 .set_vnet_le = vhost_user_set_vnet_endianness, 276 .check_peer_type = vhost_user_check_peer_type, 277 .get_vhost_net = vhost_user_get_vhost_net, 278 }; 279 280 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, 281 void *opaque) 282 { 283 NetVhostUserState *s = opaque; 284 285 qemu_chr_fe_disconnect(&s->chr); 286 287 return G_SOURCE_CONTINUE; 288 } 289 290 static void net_vhost_user_event(void *opaque, QEMUChrEvent event); 291 292 static void chr_closed_bh(void *opaque) 293 { 294 const char *name = opaque; 295 NetClientState *ncs[MAX_QUEUE_NUM]; 296 NetVhostUserState *s; 297 Error *err = NULL; 298 int queues, i; 299 300 queues = qemu_find_net_clients_except(name, ncs, 301 NET_CLIENT_DRIVER_NIC, 302 MAX_QUEUE_NUM); 303 assert(queues < MAX_QUEUE_NUM); 304 305 s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); 306 307 for (i = queues -1; i >= 0; i--) { 308 vhost_user_save_acked_features(ncs[i]); 309 } 310 311 net_client_set_link(ncs, queues, false); 312 313 qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, 314 NULL, opaque, NULL, true); 315 316 if (err) { 317 error_report_err(err); 318 } 319 qapi_event_send_netdev_vhost_user_disconnected(name); 320 } 321 322 static void net_vhost_user_event(void *opaque, QEMUChrEvent event) 323 { 324 const char *name = opaque; 325 NetClientState *ncs[MAX_QUEUE_NUM]; 326 NetVhostUserState *s; 327 Chardev *chr; 328 Error *err = NULL; 329 int queues; 330 331 queues = qemu_find_net_clients_except(name, ncs, 332 NET_CLIENT_DRIVER_NIC, 333 MAX_QUEUE_NUM); 334 assert(queues < MAX_QUEUE_NUM); 335 336 s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); 337 chr = qemu_chr_fe_get_driver(&s->chr); 338 trace_vhost_user_event(chr->label, event); 339 switch (event) { 340 case CHR_EVENT_OPENED: 341 if (vhost_user_start(queues, ncs, s->vhost_user) < 0) { 342 qemu_chr_fe_disconnect(&s->chr); 343 return; 344 } 345 s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP, 346 net_vhost_user_watch, s); 347 net_client_set_link(ncs, queues, true); 348 s->started = true; 349 qapi_event_send_netdev_vhost_user_connected(name, chr->label); 350 break; 351 case CHR_EVENT_CLOSED: 352 /* a close event may happen during a read/write, but vhost 353 * code assumes the vhost_dev remains setup, so delay the 354 * stop & clear to idle. 355 * FIXME: better handle failure in vhost code, remove bh 356 */ 357 if (s->watch) { 358 AioContext *ctx = qemu_get_current_aio_context(); 359 360 g_source_remove(s->watch); 361 s->watch = 0; 362 qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL, 363 NULL, NULL, false); 364 365 aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque); 366 } 367 break; 368 case CHR_EVENT_BREAK: 369 case CHR_EVENT_MUX_IN: 370 case CHR_EVENT_MUX_OUT: 371 /* Ignore */ 372 break; 373 } 374 375 if (err) { 376 error_report_err(err); 377 } 378 } 379 380 static int net_vhost_user_init(NetClientState *peer, const char *device, 381 const char *name, Chardev *chr, 382 int queues) 383 { 384 Error *err = NULL; 385 NetClientState *nc, *nc0 = NULL; 386 NetVhostUserState *s = NULL; 387 VhostUserState *user; 388 int i; 389 390 assert(name); 391 assert(queues > 0); 392 393 user = g_new0(struct VhostUserState, 1); 394 for (i = 0; i < queues; i++) { 395 nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); 396 qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label); 397 nc->queue_index = i; 398 if (!nc0) { 399 nc0 = nc; 400 s = DO_UPCAST(NetVhostUserState, nc, nc); 401 if (!qemu_chr_fe_init(&s->chr, chr, &err) || 402 !vhost_user_init(user, &s->chr, &err)) { 403 error_report_err(err); 404 goto err; 405 } 406 } 407 s = DO_UPCAST(NetVhostUserState, nc, nc); 408 s->vhost_user = user; 409 } 410 411 s = DO_UPCAST(NetVhostUserState, nc, nc0); 412 do { 413 if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) { 414 error_report_err(err); 415 goto err; 416 } 417 qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, 418 net_vhost_user_event, NULL, nc0->name, NULL, 419 true); 420 } while (!s->started); 421 422 assert(s->vhost_net); 423 424 return 0; 425 426 err: 427 if (user) { 428 vhost_user_cleanup(user); 429 g_free(user); 430 if (s) { 431 s->vhost_user = NULL; 432 } 433 } 434 if (nc0) { 435 qemu_del_net_client(nc0); 436 } 437 438 return -1; 439 } 440 441 static Chardev *net_vhost_claim_chardev( 442 const NetdevVhostUserOptions *opts, Error **errp) 443 { 444 Chardev *chr = qemu_chr_find(opts->chardev); 445 446 if (chr == NULL) { 447 error_setg(errp, "chardev \"%s\" not found", opts->chardev); 448 return NULL; 449 } 450 451 if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) { 452 error_setg(errp, "chardev \"%s\" is not reconnectable", 453 opts->chardev); 454 return NULL; 455 } 456 if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) { 457 error_setg(errp, "chardev \"%s\" does not support FD passing", 458 opts->chardev); 459 return NULL; 460 } 461 462 return chr; 463 } 464 465 int net_init_vhost_user(const Netdev *netdev, const char *name, 466 NetClientState *peer, Error **errp) 467 { 468 int queues; 469 const NetdevVhostUserOptions *vhost_user_opts; 470 Chardev *chr; 471 472 assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER); 473 vhost_user_opts = &netdev->u.vhost_user; 474 475 chr = net_vhost_claim_chardev(vhost_user_opts, errp); 476 if (!chr) { 477 return -1; 478 } 479 480 queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1; 481 if (queues < 1 || queues > MAX_QUEUE_NUM) { 482 error_setg(errp, 483 "vhost-user number of queues must be in range [1, %d]", 484 MAX_QUEUE_NUM); 485 return -1; 486 } 487 488 return net_vhost_user_init(peer, "vhost_user", name, chr, queues); 489 } 490