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"
20 #include "sysemu/cryptodev.h"
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
25 #include <linux/vhost.h>
27 #define VHOST_MEMORY_MAX_NREGIONS 8
28 #define VHOST_USER_F_PROTOCOL_FEATURES 30
31 * Maximum size of virtio device config space
33 #define VHOST_USER_MAX_CONFIG_SIZE 256
35 enum VhostUserProtocolFeature
{
36 VHOST_USER_PROTOCOL_F_MQ
= 0,
37 VHOST_USER_PROTOCOL_F_LOG_SHMFD
= 1,
38 VHOST_USER_PROTOCOL_F_RARP
= 2,
39 VHOST_USER_PROTOCOL_F_REPLY_ACK
= 3,
40 VHOST_USER_PROTOCOL_F_NET_MTU
= 4,
41 VHOST_USER_PROTOCOL_F_SLAVE_REQ
= 5,
42 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
= 6,
43 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION
= 7,
45 VHOST_USER_PROTOCOL_F_MAX
48 #define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
50 typedef enum VhostUserRequest
{
52 VHOST_USER_GET_FEATURES
= 1,
53 VHOST_USER_SET_FEATURES
= 2,
54 VHOST_USER_SET_OWNER
= 3,
55 VHOST_USER_RESET_OWNER
= 4,
56 VHOST_USER_SET_MEM_TABLE
= 5,
57 VHOST_USER_SET_LOG_BASE
= 6,
58 VHOST_USER_SET_LOG_FD
= 7,
59 VHOST_USER_SET_VRING_NUM
= 8,
60 VHOST_USER_SET_VRING_ADDR
= 9,
61 VHOST_USER_SET_VRING_BASE
= 10,
62 VHOST_USER_GET_VRING_BASE
= 11,
63 VHOST_USER_SET_VRING_KICK
= 12,
64 VHOST_USER_SET_VRING_CALL
= 13,
65 VHOST_USER_SET_VRING_ERR
= 14,
66 VHOST_USER_GET_PROTOCOL_FEATURES
= 15,
67 VHOST_USER_SET_PROTOCOL_FEATURES
= 16,
68 VHOST_USER_GET_QUEUE_NUM
= 17,
69 VHOST_USER_SET_VRING_ENABLE
= 18,
70 VHOST_USER_SEND_RARP
= 19,
71 VHOST_USER_NET_SET_MTU
= 20,
72 VHOST_USER_SET_SLAVE_REQ_FD
= 21,
73 VHOST_USER_IOTLB_MSG
= 22,
74 VHOST_USER_SET_VRING_ENDIAN
= 23,
75 VHOST_USER_GET_CONFIG
= 24,
76 VHOST_USER_SET_CONFIG
= 25,
77 VHOST_USER_CREATE_CRYPTO_SESSION
= 26,
78 VHOST_USER_CLOSE_CRYPTO_SESSION
= 27,
82 typedef enum VhostUserSlaveRequest
{
83 VHOST_USER_SLAVE_NONE
= 0,
84 VHOST_USER_SLAVE_IOTLB_MSG
= 1,
85 VHOST_USER_SLAVE_CONFIG_CHANGE_MSG
= 2,
87 } VhostUserSlaveRequest
;
89 typedef struct VhostUserMemoryRegion
{
90 uint64_t guest_phys_addr
;
92 uint64_t userspace_addr
;
94 } VhostUserMemoryRegion
;
96 typedef struct VhostUserMemory
{
99 VhostUserMemoryRegion regions
[VHOST_MEMORY_MAX_NREGIONS
];
102 typedef struct VhostUserLog
{
104 uint64_t mmap_offset
;
107 typedef struct VhostUserConfig
{
111 uint8_t region
[VHOST_USER_MAX_CONFIG_SIZE
];
114 #define VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN 512
115 #define VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN 64
117 typedef struct VhostUserCryptoSession
{
118 /* session id for success, -1 on errors */
120 CryptoDevBackendSymSessionInfo session_setup_data
;
121 uint8_t key
[VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN
];
122 uint8_t auth_key
[VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN
];
123 } VhostUserCryptoSession
;
125 static VhostUserConfig c
__attribute__ ((unused
));
126 #define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \
131 VhostUserRequest request
;
133 #define VHOST_USER_VERSION_MASK (0x3)
134 #define VHOST_USER_REPLY_MASK (0x1<<2)
135 #define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
137 uint32_t size
; /* the following payload size */
138 } QEMU_PACKED VhostUserHeader
;
141 #define VHOST_USER_VRING_IDX_MASK (0xff)
142 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
144 struct vhost_vring_state state
;
145 struct vhost_vring_addr addr
;
146 VhostUserMemory memory
;
148 struct vhost_iotlb_msg iotlb
;
149 VhostUserConfig config
;
150 VhostUserCryptoSession session
;
153 typedef struct VhostUserMsg
{
155 VhostUserPayload payload
;
156 } QEMU_PACKED VhostUserMsg
;
158 static VhostUserMsg m
__attribute__ ((unused
));
159 #define VHOST_USER_HDR_SIZE (sizeof(VhostUserHeader))
161 #define VHOST_USER_PAYLOAD_SIZE (sizeof(VhostUserPayload))
163 /* The version of the protocol we support */
164 #define VHOST_USER_VERSION (0x1)
171 static bool ioeventfd_enabled(void)
173 return kvm_enabled() && kvm_eventfds_enabled();
176 static int vhost_user_read(struct vhost_dev
*dev
, VhostUserMsg
*msg
)
178 struct vhost_user
*u
= dev
->opaque
;
179 CharBackend
*chr
= u
->chr
;
180 uint8_t *p
= (uint8_t *) msg
;
181 int r
, size
= VHOST_USER_HDR_SIZE
;
183 r
= qemu_chr_fe_read_all(chr
, p
, size
);
185 error_report("Failed to read msg header. Read %d instead of %d."
186 " Original request %d.", r
, size
, msg
->hdr
.request
);
190 /* validate received flags */
191 if (msg
->hdr
.flags
!= (VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
)) {
192 error_report("Failed to read msg header."
193 " Flags 0x%x instead of 0x%x.", msg
->hdr
.flags
,
194 VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
);
198 /* validate message size is sane */
199 if (msg
->hdr
.size
> VHOST_USER_PAYLOAD_SIZE
) {
200 error_report("Failed to read msg header."
201 " Size %d exceeds the maximum %zu.", msg
->hdr
.size
,
202 VHOST_USER_PAYLOAD_SIZE
);
207 p
+= VHOST_USER_HDR_SIZE
;
208 size
= msg
->hdr
.size
;
209 r
= qemu_chr_fe_read_all(chr
, p
, size
);
211 error_report("Failed to read msg payload."
212 " Read %d instead of %d.", r
, msg
->hdr
.size
);
223 static int process_message_reply(struct vhost_dev
*dev
,
224 const VhostUserMsg
*msg
)
226 VhostUserMsg msg_reply
;
228 if ((msg
->hdr
.flags
& VHOST_USER_NEED_REPLY_MASK
) == 0) {
232 if (vhost_user_read(dev
, &msg_reply
) < 0) {
236 if (msg_reply
.hdr
.request
!= msg
->hdr
.request
) {
237 error_report("Received unexpected msg type."
238 "Expected %d received %d",
239 msg
->hdr
.request
, msg_reply
.hdr
.request
);
243 return msg_reply
.payload
.u64
? -1 : 0;
246 static bool vhost_user_one_time_request(VhostUserRequest request
)
249 case VHOST_USER_SET_OWNER
:
250 case VHOST_USER_RESET_OWNER
:
251 case VHOST_USER_SET_MEM_TABLE
:
252 case VHOST_USER_GET_QUEUE_NUM
:
253 case VHOST_USER_NET_SET_MTU
:
260 /* most non-init callers ignore the error */
261 static int vhost_user_write(struct vhost_dev
*dev
, VhostUserMsg
*msg
,
262 int *fds
, int fd_num
)
264 struct vhost_user
*u
= dev
->opaque
;
265 CharBackend
*chr
= u
->chr
;
266 int ret
, size
= VHOST_USER_HDR_SIZE
+ msg
->hdr
.size
;
269 * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
270 * we just need send it once in the first time. For later such
271 * request, we just ignore it.
273 if (vhost_user_one_time_request(msg
->hdr
.request
) && dev
->vq_index
!= 0) {
274 msg
->hdr
.flags
&= ~VHOST_USER_NEED_REPLY_MASK
;
278 if (qemu_chr_fe_set_msgfds(chr
, fds
, fd_num
) < 0) {
279 error_report("Failed to set msg fds.");
283 ret
= qemu_chr_fe_write_all(chr
, (const uint8_t *) msg
, size
);
285 error_report("Failed to write msg."
286 " Wrote %d instead of %d.", ret
, size
);
293 static int vhost_user_set_log_base(struct vhost_dev
*dev
, uint64_t base
,
294 struct vhost_log
*log
)
296 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
298 bool shmfd
= virtio_has_feature(dev
->protocol_features
,
299 VHOST_USER_PROTOCOL_F_LOG_SHMFD
);
301 .hdr
.request
= VHOST_USER_SET_LOG_BASE
,
302 .hdr
.flags
= VHOST_USER_VERSION
,
303 .payload
.log
.mmap_size
= log
->size
* sizeof(*(log
->log
)),
304 .payload
.log
.mmap_offset
= 0,
305 .hdr
.size
= sizeof(msg
.payload
.log
),
308 if (shmfd
&& log
->fd
!= -1) {
309 fds
[fd_num
++] = log
->fd
;
312 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
318 if (vhost_user_read(dev
, &msg
) < 0) {
322 if (msg
.hdr
.request
!= VHOST_USER_SET_LOG_BASE
) {
323 error_report("Received unexpected msg type. "
324 "Expected %d received %d",
325 VHOST_USER_SET_LOG_BASE
, msg
.hdr
.request
);
333 static int vhost_user_set_mem_table(struct vhost_dev
*dev
,
334 struct vhost_memory
*mem
)
336 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
339 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
340 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
343 .hdr
.request
= VHOST_USER_SET_MEM_TABLE
,
344 .hdr
.flags
= VHOST_USER_VERSION
,
347 if (reply_supported
) {
348 msg
.hdr
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
351 for (i
= 0; i
< dev
->mem
->nregions
; ++i
) {
352 struct vhost_memory_region
*reg
= dev
->mem
->regions
+ i
;
356 assert((uintptr_t)reg
->userspace_addr
== reg
->userspace_addr
);
357 mr
= memory_region_from_host((void *)(uintptr_t)reg
->userspace_addr
,
359 fd
= memory_region_get_fd(mr
);
361 if (fd_num
== VHOST_MEMORY_MAX_NREGIONS
) {
362 error_report("Failed preparing vhost-user memory table msg");
365 msg
.payload
.memory
.regions
[fd_num
].userspace_addr
= reg
->userspace_addr
;
366 msg
.payload
.memory
.regions
[fd_num
].memory_size
= reg
->memory_size
;
367 msg
.payload
.memory
.regions
[fd_num
].guest_phys_addr
= reg
->guest_phys_addr
;
368 msg
.payload
.memory
.regions
[fd_num
].mmap_offset
= offset
;
373 msg
.payload
.memory
.nregions
= fd_num
;
376 error_report("Failed initializing vhost-user memory map, "
377 "consider using -object memory-backend-file share=on");
381 msg
.hdr
.size
= sizeof(msg
.payload
.memory
.nregions
);
382 msg
.hdr
.size
+= sizeof(msg
.payload
.memory
.padding
);
383 msg
.hdr
.size
+= fd_num
* sizeof(VhostUserMemoryRegion
);
385 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
389 if (reply_supported
) {
390 return process_message_reply(dev
, &msg
);
396 static int vhost_user_set_vring_addr(struct vhost_dev
*dev
,
397 struct vhost_vring_addr
*addr
)
400 .hdr
.request
= VHOST_USER_SET_VRING_ADDR
,
401 .hdr
.flags
= VHOST_USER_VERSION
,
402 .payload
.addr
= *addr
,
403 .hdr
.size
= sizeof(msg
.payload
.addr
),
406 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
413 static int vhost_user_set_vring_endian(struct vhost_dev
*dev
,
414 struct vhost_vring_state
*ring
)
416 bool cross_endian
= virtio_has_feature(dev
->protocol_features
,
417 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
);
419 .hdr
.request
= VHOST_USER_SET_VRING_ENDIAN
,
420 .hdr
.flags
= VHOST_USER_VERSION
,
421 .payload
.state
= *ring
,
422 .hdr
.size
= sizeof(msg
.payload
.state
),
426 error_report("vhost-user trying to send unhandled ioctl");
430 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
437 static int vhost_set_vring(struct vhost_dev
*dev
,
438 unsigned long int request
,
439 struct vhost_vring_state
*ring
)
442 .hdr
.request
= request
,
443 .hdr
.flags
= VHOST_USER_VERSION
,
444 .payload
.state
= *ring
,
445 .hdr
.size
= sizeof(msg
.payload
.state
),
448 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
455 static int vhost_user_set_vring_num(struct vhost_dev
*dev
,
456 struct vhost_vring_state
*ring
)
458 return vhost_set_vring(dev
, VHOST_USER_SET_VRING_NUM
, ring
);
461 static int vhost_user_set_vring_base(struct vhost_dev
*dev
,
462 struct vhost_vring_state
*ring
)
464 return vhost_set_vring(dev
, VHOST_USER_SET_VRING_BASE
, ring
);
467 static int vhost_user_set_vring_enable(struct vhost_dev
*dev
, int enable
)
471 if (!virtio_has_feature(dev
->features
, VHOST_USER_F_PROTOCOL_FEATURES
)) {
475 for (i
= 0; i
< dev
->nvqs
; ++i
) {
476 struct vhost_vring_state state
= {
477 .index
= dev
->vq_index
+ i
,
481 vhost_set_vring(dev
, VHOST_USER_SET_VRING_ENABLE
, &state
);
487 static int vhost_user_get_vring_base(struct vhost_dev
*dev
,
488 struct vhost_vring_state
*ring
)
491 .hdr
.request
= VHOST_USER_GET_VRING_BASE
,
492 .hdr
.flags
= VHOST_USER_VERSION
,
493 .payload
.state
= *ring
,
494 .hdr
.size
= sizeof(msg
.payload
.state
),
497 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
501 if (vhost_user_read(dev
, &msg
) < 0) {
505 if (msg
.hdr
.request
!= VHOST_USER_GET_VRING_BASE
) {
506 error_report("Received unexpected msg type. Expected %d received %d",
507 VHOST_USER_GET_VRING_BASE
, msg
.hdr
.request
);
511 if (msg
.hdr
.size
!= sizeof(msg
.payload
.state
)) {
512 error_report("Received bad msg size.");
516 *ring
= msg
.payload
.state
;
521 static int vhost_set_vring_file(struct vhost_dev
*dev
,
522 VhostUserRequest request
,
523 struct vhost_vring_file
*file
)
525 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
528 .hdr
.request
= request
,
529 .hdr
.flags
= VHOST_USER_VERSION
,
530 .payload
.u64
= file
->index
& VHOST_USER_VRING_IDX_MASK
,
531 .hdr
.size
= sizeof(msg
.payload
.u64
),
534 if (ioeventfd_enabled() && file
->fd
> 0) {
535 fds
[fd_num
++] = file
->fd
;
537 msg
.payload
.u64
|= VHOST_USER_VRING_NOFD_MASK
;
540 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
547 static int vhost_user_set_vring_kick(struct vhost_dev
*dev
,
548 struct vhost_vring_file
*file
)
550 return vhost_set_vring_file(dev
, VHOST_USER_SET_VRING_KICK
, file
);
553 static int vhost_user_set_vring_call(struct vhost_dev
*dev
,
554 struct vhost_vring_file
*file
)
556 return vhost_set_vring_file(dev
, VHOST_USER_SET_VRING_CALL
, file
);
559 static int vhost_user_set_u64(struct vhost_dev
*dev
, int request
, uint64_t u64
)
562 .hdr
.request
= request
,
563 .hdr
.flags
= VHOST_USER_VERSION
,
565 .hdr
.size
= sizeof(msg
.payload
.u64
),
568 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
575 static int vhost_user_set_features(struct vhost_dev
*dev
,
578 return vhost_user_set_u64(dev
, VHOST_USER_SET_FEATURES
, features
);
581 static int vhost_user_set_protocol_features(struct vhost_dev
*dev
,
584 return vhost_user_set_u64(dev
, VHOST_USER_SET_PROTOCOL_FEATURES
, features
);
587 static int vhost_user_get_u64(struct vhost_dev
*dev
, int request
, uint64_t *u64
)
590 .hdr
.request
= request
,
591 .hdr
.flags
= VHOST_USER_VERSION
,
594 if (vhost_user_one_time_request(request
) && dev
->vq_index
!= 0) {
598 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
602 if (vhost_user_read(dev
, &msg
) < 0) {
606 if (msg
.hdr
.request
!= request
) {
607 error_report("Received unexpected msg type. Expected %d received %d",
608 request
, msg
.hdr
.request
);
612 if (msg
.hdr
.size
!= sizeof(msg
.payload
.u64
)) {
613 error_report("Received bad msg size.");
617 *u64
= msg
.payload
.u64
;
622 static int vhost_user_get_features(struct vhost_dev
*dev
, uint64_t *features
)
624 return vhost_user_get_u64(dev
, VHOST_USER_GET_FEATURES
, features
);
627 static int vhost_user_set_owner(struct vhost_dev
*dev
)
630 .hdr
.request
= VHOST_USER_SET_OWNER
,
631 .hdr
.flags
= VHOST_USER_VERSION
,
634 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
641 static int vhost_user_reset_device(struct vhost_dev
*dev
)
644 .hdr
.request
= VHOST_USER_RESET_OWNER
,
645 .hdr
.flags
= VHOST_USER_VERSION
,
648 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
655 static int vhost_user_slave_handle_config_change(struct vhost_dev
*dev
)
659 if (!dev
->config_ops
) {
663 if (dev
->config_ops
->vhost_dev_config_notifier
) {
664 ret
= dev
->config_ops
->vhost_dev_config_notifier(dev
);
670 static void slave_read(void *opaque
)
672 struct vhost_dev
*dev
= opaque
;
673 struct vhost_user
*u
= dev
->opaque
;
674 VhostUserHeader hdr
= { 0, };
675 VhostUserPayload payload
= { 0, };
679 size
= read(u
->slave_fd
, &hdr
, VHOST_USER_HDR_SIZE
);
680 if (size
!= VHOST_USER_HDR_SIZE
) {
681 error_report("Failed to read from slave.");
685 if (hdr
.size
> VHOST_USER_PAYLOAD_SIZE
) {
686 error_report("Failed to read msg header."
687 " Size %d exceeds the maximum %zu.", hdr
.size
,
688 VHOST_USER_PAYLOAD_SIZE
);
693 size
= read(u
->slave_fd
, &payload
, hdr
.size
);
694 if (size
!= hdr
.size
) {
695 error_report("Failed to read payload from slave.");
699 switch (hdr
.request
) {
700 case VHOST_USER_SLAVE_IOTLB_MSG
:
701 ret
= vhost_backend_handle_iotlb_msg(dev
, &payload
.iotlb
);
703 case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG
:
704 ret
= vhost_user_slave_handle_config_change(dev
);
707 error_report("Received unexpected msg type.");
712 * REPLY_ACK feature handling. Other reply types has to be managed
713 * directly in their request handlers.
715 if (hdr
.flags
& VHOST_USER_NEED_REPLY_MASK
) {
716 struct iovec iovec
[2];
719 hdr
.flags
&= ~VHOST_USER_NEED_REPLY_MASK
;
720 hdr
.flags
|= VHOST_USER_REPLY_MASK
;
723 hdr
.size
= sizeof(payload
.u64
);
725 iovec
[0].iov_base
= &hdr
;
726 iovec
[0].iov_len
= VHOST_USER_HDR_SIZE
;
727 iovec
[1].iov_base
= &payload
;
728 iovec
[1].iov_len
= hdr
.size
;
730 size
= writev(u
->slave_fd
, iovec
, ARRAY_SIZE(iovec
));
731 if (size
!= VHOST_USER_HDR_SIZE
+ hdr
.size
) {
732 error_report("Failed to send msg reply to slave.");
740 qemu_set_fd_handler(u
->slave_fd
, NULL
, NULL
, NULL
);
746 static int vhost_setup_slave_channel(struct vhost_dev
*dev
)
749 .hdr
.request
= VHOST_USER_SET_SLAVE_REQ_FD
,
750 .hdr
.flags
= VHOST_USER_VERSION
,
752 struct vhost_user
*u
= dev
->opaque
;
754 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
755 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
757 if (!virtio_has_feature(dev
->protocol_features
,
758 VHOST_USER_PROTOCOL_F_SLAVE_REQ
)) {
762 if (socketpair(PF_UNIX
, SOCK_STREAM
, 0, sv
) == -1) {
763 error_report("socketpair() failed");
768 qemu_set_fd_handler(u
->slave_fd
, slave_read
, NULL
, dev
);
770 if (reply_supported
) {
771 msg
.hdr
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
774 ret
= vhost_user_write(dev
, &msg
, &sv
[1], 1);
779 if (reply_supported
) {
780 ret
= process_message_reply(dev
, &msg
);
786 qemu_set_fd_handler(u
->slave_fd
, NULL
, NULL
, NULL
);
794 static int vhost_user_init(struct vhost_dev
*dev
, void *opaque
)
796 uint64_t features
, protocol_features
;
797 struct vhost_user
*u
;
800 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
802 u
= g_new0(struct vhost_user
, 1);
807 err
= vhost_user_get_features(dev
, &features
);
812 if (virtio_has_feature(features
, VHOST_USER_F_PROTOCOL_FEATURES
)) {
813 dev
->backend_features
|= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES
;
815 err
= vhost_user_get_u64(dev
, VHOST_USER_GET_PROTOCOL_FEATURES
,
821 dev
->protocol_features
=
822 protocol_features
& VHOST_USER_PROTOCOL_FEATURE_MASK
;
823 err
= vhost_user_set_protocol_features(dev
, dev
->protocol_features
);
828 /* query the max queues we support if backend supports Multiple Queue */
829 if (dev
->protocol_features
& (1ULL << VHOST_USER_PROTOCOL_F_MQ
)) {
830 err
= vhost_user_get_u64(dev
, VHOST_USER_GET_QUEUE_NUM
,
837 if (virtio_has_feature(features
, VIRTIO_F_IOMMU_PLATFORM
) &&
838 !(virtio_has_feature(dev
->protocol_features
,
839 VHOST_USER_PROTOCOL_F_SLAVE_REQ
) &&
840 virtio_has_feature(dev
->protocol_features
,
841 VHOST_USER_PROTOCOL_F_REPLY_ACK
))) {
842 error_report("IOMMU support requires reply-ack and "
843 "slave-req protocol features.");
848 if (dev
->migration_blocker
== NULL
&&
849 !virtio_has_feature(dev
->protocol_features
,
850 VHOST_USER_PROTOCOL_F_LOG_SHMFD
)) {
851 error_setg(&dev
->migration_blocker
,
852 "Migration disabled: vhost-user backend lacks "
853 "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
856 err
= vhost_setup_slave_channel(dev
);
864 static int vhost_user_cleanup(struct vhost_dev
*dev
)
866 struct vhost_user
*u
;
868 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
871 if (u
->slave_fd
>= 0) {
872 qemu_set_fd_handler(u
->slave_fd
, NULL
, NULL
, NULL
);
882 static int vhost_user_get_vq_index(struct vhost_dev
*dev
, int idx
)
884 assert(idx
>= dev
->vq_index
&& idx
< dev
->vq_index
+ dev
->nvqs
);
889 static int vhost_user_memslots_limit(struct vhost_dev
*dev
)
891 return VHOST_MEMORY_MAX_NREGIONS
;
894 static bool vhost_user_requires_shm_log(struct vhost_dev
*dev
)
896 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
898 return virtio_has_feature(dev
->protocol_features
,
899 VHOST_USER_PROTOCOL_F_LOG_SHMFD
);
902 static int vhost_user_migration_done(struct vhost_dev
*dev
, char* mac_addr
)
904 VhostUserMsg msg
= { 0 };
906 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
908 /* If guest supports GUEST_ANNOUNCE do nothing */
909 if (virtio_has_feature(dev
->acked_features
, VIRTIO_NET_F_GUEST_ANNOUNCE
)) {
913 /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */
914 if (virtio_has_feature(dev
->protocol_features
,
915 VHOST_USER_PROTOCOL_F_RARP
)) {
916 msg
.hdr
.request
= VHOST_USER_SEND_RARP
;
917 msg
.hdr
.flags
= VHOST_USER_VERSION
;
918 memcpy((char *)&msg
.payload
.u64
, mac_addr
, 6);
919 msg
.hdr
.size
= sizeof(msg
.payload
.u64
);
921 return vhost_user_write(dev
, &msg
, NULL
, 0);
926 static bool vhost_user_can_merge(struct vhost_dev
*dev
,
927 uint64_t start1
, uint64_t size1
,
928 uint64_t start2
, uint64_t size2
)
934 mr
= memory_region_from_host((void *)(uintptr_t)start1
, &offset
);
935 mfd
= memory_region_get_fd(mr
);
937 mr
= memory_region_from_host((void *)(uintptr_t)start2
, &offset
);
938 rfd
= memory_region_get_fd(mr
);
943 static int vhost_user_net_set_mtu(struct vhost_dev
*dev
, uint16_t mtu
)
946 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
947 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
949 if (!(dev
->protocol_features
& (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU
))) {
953 msg
.hdr
.request
= VHOST_USER_NET_SET_MTU
;
954 msg
.payload
.u64
= mtu
;
955 msg
.hdr
.size
= sizeof(msg
.payload
.u64
);
956 msg
.hdr
.flags
= VHOST_USER_VERSION
;
957 if (reply_supported
) {
958 msg
.hdr
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
961 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
965 /* If reply_ack supported, slave has to ack specified MTU is valid */
966 if (reply_supported
) {
967 return process_message_reply(dev
, &msg
);
973 static int vhost_user_send_device_iotlb_msg(struct vhost_dev
*dev
,
974 struct vhost_iotlb_msg
*imsg
)
977 .hdr
.request
= VHOST_USER_IOTLB_MSG
,
978 .hdr
.size
= sizeof(msg
.payload
.iotlb
),
979 .hdr
.flags
= VHOST_USER_VERSION
| VHOST_USER_NEED_REPLY_MASK
,
980 .payload
.iotlb
= *imsg
,
983 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
987 return process_message_reply(dev
, &msg
);
991 static void vhost_user_set_iotlb_callback(struct vhost_dev
*dev
, int enabled
)
993 /* No-op as the receive channel is not dedicated to IOTLB messages. */
996 static int vhost_user_get_config(struct vhost_dev
*dev
, uint8_t *config
,
1000 .hdr
.request
= VHOST_USER_GET_CONFIG
,
1001 .hdr
.flags
= VHOST_USER_VERSION
,
1002 .hdr
.size
= VHOST_USER_CONFIG_HDR_SIZE
+ config_len
,
1005 if (config_len
> VHOST_USER_MAX_CONFIG_SIZE
) {
1009 msg
.payload
.config
.offset
= 0;
1010 msg
.payload
.config
.size
= config_len
;
1011 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
1015 if (vhost_user_read(dev
, &msg
) < 0) {
1019 if (msg
.hdr
.request
!= VHOST_USER_GET_CONFIG
) {
1020 error_report("Received unexpected msg type. Expected %d received %d",
1021 VHOST_USER_GET_CONFIG
, msg
.hdr
.request
);
1025 if (msg
.hdr
.size
!= VHOST_USER_CONFIG_HDR_SIZE
+ config_len
) {
1026 error_report("Received bad msg size.");
1030 memcpy(config
, msg
.payload
.config
.region
, config_len
);
1035 static int vhost_user_set_config(struct vhost_dev
*dev
, const uint8_t *data
,
1036 uint32_t offset
, uint32_t size
, uint32_t flags
)
1039 bool reply_supported
= virtio_has_feature(dev
->protocol_features
,
1040 VHOST_USER_PROTOCOL_F_REPLY_ACK
);
1042 VhostUserMsg msg
= {
1043 .hdr
.request
= VHOST_USER_SET_CONFIG
,
1044 .hdr
.flags
= VHOST_USER_VERSION
,
1045 .hdr
.size
= VHOST_USER_CONFIG_HDR_SIZE
+ size
,
1048 if (reply_supported
) {
1049 msg
.hdr
.flags
|= VHOST_USER_NEED_REPLY_MASK
;
1052 if (size
> VHOST_USER_MAX_CONFIG_SIZE
) {
1056 msg
.payload
.config
.offset
= offset
,
1057 msg
.payload
.config
.size
= size
,
1058 msg
.payload
.config
.flags
= flags
,
1059 p
= msg
.payload
.config
.region
;
1060 memcpy(p
, data
, size
);
1062 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
1066 if (reply_supported
) {
1067 return process_message_reply(dev
, &msg
);
1073 static int vhost_user_crypto_create_session(struct vhost_dev
*dev
,
1075 uint64_t *session_id
)
1077 bool crypto_session
= virtio_has_feature(dev
->protocol_features
,
1078 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION
);
1079 CryptoDevBackendSymSessionInfo
*sess_info
= session_info
;
1080 VhostUserMsg msg
= {
1081 .hdr
.request
= VHOST_USER_CREATE_CRYPTO_SESSION
,
1082 .hdr
.flags
= VHOST_USER_VERSION
,
1083 .hdr
.size
= sizeof(msg
.payload
.session
),
1086 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
1088 if (!crypto_session
) {
1089 error_report("vhost-user trying to send unhandled ioctl");
1093 memcpy(&msg
.payload
.session
.session_setup_data
, sess_info
,
1094 sizeof(CryptoDevBackendSymSessionInfo
));
1095 if (sess_info
->key_len
) {
1096 memcpy(&msg
.payload
.session
.key
, sess_info
->cipher_key
,
1097 sess_info
->key_len
);
1099 if (sess_info
->auth_key_len
> 0) {
1100 memcpy(&msg
.payload
.session
.auth_key
, sess_info
->auth_key
,
1101 sess_info
->auth_key_len
);
1103 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
1104 error_report("vhost_user_write() return -1, create session failed");
1108 if (vhost_user_read(dev
, &msg
) < 0) {
1109 error_report("vhost_user_read() return -1, create session failed");
1113 if (msg
.hdr
.request
!= VHOST_USER_CREATE_CRYPTO_SESSION
) {
1114 error_report("Received unexpected msg type. Expected %d received %d",
1115 VHOST_USER_CREATE_CRYPTO_SESSION
, msg
.hdr
.request
);
1119 if (msg
.hdr
.size
!= sizeof(msg
.payload
.session
)) {
1120 error_report("Received bad msg size.");
1124 if (msg
.payload
.session
.session_id
< 0) {
1125 error_report("Bad session id: %" PRId64
"",
1126 msg
.payload
.session
.session_id
);
1129 *session_id
= msg
.payload
.session
.session_id
;
1135 vhost_user_crypto_close_session(struct vhost_dev
*dev
, uint64_t session_id
)
1137 bool crypto_session
= virtio_has_feature(dev
->protocol_features
,
1138 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION
);
1139 VhostUserMsg msg
= {
1140 .hdr
.request
= VHOST_USER_CLOSE_CRYPTO_SESSION
,
1141 .hdr
.flags
= VHOST_USER_VERSION
,
1142 .hdr
.size
= sizeof(msg
.payload
.u64
),
1144 msg
.payload
.u64
= session_id
;
1146 if (!crypto_session
) {
1147 error_report("vhost-user trying to send unhandled ioctl");
1151 if (vhost_user_write(dev
, &msg
, NULL
, 0) < 0) {
1152 error_report("vhost_user_write() return -1, close session failed");
1159 const VhostOps user_ops
= {
1160 .backend_type
= VHOST_BACKEND_TYPE_USER
,
1161 .vhost_backend_init
= vhost_user_init
,
1162 .vhost_backend_cleanup
= vhost_user_cleanup
,
1163 .vhost_backend_memslots_limit
= vhost_user_memslots_limit
,
1164 .vhost_set_log_base
= vhost_user_set_log_base
,
1165 .vhost_set_mem_table
= vhost_user_set_mem_table
,
1166 .vhost_set_vring_addr
= vhost_user_set_vring_addr
,
1167 .vhost_set_vring_endian
= vhost_user_set_vring_endian
,
1168 .vhost_set_vring_num
= vhost_user_set_vring_num
,
1169 .vhost_set_vring_base
= vhost_user_set_vring_base
,
1170 .vhost_get_vring_base
= vhost_user_get_vring_base
,
1171 .vhost_set_vring_kick
= vhost_user_set_vring_kick
,
1172 .vhost_set_vring_call
= vhost_user_set_vring_call
,
1173 .vhost_set_features
= vhost_user_set_features
,
1174 .vhost_get_features
= vhost_user_get_features
,
1175 .vhost_set_owner
= vhost_user_set_owner
,
1176 .vhost_reset_device
= vhost_user_reset_device
,
1177 .vhost_get_vq_index
= vhost_user_get_vq_index
,
1178 .vhost_set_vring_enable
= vhost_user_set_vring_enable
,
1179 .vhost_requires_shm_log
= vhost_user_requires_shm_log
,
1180 .vhost_migration_done
= vhost_user_migration_done
,
1181 .vhost_backend_can_merge
= vhost_user_can_merge
,
1182 .vhost_net_set_mtu
= vhost_user_net_set_mtu
,
1183 .vhost_set_iotlb_callback
= vhost_user_set_iotlb_callback
,
1184 .vhost_send_device_iotlb_msg
= vhost_user_send_device_iotlb_msg
,
1185 .vhost_get_config
= vhost_user_get_config
,
1186 .vhost_set_config
= vhost_user_set_config
,
1187 .vhost_crypto_create_session
= vhost_user_crypto_create_session
,
1188 .vhost_crypto_close_session
= vhost_user_crypto_close_session
,