1 /* 2 * vhost-user 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 "qapi/error.h" 13 #include "hw/virtio/vhost.h" 14 #include "hw/virtio/vhost-backend.h" 15 #include "hw/virtio/virtio-net.h" 16 #include "sysemu/char.h" 17 #include "sysemu/kvm.h" 18 #include "qemu/error-report.h" 19 #include "qemu/sockets.h" 20 21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 23 #include <sys/un.h> 24 #include <linux/vhost.h> 25 26 #define VHOST_MEMORY_MAX_NREGIONS 8 27 #define VHOST_USER_F_PROTOCOL_FEATURES 30 28 29 enum VhostUserProtocolFeature { 30 VHOST_USER_PROTOCOL_F_MQ = 0, 31 VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, 32 VHOST_USER_PROTOCOL_F_RARP = 2, 33 VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, 34 VHOST_USER_PROTOCOL_F_NET_MTU = 4, 35 36 VHOST_USER_PROTOCOL_F_MAX 37 }; 38 39 #define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1) 40 41 typedef enum VhostUserRequest { 42 VHOST_USER_NONE = 0, 43 VHOST_USER_GET_FEATURES = 1, 44 VHOST_USER_SET_FEATURES = 2, 45 VHOST_USER_SET_OWNER = 3, 46 VHOST_USER_RESET_OWNER = 4, 47 VHOST_USER_SET_MEM_TABLE = 5, 48 VHOST_USER_SET_LOG_BASE = 6, 49 VHOST_USER_SET_LOG_FD = 7, 50 VHOST_USER_SET_VRING_NUM = 8, 51 VHOST_USER_SET_VRING_ADDR = 9, 52 VHOST_USER_SET_VRING_BASE = 10, 53 VHOST_USER_GET_VRING_BASE = 11, 54 VHOST_USER_SET_VRING_KICK = 12, 55 VHOST_USER_SET_VRING_CALL = 13, 56 VHOST_USER_SET_VRING_ERR = 14, 57 VHOST_USER_GET_PROTOCOL_FEATURES = 15, 58 VHOST_USER_SET_PROTOCOL_FEATURES = 16, 59 VHOST_USER_GET_QUEUE_NUM = 17, 60 VHOST_USER_SET_VRING_ENABLE = 18, 61 VHOST_USER_SEND_RARP = 19, 62 VHOST_USER_NET_SET_MTU = 20, 63 VHOST_USER_MAX 64 } VhostUserRequest; 65 66 typedef struct VhostUserMemoryRegion { 67 uint64_t guest_phys_addr; 68 uint64_t memory_size; 69 uint64_t userspace_addr; 70 uint64_t mmap_offset; 71 } VhostUserMemoryRegion; 72 73 typedef struct VhostUserMemory { 74 uint32_t nregions; 75 uint32_t padding; 76 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; 77 } VhostUserMemory; 78 79 typedef struct VhostUserLog { 80 uint64_t mmap_size; 81 uint64_t mmap_offset; 82 } VhostUserLog; 83 84 typedef struct VhostUserMsg { 85 VhostUserRequest request; 86 87 #define VHOST_USER_VERSION_MASK (0x3) 88 #define VHOST_USER_REPLY_MASK (0x1<<2) 89 #define VHOST_USER_NEED_REPLY_MASK (0x1 << 3) 90 uint32_t flags; 91 uint32_t size; /* the following payload size */ 92 union { 93 #define VHOST_USER_VRING_IDX_MASK (0xff) 94 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8) 95 uint64_t u64; 96 struct vhost_vring_state state; 97 struct vhost_vring_addr addr; 98 VhostUserMemory memory; 99 VhostUserLog log; 100 } payload; 101 } QEMU_PACKED VhostUserMsg; 102 103 static VhostUserMsg m __attribute__ ((unused)); 104 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \ 105 + sizeof(m.flags) \ 106 + sizeof(m.size)) 107 108 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE) 109 110 /* The version of the protocol we support */ 111 #define VHOST_USER_VERSION (0x1) 112 113 static bool ioeventfd_enabled(void) 114 { 115 return kvm_enabled() && kvm_eventfds_enabled(); 116 } 117 118 static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) 119 { 120 CharBackend *chr = dev->opaque; 121 uint8_t *p = (uint8_t *) msg; 122 int r, size = VHOST_USER_HDR_SIZE; 123 124 r = qemu_chr_fe_read_all(chr, p, size); 125 if (r != size) { 126 error_report("Failed to read msg header. Read %d instead of %d." 127 " Original request %d.", r, size, msg->request); 128 goto fail; 129 } 130 131 /* validate received flags */ 132 if (msg->flags != (VHOST_USER_REPLY_MASK | VHOST_USER_VERSION)) { 133 error_report("Failed to read msg header." 134 " Flags 0x%x instead of 0x%x.", msg->flags, 135 VHOST_USER_REPLY_MASK | VHOST_USER_VERSION); 136 goto fail; 137 } 138 139 /* validate message size is sane */ 140 if (msg->size > VHOST_USER_PAYLOAD_SIZE) { 141 error_report("Failed to read msg header." 142 " Size %d exceeds the maximum %zu.", msg->size, 143 VHOST_USER_PAYLOAD_SIZE); 144 goto fail; 145 } 146 147 if (msg->size) { 148 p += VHOST_USER_HDR_SIZE; 149 size = msg->size; 150 r = qemu_chr_fe_read_all(chr, p, size); 151 if (r != size) { 152 error_report("Failed to read msg payload." 153 " Read %d instead of %d.", r, msg->size); 154 goto fail; 155 } 156 } 157 158 return 0; 159 160 fail: 161 return -1; 162 } 163 164 static int process_message_reply(struct vhost_dev *dev, 165 const VhostUserMsg *msg) 166 { 167 VhostUserMsg msg_reply; 168 169 if ((msg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) { 170 return 0; 171 } 172 173 if (vhost_user_read(dev, &msg_reply) < 0) { 174 return -1; 175 } 176 177 if (msg_reply.request != msg->request) { 178 error_report("Received unexpected msg type." 179 "Expected %d received %d", 180 msg->request, msg_reply.request); 181 return -1; 182 } 183 184 return msg_reply.payload.u64 ? -1 : 0; 185 } 186 187 static bool vhost_user_one_time_request(VhostUserRequest request) 188 { 189 switch (request) { 190 case VHOST_USER_SET_OWNER: 191 case VHOST_USER_RESET_OWNER: 192 case VHOST_USER_SET_MEM_TABLE: 193 case VHOST_USER_GET_QUEUE_NUM: 194 case VHOST_USER_NET_SET_MTU: 195 return true; 196 default: 197 return false; 198 } 199 } 200 201 /* most non-init callers ignore the error */ 202 static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, 203 int *fds, int fd_num) 204 { 205 CharBackend *chr = dev->opaque; 206 int ret, size = VHOST_USER_HDR_SIZE + msg->size; 207 208 /* 209 * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, 210 * we just need send it once in the first time. For later such 211 * request, we just ignore it. 212 */ 213 if (vhost_user_one_time_request(msg->request) && dev->vq_index != 0) { 214 msg->flags &= ~VHOST_USER_NEED_REPLY_MASK; 215 return 0; 216 } 217 218 if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) { 219 error_report("Failed to set msg fds."); 220 return -1; 221 } 222 223 ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size); 224 if (ret != size) { 225 error_report("Failed to write msg." 226 " Wrote %d instead of %d.", ret, size); 227 return -1; 228 } 229 230 return 0; 231 } 232 233 static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, 234 struct vhost_log *log) 235 { 236 int fds[VHOST_MEMORY_MAX_NREGIONS]; 237 size_t fd_num = 0; 238 bool shmfd = virtio_has_feature(dev->protocol_features, 239 VHOST_USER_PROTOCOL_F_LOG_SHMFD); 240 VhostUserMsg msg = { 241 .request = VHOST_USER_SET_LOG_BASE, 242 .flags = VHOST_USER_VERSION, 243 .payload.log.mmap_size = log->size * sizeof(*(log->log)), 244 .payload.log.mmap_offset = 0, 245 .size = sizeof(msg.payload.log), 246 }; 247 248 if (shmfd && log->fd != -1) { 249 fds[fd_num++] = log->fd; 250 } 251 252 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { 253 return -1; 254 } 255 256 if (shmfd) { 257 msg.size = 0; 258 if (vhost_user_read(dev, &msg) < 0) { 259 return -1; 260 } 261 262 if (msg.request != VHOST_USER_SET_LOG_BASE) { 263 error_report("Received unexpected msg type. " 264 "Expected %d received %d", 265 VHOST_USER_SET_LOG_BASE, msg.request); 266 return -1; 267 } 268 } 269 270 return 0; 271 } 272 273 static int vhost_user_set_mem_table(struct vhost_dev *dev, 274 struct vhost_memory *mem) 275 { 276 int fds[VHOST_MEMORY_MAX_NREGIONS]; 277 int i, fd; 278 size_t fd_num = 0; 279 bool reply_supported = virtio_has_feature(dev->protocol_features, 280 VHOST_USER_PROTOCOL_F_REPLY_ACK); 281 282 VhostUserMsg msg = { 283 .request = VHOST_USER_SET_MEM_TABLE, 284 .flags = VHOST_USER_VERSION, 285 }; 286 287 if (reply_supported) { 288 msg.flags |= VHOST_USER_NEED_REPLY_MASK; 289 } 290 291 for (i = 0; i < dev->mem->nregions; ++i) { 292 struct vhost_memory_region *reg = dev->mem->regions + i; 293 ram_addr_t offset; 294 MemoryRegion *mr; 295 296 assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); 297 mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, 298 &offset); 299 fd = memory_region_get_fd(mr); 300 if (fd > 0) { 301 msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; 302 msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; 303 msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr; 304 msg.payload.memory.regions[fd_num].mmap_offset = offset; 305 assert(fd_num < VHOST_MEMORY_MAX_NREGIONS); 306 fds[fd_num++] = fd; 307 } 308 } 309 310 msg.payload.memory.nregions = fd_num; 311 312 if (!fd_num) { 313 error_report("Failed initializing vhost-user memory map, " 314 "consider using -object memory-backend-file share=on"); 315 return -1; 316 } 317 318 msg.size = sizeof(msg.payload.memory.nregions); 319 msg.size += sizeof(msg.payload.memory.padding); 320 msg.size += fd_num * sizeof(VhostUserMemoryRegion); 321 322 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { 323 return -1; 324 } 325 326 if (reply_supported) { 327 return process_message_reply(dev, &msg); 328 } 329 330 return 0; 331 } 332 333 static int vhost_user_set_vring_addr(struct vhost_dev *dev, 334 struct vhost_vring_addr *addr) 335 { 336 VhostUserMsg msg = { 337 .request = VHOST_USER_SET_VRING_ADDR, 338 .flags = VHOST_USER_VERSION, 339 .payload.addr = *addr, 340 .size = sizeof(msg.payload.addr), 341 }; 342 343 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 344 return -1; 345 } 346 347 return 0; 348 } 349 350 static int vhost_user_set_vring_endian(struct vhost_dev *dev, 351 struct vhost_vring_state *ring) 352 { 353 error_report("vhost-user trying to send unhandled ioctl"); 354 return -1; 355 } 356 357 static int vhost_set_vring(struct vhost_dev *dev, 358 unsigned long int request, 359 struct vhost_vring_state *ring) 360 { 361 VhostUserMsg msg = { 362 .request = request, 363 .flags = VHOST_USER_VERSION, 364 .payload.state = *ring, 365 .size = sizeof(msg.payload.state), 366 }; 367 368 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 369 return -1; 370 } 371 372 return 0; 373 } 374 375 static int vhost_user_set_vring_num(struct vhost_dev *dev, 376 struct vhost_vring_state *ring) 377 { 378 return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring); 379 } 380 381 static int vhost_user_set_vring_base(struct vhost_dev *dev, 382 struct vhost_vring_state *ring) 383 { 384 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring); 385 } 386 387 static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) 388 { 389 int i; 390 391 if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) { 392 return -1; 393 } 394 395 for (i = 0; i < dev->nvqs; ++i) { 396 struct vhost_vring_state state = { 397 .index = dev->vq_index + i, 398 .num = enable, 399 }; 400 401 vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); 402 } 403 404 return 0; 405 } 406 407 static int vhost_user_get_vring_base(struct vhost_dev *dev, 408 struct vhost_vring_state *ring) 409 { 410 VhostUserMsg msg = { 411 .request = VHOST_USER_GET_VRING_BASE, 412 .flags = VHOST_USER_VERSION, 413 .payload.state = *ring, 414 .size = sizeof(msg.payload.state), 415 }; 416 417 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 418 return -1; 419 } 420 421 if (vhost_user_read(dev, &msg) < 0) { 422 return -1; 423 } 424 425 if (msg.request != VHOST_USER_GET_VRING_BASE) { 426 error_report("Received unexpected msg type. Expected %d received %d", 427 VHOST_USER_GET_VRING_BASE, msg.request); 428 return -1; 429 } 430 431 if (msg.size != sizeof(msg.payload.state)) { 432 error_report("Received bad msg size."); 433 return -1; 434 } 435 436 *ring = msg.payload.state; 437 438 return 0; 439 } 440 441 static int vhost_set_vring_file(struct vhost_dev *dev, 442 VhostUserRequest request, 443 struct vhost_vring_file *file) 444 { 445 int fds[VHOST_MEMORY_MAX_NREGIONS]; 446 size_t fd_num = 0; 447 VhostUserMsg msg = { 448 .request = request, 449 .flags = VHOST_USER_VERSION, 450 .payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK, 451 .size = sizeof(msg.payload.u64), 452 }; 453 454 if (ioeventfd_enabled() && file->fd > 0) { 455 fds[fd_num++] = file->fd; 456 } else { 457 msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK; 458 } 459 460 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { 461 return -1; 462 } 463 464 return 0; 465 } 466 467 static int vhost_user_set_vring_kick(struct vhost_dev *dev, 468 struct vhost_vring_file *file) 469 { 470 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file); 471 } 472 473 static int vhost_user_set_vring_call(struct vhost_dev *dev, 474 struct vhost_vring_file *file) 475 { 476 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file); 477 } 478 479 static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64) 480 { 481 VhostUserMsg msg = { 482 .request = request, 483 .flags = VHOST_USER_VERSION, 484 .payload.u64 = u64, 485 .size = sizeof(msg.payload.u64), 486 }; 487 488 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 489 return -1; 490 } 491 492 return 0; 493 } 494 495 static int vhost_user_set_features(struct vhost_dev *dev, 496 uint64_t features) 497 { 498 return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features); 499 } 500 501 static int vhost_user_set_protocol_features(struct vhost_dev *dev, 502 uint64_t features) 503 { 504 return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features); 505 } 506 507 static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) 508 { 509 VhostUserMsg msg = { 510 .request = request, 511 .flags = VHOST_USER_VERSION, 512 }; 513 514 if (vhost_user_one_time_request(request) && dev->vq_index != 0) { 515 return 0; 516 } 517 518 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 519 return -1; 520 } 521 522 if (vhost_user_read(dev, &msg) < 0) { 523 return -1; 524 } 525 526 if (msg.request != request) { 527 error_report("Received unexpected msg type. Expected %d received %d", 528 request, msg.request); 529 return -1; 530 } 531 532 if (msg.size != sizeof(msg.payload.u64)) { 533 error_report("Received bad msg size."); 534 return -1; 535 } 536 537 *u64 = msg.payload.u64; 538 539 return 0; 540 } 541 542 static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) 543 { 544 return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features); 545 } 546 547 static int vhost_user_set_owner(struct vhost_dev *dev) 548 { 549 VhostUserMsg msg = { 550 .request = VHOST_USER_SET_OWNER, 551 .flags = VHOST_USER_VERSION, 552 }; 553 554 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 555 return -1; 556 } 557 558 return 0; 559 } 560 561 static int vhost_user_reset_device(struct vhost_dev *dev) 562 { 563 VhostUserMsg msg = { 564 .request = VHOST_USER_RESET_OWNER, 565 .flags = VHOST_USER_VERSION, 566 }; 567 568 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 569 return -1; 570 } 571 572 return 0; 573 } 574 575 static int vhost_user_init(struct vhost_dev *dev, void *opaque) 576 { 577 uint64_t features; 578 int err; 579 580 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 581 582 dev->opaque = opaque; 583 584 err = vhost_user_get_features(dev, &features); 585 if (err < 0) { 586 return err; 587 } 588 589 if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) { 590 dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; 591 592 err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES, 593 &features); 594 if (err < 0) { 595 return err; 596 } 597 598 dev->protocol_features = features & VHOST_USER_PROTOCOL_FEATURE_MASK; 599 err = vhost_user_set_protocol_features(dev, dev->protocol_features); 600 if (err < 0) { 601 return err; 602 } 603 604 /* query the max queues we support if backend supports Multiple Queue */ 605 if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) { 606 err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM, 607 &dev->max_queues); 608 if (err < 0) { 609 return err; 610 } 611 } 612 } 613 614 if (dev->migration_blocker == NULL && 615 !virtio_has_feature(dev->protocol_features, 616 VHOST_USER_PROTOCOL_F_LOG_SHMFD)) { 617 error_setg(&dev->migration_blocker, 618 "Migration disabled: vhost-user backend lacks " 619 "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature."); 620 } 621 622 return 0; 623 } 624 625 static int vhost_user_cleanup(struct vhost_dev *dev) 626 { 627 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 628 629 dev->opaque = 0; 630 631 return 0; 632 } 633 634 static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx) 635 { 636 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); 637 638 return idx; 639 } 640 641 static int vhost_user_memslots_limit(struct vhost_dev *dev) 642 { 643 return VHOST_MEMORY_MAX_NREGIONS; 644 } 645 646 static bool vhost_user_requires_shm_log(struct vhost_dev *dev) 647 { 648 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 649 650 return virtio_has_feature(dev->protocol_features, 651 VHOST_USER_PROTOCOL_F_LOG_SHMFD); 652 } 653 654 static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) 655 { 656 VhostUserMsg msg = { 0 }; 657 658 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 659 660 /* If guest supports GUEST_ANNOUNCE do nothing */ 661 if (virtio_has_feature(dev->acked_features, VIRTIO_NET_F_GUEST_ANNOUNCE)) { 662 return 0; 663 } 664 665 /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */ 666 if (virtio_has_feature(dev->protocol_features, 667 VHOST_USER_PROTOCOL_F_RARP)) { 668 msg.request = VHOST_USER_SEND_RARP; 669 msg.flags = VHOST_USER_VERSION; 670 memcpy((char *)&msg.payload.u64, mac_addr, 6); 671 msg.size = sizeof(msg.payload.u64); 672 673 return vhost_user_write(dev, &msg, NULL, 0); 674 } 675 return -1; 676 } 677 678 static bool vhost_user_can_merge(struct vhost_dev *dev, 679 uint64_t start1, uint64_t size1, 680 uint64_t start2, uint64_t size2) 681 { 682 ram_addr_t offset; 683 int mfd, rfd; 684 MemoryRegion *mr; 685 686 mr = memory_region_from_host((void *)(uintptr_t)start1, &offset); 687 mfd = memory_region_get_fd(mr); 688 689 mr = memory_region_from_host((void *)(uintptr_t)start2, &offset); 690 rfd = memory_region_get_fd(mr); 691 692 return mfd == rfd; 693 } 694 695 static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) 696 { 697 VhostUserMsg msg; 698 bool reply_supported = virtio_has_feature(dev->protocol_features, 699 VHOST_USER_PROTOCOL_F_REPLY_ACK); 700 701 if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) { 702 return 0; 703 } 704 705 msg.request = VHOST_USER_NET_SET_MTU; 706 msg.payload.u64 = mtu; 707 msg.size = sizeof(msg.payload.u64); 708 msg.flags = VHOST_USER_VERSION; 709 if (reply_supported) { 710 msg.flags |= VHOST_USER_NEED_REPLY_MASK; 711 } 712 713 if (vhost_user_write(dev, &msg, NULL, 0) < 0) { 714 return -1; 715 } 716 717 /* If reply_ack supported, slave has to ack specified MTU is valid */ 718 if (reply_supported) { 719 return process_message_reply(dev, &msg); 720 } 721 722 return 0; 723 } 724 725 const VhostOps user_ops = { 726 .backend_type = VHOST_BACKEND_TYPE_USER, 727 .vhost_backend_init = vhost_user_init, 728 .vhost_backend_cleanup = vhost_user_cleanup, 729 .vhost_backend_memslots_limit = vhost_user_memslots_limit, 730 .vhost_set_log_base = vhost_user_set_log_base, 731 .vhost_set_mem_table = vhost_user_set_mem_table, 732 .vhost_set_vring_addr = vhost_user_set_vring_addr, 733 .vhost_set_vring_endian = vhost_user_set_vring_endian, 734 .vhost_set_vring_num = vhost_user_set_vring_num, 735 .vhost_set_vring_base = vhost_user_set_vring_base, 736 .vhost_get_vring_base = vhost_user_get_vring_base, 737 .vhost_set_vring_kick = vhost_user_set_vring_kick, 738 .vhost_set_vring_call = vhost_user_set_vring_call, 739 .vhost_set_features = vhost_user_set_features, 740 .vhost_get_features = vhost_user_get_features, 741 .vhost_set_owner = vhost_user_set_owner, 742 .vhost_reset_device = vhost_user_reset_device, 743 .vhost_get_vq_index = vhost_user_get_vq_index, 744 .vhost_set_vring_enable = vhost_user_set_vring_enable, 745 .vhost_requires_shm_log = vhost_user_requires_shm_log, 746 .vhost_migration_done = vhost_user_migration_done, 747 .vhost_backend_can_merge = vhost_user_can_merge, 748 .vhost_net_set_mtu = vhost_user_net_set_mtu, 749 }; 750