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