4 * Copyright (c) 2013 Virtual Open Systems Sarl.
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.
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 "chardev/char-fe.h"
17 #include "sysemu/kvm.h"
18 #include "qemu/error-report.h"
19 #include "qemu/sockets.h"
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
24 #include <linux/vhost.h>
26 #define VHOST_MEMORY_MAX_NREGIONS 8
27 #define VHOST_USER_F_PROTOCOL_FEATURES 30
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 VHOST_USER_PROTOCOL_F_SLAVE_REQ
= 5,
37 VHOST_USER_PROTOCOL_F_MAX
40 #define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
42 typedef enum VhostUserRequest
{
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_SET_SLAVE_REQ_FD
= 21,
65 VHOST_USER_IOTLB_MSG
= 22,
69 typedef enum VhostUserSlaveRequest
{
70 VHOST_USER_SLAVE_NONE
= 0,
71 VHOST_USER_SLAVE_IOTLB_MSG
= 1,
73 } VhostUserSlaveRequest
;
75 typedef struct VhostUserMemoryRegion
{
76 uint64_t guest_phys_addr
;
78 uint64_t userspace_addr
;
80 } VhostUserMemoryRegion
;
82 typedef struct VhostUserMemory
{
85 VhostUserMemoryRegion regions
[VHOST_MEMORY_MAX_NREGIONS
];
88 typedef struct VhostUserLog
{
93 typedef struct VhostUserMsg
{
94 VhostUserRequest request
;
96 #define VHOST_USER_VERSION_MASK (0x3)
97 #define VHOST_USER_REPLY_MASK (0x1<<2)
98 #define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
100 uint32_t size
; /* the following payload size */
102 #define VHOST_USER_VRING_IDX_MASK (0xff)
103 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
105 struct vhost_vring_state state
;
106 struct vhost_vring_addr addr
;
107 VhostUserMemory memory
;
109 struct vhost_iotlb_msg iotlb
;
111 } QEMU_PACKED VhostUserMsg
;
113 static VhostUserMsg m
__attribute__ ((unused
));
114 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
118 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
120 /* The version of the protocol we support */
121 #define VHOST_USER_VERSION (0x1)
128 static bool ioeventfd_enabled(void)
130 return kvm_enabled() && kvm_eventfds_enabled();
133 static int vhost_user_read(struct vhost_dev
*dev
, VhostUserMsg
*msg
)
135 struct vhost_user
*u
= dev
->opaque
;
136 CharBackend
*chr
= u
->chr
;
137 uint8_t *p
= (uint8_t *) msg
;
138 int r
, size
= VHOST_USER_HDR_SIZE
;
140 r
= qemu_chr_fe_read_all(chr
, p
, size
);
142 error_report("Failed to read msg header. Read %d instead of %d."
143 " Original request %d.", r
, size
, msg
->request
);
147 /* validate received flags */
148 if (msg
->flags
!= (VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
)) {
149 error_report("Failed to read msg header."
150 " Flags 0x%x instead of 0x%x.", msg
->flags
,
151 VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
);
155 /* validate message size is sane */
156 if (msg
->size
> VHOST_USER_PAYLOAD_SIZE
) {
157 error_report("Failed to read msg header."
158 " Size %d exceeds the maximum %zu.", msg
->size
,
159 VHOST_USER_PAYLOAD_SIZE
);
164 p
+= VHOST_USER_HDR_SIZE
;
166 r
= qemu_chr_fe_read_all(chr
, p
, size
);
168 error_report("Failed to read msg payload."
169 " Read %d instead of %d.", r
, msg
->size
);
180 static int process_message_reply(struct vhost_dev
*dev
,
181 const VhostUserMsg
*msg
)
183 VhostUserMsg msg_reply
;
185 if ((msg
->flags
& VHOST_USER_NEED_REPLY_MASK
) == 0) {
189 if (vhost_user_read(dev
, &msg_reply
) < 0) {
193 if (msg_reply
.request
!= msg
->request
) {
194 error_report("Received unexpected msg type."
195 "Expected %d received %d",
196 msg
->request
, msg_reply
.request
);
200 return msg_reply
.payload
.u64
? -1 : 0;
203 static bool vhost_user_one_time_request(VhostUserRequest request
)
206 case VHOST_USER_SET_OWNER
:
207 case VHOST_USER_RESET_OWNER
:
208 case VHOST_USER_SET_MEM_TABLE
:
209 case VHOST_USER_GET_QUEUE_NUM
:
210 case VHOST_USER_NET_SET_MTU
:
217 /* most non-init callers ignore the error */
218 static int vhost_user_write(struct vhost_dev
*dev
, VhostUserMsg
*msg
,
219 int *fds
, int fd_num
)
221 struct vhost_user
*u
= dev
->opaque
;
222 CharBackend
*chr
= u
->chr
;
223 int ret
, size
= VHOST_USER_HDR_SIZE
+ msg
->size
;
226 * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
227 * we just need send it once in the first time. For later such
228 * request, we just ignore it.
230 if (vhost_user_one_time_request(msg
->request
) && dev
->vq_index
!= 0) {
231 msg
->flags
&= ~VHOST_USER_NEED_REPLY_MASK
;
235 if (qemu_chr_fe_set_msgfds(chr
, fds
, fd_num
) < 0) {
236 error_report("Failed to set msg fds.");
240 ret
= qemu_chr_fe_write_all(chr
, (const uint8_t *) msg
, size
);
242 error_report("Failed to write msg."
243 " Wrote %d instead of %d.", ret
, size
);
250 static int vhost_user_set_log_base(struct vhost_dev
*dev
, uint64_t base
,
251 struct vhost_log
*log
)
253 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
255 bool shmfd
= virtio_has_feature(dev
->protocol_features
,
256 VHOST_USER_PROTOCOL_F_LOG_SHMFD
);
258 .request
= VHOST_USER_SET_LOG_BASE
,
259 .flags
= VHOST_USER_VERSION
,
260 .payload
.log
.mmap_size
= log
->size
* sizeof(*(log
->log
)),
261 .payload
.log
.mmap_offset
= 0,
262 .size
= sizeof(msg
.payload
.log
),
265 if (shmfd
&& log
->fd
!= -1) {
266 fds
[fd_num
++] = log
->fd
;
269 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
275 if (vhost_user_read(dev
, &msg
) < 0) {
279 if (msg
.request
!= VHOST_USER_SET_LOG_BASE
) {
280 error_report("Received unexpected msg type. "
281 "Expected %d received %d",
282 VHOST_USER_SET_LOG_BASE
, msg
.request
);
290 static int vhost_user_set_mem_table(struct vhost_dev
*dev
,
291 struct vhost_memory
*mem
)
293 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
296 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
297 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
300 .request
= VHOST_USER_SET_MEM_TABLE
,
301 .flags
= VHOST_USER_VERSION
,
304 if (reply_supported
) {
305 msg
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
308 for (i
= 0; i
< dev
->mem
->nregions
; ++i
) {
309 struct vhost_memory_region
*reg
= dev
->mem
->regions
+ i
;
313 assert((uintptr_t)reg
->userspace_addr
== reg
->userspace_addr
);
314 mr
= memory_region_from_host((void *)(uintptr_t)reg
->userspace_addr
,
316 fd
= memory_region_get_fd(mr
);
318 msg
.payload
.memory
.regions
[fd_num
].userspace_addr
= reg
->userspace_addr
;
319 msg
.payload
.memory
.regions
[fd_num
].memory_size
= reg
->memory_size
;
320 msg
.payload
.memory
.regions
[fd_num
].guest_phys_addr
= reg
->guest_phys_addr
;
321 msg
.payload
.memory
.regions
[fd_num
].mmap_offset
= offset
;
322 assert(fd_num
< VHOST_MEMORY_MAX_NREGIONS
);
327 msg
.payload
.memory
.nregions
= fd_num
;
330 error_report("Failed initializing vhost-user memory map, "
331 "consider using -object memory-backend-file share=on");
335 msg
.size
= sizeof(msg
.payload
.memory
.nregions
);
336 msg
.size
+= sizeof(msg
.payload
.memory
.padding
);
337 msg
.size
+= fd_num
* sizeof(VhostUserMemoryRegion
);
339 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
343 if (reply_supported
) {
344 return process_message_reply(dev
, &msg
);
350 static int vhost_user_set_vring_addr(struct vhost_dev
*dev
,
351 struct vhost_vring_addr
*addr
)
354 .request
= VHOST_USER_SET_VRING_ADDR
,
355 .flags
= VHOST_USER_VERSION
,
356 .payload
.addr
= *addr
,
357 .size
= sizeof(msg
.payload
.addr
),
360 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
367 static int vhost_user_set_vring_endian(struct vhost_dev
*dev
,
368 struct vhost_vring_state
*ring
)
370 error_report("vhost-user trying to send unhandled ioctl");
374 static int vhost_set_vring(struct vhost_dev
*dev
,
375 unsigned long int request
,
376 struct vhost_vring_state
*ring
)
380 .flags
= VHOST_USER_VERSION
,
381 .payload
.state
= *ring
,
382 .size
= sizeof(msg
.payload
.state
),
385 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
392 static int vhost_user_set_vring_num(struct vhost_dev
*dev
,
393 struct vhost_vring_state
*ring
)
395 return vhost_set_vring(dev
, VHOST_USER_SET_VRING_NUM
, ring
);
398 static int vhost_user_set_vring_base(struct vhost_dev
*dev
,
399 struct vhost_vring_state
*ring
)
401 return vhost_set_vring(dev
, VHOST_USER_SET_VRING_BASE
, ring
);
404 static int vhost_user_set_vring_enable(struct vhost_dev
*dev
, int enable
)
408 if (!virtio_has_feature(dev
->features
, VHOST_USER_F_PROTOCOL_FEATURES
)) {
412 for (i
= 0; i
< dev
->nvqs
; ++i
) {
413 struct vhost_vring_state state
= {
414 .index
= dev
->vq_index
+ i
,
418 vhost_set_vring(dev
, VHOST_USER_SET_VRING_ENABLE
, &state
);
424 static int vhost_user_get_vring_base(struct vhost_dev
*dev
,
425 struct vhost_vring_state
*ring
)
428 .request
= VHOST_USER_GET_VRING_BASE
,
429 .flags
= VHOST_USER_VERSION
,
430 .payload
.state
= *ring
,
431 .size
= sizeof(msg
.payload
.state
),
434 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
438 if (vhost_user_read(dev
, &msg
) < 0) {
442 if (msg
.request
!= VHOST_USER_GET_VRING_BASE
) {
443 error_report("Received unexpected msg type. Expected %d received %d",
444 VHOST_USER_GET_VRING_BASE
, msg
.request
);
448 if (msg
.size
!= sizeof(msg
.payload
.state
)) {
449 error_report("Received bad msg size.");
453 *ring
= msg
.payload
.state
;
458 static int vhost_set_vring_file(struct vhost_dev
*dev
,
459 VhostUserRequest request
,
460 struct vhost_vring_file
*file
)
462 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
466 .flags
= VHOST_USER_VERSION
,
467 .payload
.u64
= file
->index
& VHOST_USER_VRING_IDX_MASK
,
468 .size
= sizeof(msg
.payload
.u64
),
471 if (ioeventfd_enabled() && file
->fd
> 0) {
472 fds
[fd_num
++] = file
->fd
;
474 msg
.payload
.u64
|= VHOST_USER_VRING_NOFD_MASK
;
477 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
484 static int vhost_user_set_vring_kick(struct vhost_dev
*dev
,
485 struct vhost_vring_file
*file
)
487 return vhost_set_vring_file(dev
, VHOST_USER_SET_VRING_KICK
, file
);
490 static int vhost_user_set_vring_call(struct vhost_dev
*dev
,
491 struct vhost_vring_file
*file
)
493 return vhost_set_vring_file(dev
, VHOST_USER_SET_VRING_CALL
, file
);
496 static int vhost_user_set_u64(struct vhost_dev
*dev
, int request
, uint64_t u64
)
500 .flags
= VHOST_USER_VERSION
,
502 .size
= sizeof(msg
.payload
.u64
),
505 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
512 static int vhost_user_set_features(struct vhost_dev
*dev
,
515 return vhost_user_set_u64(dev
, VHOST_USER_SET_FEATURES
, features
);
518 static int vhost_user_set_protocol_features(struct vhost_dev
*dev
,
521 return vhost_user_set_u64(dev
, VHOST_USER_SET_PROTOCOL_FEATURES
, features
);
524 static int vhost_user_get_u64(struct vhost_dev
*dev
, int request
, uint64_t *u64
)
528 .flags
= VHOST_USER_VERSION
,
531 if (vhost_user_one_time_request(request
) && dev
->vq_index
!= 0) {
535 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
539 if (vhost_user_read(dev
, &msg
) < 0) {
543 if (msg
.request
!= request
) {
544 error_report("Received unexpected msg type. Expected %d received %d",
545 request
, msg
.request
);
549 if (msg
.size
!= sizeof(msg
.payload
.u64
)) {
550 error_report("Received bad msg size.");
554 *u64
= msg
.payload
.u64
;
559 static int vhost_user_get_features(struct vhost_dev
*dev
, uint64_t *features
)
561 return vhost_user_get_u64(dev
, VHOST_USER_GET_FEATURES
, features
);
564 static int vhost_user_set_owner(struct vhost_dev
*dev
)
567 .request
= VHOST_USER_SET_OWNER
,
568 .flags
= VHOST_USER_VERSION
,
571 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
578 static int vhost_user_reset_device(struct vhost_dev
*dev
)
581 .request
= VHOST_USER_RESET_OWNER
,
582 .flags
= VHOST_USER_VERSION
,
585 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
592 static void slave_read(void *opaque
)
594 struct vhost_dev
*dev
= opaque
;
595 struct vhost_user
*u
= dev
->opaque
;
596 VhostUserMsg msg
= { 0, };
600 size
= read(u
->slave_fd
, &msg
, VHOST_USER_HDR_SIZE
);
601 if (size
!= VHOST_USER_HDR_SIZE
) {
602 error_report("Failed to read from slave.");
606 if (msg
.size
> VHOST_USER_PAYLOAD_SIZE
) {
607 error_report("Failed to read msg header."
608 " Size %d exceeds the maximum %zu.", msg
.size
,
609 VHOST_USER_PAYLOAD_SIZE
);
614 size
= read(u
->slave_fd
, &msg
.payload
, msg
.size
);
615 if (size
!= msg
.size
) {
616 error_report("Failed to read payload from slave.");
620 switch (msg
.request
) {
621 case VHOST_USER_SLAVE_IOTLB_MSG
:
622 ret
= vhost_backend_handle_iotlb_msg(dev
, &msg
.payload
.iotlb
);
625 error_report("Received unexpected msg type.");
630 * REPLY_ACK feature handling. Other reply types has to be managed
631 * directly in their request handlers.
633 if (msg
.flags
& VHOST_USER_NEED_REPLY_MASK
) {
634 msg
.flags
&= ~VHOST_USER_NEED_REPLY_MASK
;
635 msg
.flags
|= VHOST_USER_REPLY_MASK
;
637 msg
.payload
.u64
= !!ret
;
638 msg
.size
= sizeof(msg
.payload
.u64
);
640 size
= write(u
->slave_fd
, &msg
, VHOST_USER_HDR_SIZE
+ msg
.size
);
641 if (size
!= VHOST_USER_HDR_SIZE
+ msg
.size
) {
642 error_report("Failed to send msg reply to slave.");
650 qemu_set_fd_handler(u
->slave_fd
, NULL
, NULL
, NULL
);
656 static int vhost_setup_slave_channel(struct vhost_dev
*dev
)
659 .request
= VHOST_USER_SET_SLAVE_REQ_FD
,
660 .flags
= VHOST_USER_VERSION
,
662 struct vhost_user
*u
= dev
->opaque
;
664 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
665 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
667 if (!virtio_has_feature(dev
->protocol_features
,
668 VHOST_USER_PROTOCOL_F_SLAVE_REQ
)) {
672 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, sv
) == -1) {
673 error_report("socketpair() failed");
678 qemu_set_fd_handler(u
->slave_fd
, slave_read
, NULL
, dev
);
680 if (reply_supported
) {
681 msg
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
684 ret
= vhost_user_write(dev
, &msg
, &sv
[1], 1);
689 if (reply_supported
) {
690 ret
= process_message_reply(dev
, &msg
);
696 qemu_set_fd_handler(u
->slave_fd
, NULL
, NULL
, NULL
);
704 static int vhost_user_init(struct vhost_dev
*dev
, void *opaque
)
706 uint64_t features
, protocol_features
;
707 struct vhost_user
*u
;
710 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
712 u
= g_new0(struct vhost_user
, 1);
717 err
= vhost_user_get_features(dev
, &features
);
722 if (virtio_has_feature(features
, VHOST_USER_F_PROTOCOL_FEATURES
)) {
723 dev
->backend_features
|= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES
;
725 err
= vhost_user_get_u64(dev
, VHOST_USER_GET_PROTOCOL_FEATURES
,
731 dev
->protocol_features
=
732 protocol_features
& VHOST_USER_PROTOCOL_FEATURE_MASK
;
733 err
= vhost_user_set_protocol_features(dev
, dev
->protocol_features
);
738 /* query the max queues we support if backend supports Multiple Queue */
739 if (dev
->protocol_features
& (1ULL << VHOST_USER_PROTOCOL_F_MQ
)) {
740 err
= vhost_user_get_u64(dev
, VHOST_USER_GET_QUEUE_NUM
,
747 if (virtio_has_feature(features
, VIRTIO_F_IOMMU_PLATFORM
) &&
748 !(virtio_has_feature(dev
->protocol_features
,
749 VHOST_USER_PROTOCOL_F_SLAVE_REQ
) &&
750 virtio_has_feature(dev
->protocol_features
,
751 VHOST_USER_PROTOCOL_F_REPLY_ACK
))) {
752 error_report("IOMMU support requires reply-ack and "
753 "slave-req protocol features.");
758 if (dev
->migration_blocker
== NULL
&&
759 !virtio_has_feature(dev
->protocol_features
,
760 VHOST_USER_PROTOCOL_F_LOG_SHMFD
)) {
761 error_setg(&dev
->migration_blocker
,
762 "Migration disabled: vhost-user backend lacks "
763 "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
766 err
= vhost_setup_slave_channel(dev
);
774 static int vhost_user_cleanup(struct vhost_dev
*dev
)
776 struct vhost_user
*u
;
778 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
781 if (u
->slave_fd
>= 0) {
791 static int vhost_user_get_vq_index(struct vhost_dev
*dev
, int idx
)
793 assert(idx
>= dev
->vq_index
&& idx
< dev
->vq_index
+ dev
->nvqs
);
798 static int vhost_user_memslots_limit(struct vhost_dev
*dev
)
800 return VHOST_MEMORY_MAX_NREGIONS
;
803 static bool vhost_user_requires_shm_log(struct vhost_dev
*dev
)
805 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
807 return virtio_has_feature(dev
->protocol_features
,
808 VHOST_USER_PROTOCOL_F_LOG_SHMFD
);
811 static int vhost_user_migration_done(struct vhost_dev
*dev
, char* mac_addr
)
813 VhostUserMsg msg
= { 0 };
815 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
817 /* If guest supports GUEST_ANNOUNCE do nothing */
818 if (virtio_has_feature(dev
->acked_features
, VIRTIO_NET_F_GUEST_ANNOUNCE
)) {
822 /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */
823 if (virtio_has_feature(dev
->protocol_features
,
824 VHOST_USER_PROTOCOL_F_RARP
)) {
825 msg
.request
= VHOST_USER_SEND_RARP
;
826 msg
.flags
= VHOST_USER_VERSION
;
827 memcpy((char *)&msg
.payload
.u64
, mac_addr
, 6);
828 msg
.size
= sizeof(msg
.payload
.u64
);
830 return vhost_user_write(dev
, &msg
, NULL
, 0);
835 static bool vhost_user_can_merge(struct vhost_dev
*dev
,
836 uint64_t start1
, uint64_t size1
,
837 uint64_t start2
, uint64_t size2
)
843 mr
= memory_region_from_host((void *)(uintptr_t)start1
, &offset
);
844 mfd
= memory_region_get_fd(mr
);
846 mr
= memory_region_from_host((void *)(uintptr_t)start2
, &offset
);
847 rfd
= memory_region_get_fd(mr
);
852 static int vhost_user_net_set_mtu(struct vhost_dev
*dev
, uint16_t mtu
)
855 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
856 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
858 if (!(dev
->protocol_features
& (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU
))) {
862 msg
.request
= VHOST_USER_NET_SET_MTU
;
863 msg
.payload
.u64
= mtu
;
864 msg
.size
= sizeof(msg
.payload
.u64
);
865 msg
.flags
= VHOST_USER_VERSION
;
866 if (reply_supported
) {
867 msg
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
870 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
874 /* If reply_ack supported, slave has to ack specified MTU is valid */
875 if (reply_supported
) {
876 return process_message_reply(dev
, &msg
);
882 static int vhost_user_send_device_iotlb_msg(struct vhost_dev
*dev
,
883 struct vhost_iotlb_msg
*imsg
)
886 .request
= VHOST_USER_IOTLB_MSG
,
887 .size
= sizeof(msg
.payload
.iotlb
),
888 .flags
= VHOST_USER_VERSION
| VHOST_USER_NEED_REPLY_MASK
,
889 .payload
.iotlb
= *imsg
,
892 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
896 return process_message_reply(dev
, &msg
);
900 static void vhost_user_set_iotlb_callback(struct vhost_dev
*dev
, int enabled
)
902 /* No-op as the receive channel is not dedicated to IOTLB messages. */
905 const VhostOps user_ops
= {
906 .backend_type
= VHOST_BACKEND_TYPE_USER
,
907 .vhost_backend_init
= vhost_user_init
,
908 .vhost_backend_cleanup
= vhost_user_cleanup
,
909 .vhost_backend_memslots_limit
= vhost_user_memslots_limit
,
910 .vhost_set_log_base
= vhost_user_set_log_base
,
911 .vhost_set_mem_table
= vhost_user_set_mem_table
,
912 .vhost_set_vring_addr
= vhost_user_set_vring_addr
,
913 .vhost_set_vring_endian
= vhost_user_set_vring_endian
,
914 .vhost_set_vring_num
= vhost_user_set_vring_num
,
915 .vhost_set_vring_base
= vhost_user_set_vring_base
,
916 .vhost_get_vring_base
= vhost_user_get_vring_base
,
917 .vhost_set_vring_kick
= vhost_user_set_vring_kick
,
918 .vhost_set_vring_call
= vhost_user_set_vring_call
,
919 .vhost_set_features
= vhost_user_set_features
,
920 .vhost_get_features
= vhost_user_get_features
,
921 .vhost_set_owner
= vhost_user_set_owner
,
922 .vhost_reset_device
= vhost_user_reset_device
,
923 .vhost_get_vq_index
= vhost_user_get_vq_index
,
924 .vhost_set_vring_enable
= vhost_user_set_vring_enable
,
925 .vhost_requires_shm_log
= vhost_user_requires_shm_log
,
926 .vhost_migration_done
= vhost_user_migration_done
,
927 .vhost_backend_can_merge
= vhost_user_can_merge
,
928 .vhost_net_set_mtu
= vhost_user_net_set_mtu
,
929 .vhost_set_iotlb_callback
= vhost_user_set_iotlb_callback
,
930 .vhost_send_device_iotlb_msg
= vhost_user_send_device_iotlb_msg
,