]> git.proxmox.com Git - mirror_qemu.git/blame - hw/virtio/vhost-user.c
postcopy: Allow registering of fd handler
[mirror_qemu.git] / hw / virtio / vhost-user.c
CommitLineData
5f6f6664
NN
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
9b8bfe21 11#include "qemu/osdep.h"
da34e65c 12#include "qapi/error.h"
5f6f6664
NN
13#include "hw/virtio/vhost.h"
14#include "hw/virtio/vhost-backend.h"
3e866365 15#include "hw/virtio/virtio-net.h"
4d43a603 16#include "chardev/char-fe.h"
5f6f6664
NN
17#include "sysemu/kvm.h"
18#include "qemu/error-report.h"
19#include "qemu/sockets.h"
efbfeb81 20#include "sysemu/cryptodev.h"
9ccbfe14
DDAG
21#include "migration/migration.h"
22#include "migration/postcopy-ram.h"
5f6f6664 23
5f6f6664
NN
24#include <sys/ioctl.h>
25#include <sys/socket.h>
26#include <sys/un.h>
27#include <linux/vhost.h>
28
29#define VHOST_MEMORY_MAX_NREGIONS 8
dcb10c00 30#define VHOST_USER_F_PROTOCOL_FEATURES 30
e2051e9e 31
4c3e257b
CL
32/*
33 * Maximum size of virtio device config space
34 */
35#define VHOST_USER_MAX_CONFIG_SIZE 256
36
de1372d4
TC
37enum VhostUserProtocolFeature {
38 VHOST_USER_PROTOCOL_F_MQ = 0,
39 VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
40 VHOST_USER_PROTOCOL_F_RARP = 2,
ca525ce5 41 VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
c5f048d8 42 VHOST_USER_PROTOCOL_F_NET_MTU = 4,
4bbeeba0 43 VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5,
5df04f17 44 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
efbfeb81 45 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
9ccbfe14 46 VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
de1372d4
TC
47 VHOST_USER_PROTOCOL_F_MAX
48};
49
50#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
5f6f6664
NN
51
52typedef enum VhostUserRequest {
53 VHOST_USER_NONE = 0,
54 VHOST_USER_GET_FEATURES = 1,
55 VHOST_USER_SET_FEATURES = 2,
56 VHOST_USER_SET_OWNER = 3,
60915dc4 57 VHOST_USER_RESET_OWNER = 4,
5f6f6664
NN
58 VHOST_USER_SET_MEM_TABLE = 5,
59 VHOST_USER_SET_LOG_BASE = 6,
60 VHOST_USER_SET_LOG_FD = 7,
61 VHOST_USER_SET_VRING_NUM = 8,
62 VHOST_USER_SET_VRING_ADDR = 9,
63 VHOST_USER_SET_VRING_BASE = 10,
64 VHOST_USER_GET_VRING_BASE = 11,
65 VHOST_USER_SET_VRING_KICK = 12,
66 VHOST_USER_SET_VRING_CALL = 13,
67 VHOST_USER_SET_VRING_ERR = 14,
dcb10c00
MT
68 VHOST_USER_GET_PROTOCOL_FEATURES = 15,
69 VHOST_USER_SET_PROTOCOL_FEATURES = 16,
e2051e9e 70 VHOST_USER_GET_QUEUE_NUM = 17,
7263a0ad 71 VHOST_USER_SET_VRING_ENABLE = 18,
3e866365 72 VHOST_USER_SEND_RARP = 19,
c5f048d8 73 VHOST_USER_NET_SET_MTU = 20,
4bbeeba0 74 VHOST_USER_SET_SLAVE_REQ_FD = 21,
6dcdd06e 75 VHOST_USER_IOTLB_MSG = 22,
5df04f17 76 VHOST_USER_SET_VRING_ENDIAN = 23,
4c3e257b
CL
77 VHOST_USER_GET_CONFIG = 24,
78 VHOST_USER_SET_CONFIG = 25,
efbfeb81
GA
79 VHOST_USER_CREATE_CRYPTO_SESSION = 26,
80 VHOST_USER_CLOSE_CRYPTO_SESSION = 27,
d3dff7a5 81 VHOST_USER_POSTCOPY_ADVISE = 28,
5f6f6664
NN
82 VHOST_USER_MAX
83} VhostUserRequest;
84
4bbeeba0
MAL
85typedef enum VhostUserSlaveRequest {
86 VHOST_USER_SLAVE_NONE = 0,
6dcdd06e 87 VHOST_USER_SLAVE_IOTLB_MSG = 1,
4c3e257b 88 VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
4bbeeba0
MAL
89 VHOST_USER_SLAVE_MAX
90} VhostUserSlaveRequest;
91
5f6f6664
NN
92typedef struct VhostUserMemoryRegion {
93 uint64_t guest_phys_addr;
94 uint64_t memory_size;
95 uint64_t userspace_addr;
3fd74b84 96 uint64_t mmap_offset;
5f6f6664
NN
97} VhostUserMemoryRegion;
98
99typedef struct VhostUserMemory {
100 uint32_t nregions;
101 uint32_t padding;
102 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
103} VhostUserMemory;
104
2b8819c6
VK
105typedef struct VhostUserLog {
106 uint64_t mmap_size;
107 uint64_t mmap_offset;
108} VhostUserLog;
109
4c3e257b
CL
110typedef struct VhostUserConfig {
111 uint32_t offset;
112 uint32_t size;
113 uint32_t flags;
114 uint8_t region[VHOST_USER_MAX_CONFIG_SIZE];
115} VhostUserConfig;
116
efbfeb81
GA
117#define VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN 512
118#define VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN 64
119
120typedef struct VhostUserCryptoSession {
121 /* session id for success, -1 on errors */
122 int64_t session_id;
123 CryptoDevBackendSymSessionInfo session_setup_data;
124 uint8_t key[VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN];
125 uint8_t auth_key[VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN];
126} VhostUserCryptoSession;
127
4c3e257b
CL
128static VhostUserConfig c __attribute__ ((unused));
129#define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \
130 + sizeof(c.size) \
131 + sizeof(c.flags))
132
24e34754 133typedef struct {
5f6f6664
NN
134 VhostUserRequest request;
135
136#define VHOST_USER_VERSION_MASK (0x3)
137#define VHOST_USER_REPLY_MASK (0x1<<2)
ca525ce5 138#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
5f6f6664
NN
139 uint32_t flags;
140 uint32_t size; /* the following payload size */
24e34754
MT
141} QEMU_PACKED VhostUserHeader;
142
143typedef union {
5f6f6664
NN
144#define VHOST_USER_VRING_IDX_MASK (0xff)
145#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
146 uint64_t u64;
147 struct vhost_vring_state state;
148 struct vhost_vring_addr addr;
149 VhostUserMemory memory;
2b8819c6 150 VhostUserLog log;
6dcdd06e 151 struct vhost_iotlb_msg iotlb;
4c3e257b 152 VhostUserConfig config;
efbfeb81 153 VhostUserCryptoSession session;
24e34754
MT
154} VhostUserPayload;
155
156typedef struct VhostUserMsg {
157 VhostUserHeader hdr;
158 VhostUserPayload payload;
5f6f6664
NN
159} QEMU_PACKED VhostUserMsg;
160
161static VhostUserMsg m __attribute__ ((unused));
24e34754 162#define VHOST_USER_HDR_SIZE (sizeof(VhostUserHeader))
5f6f6664 163
24e34754 164#define VHOST_USER_PAYLOAD_SIZE (sizeof(VhostUserPayload))
5f6f6664
NN
165
166/* The version of the protocol we support */
167#define VHOST_USER_VERSION (0x1)
168
2152f3fe 169struct vhost_user {
9ccbfe14 170 struct vhost_dev *dev;
2152f3fe 171 CharBackend *chr;
4bbeeba0 172 int slave_fd;
9ccbfe14 173 NotifierWithReturn postcopy_notifier;
2152f3fe
MAL
174};
175
5f6f6664
NN
176static bool ioeventfd_enabled(void)
177{
178 return kvm_enabled() && kvm_eventfds_enabled();
179}
180
5f6f6664
NN
181static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
182{
2152f3fe
MAL
183 struct vhost_user *u = dev->opaque;
184 CharBackend *chr = u->chr;
5f6f6664
NN
185 uint8_t *p = (uint8_t *) msg;
186 int r, size = VHOST_USER_HDR_SIZE;
187
188 r = qemu_chr_fe_read_all(chr, p, size);
189 if (r != size) {
5421f318 190 error_report("Failed to read msg header. Read %d instead of %d."
24e34754 191 " Original request %d.", r, size, msg->hdr.request);
5f6f6664
NN
192 goto fail;
193 }
194
195 /* validate received flags */
24e34754 196 if (msg->hdr.flags != (VHOST_USER_REPLY_MASK | VHOST_USER_VERSION)) {
5f6f6664 197 error_report("Failed to read msg header."
24e34754 198 " Flags 0x%x instead of 0x%x.", msg->hdr.flags,
5f6f6664
NN
199 VHOST_USER_REPLY_MASK | VHOST_USER_VERSION);
200 goto fail;
201 }
202
203 /* validate message size is sane */
24e34754 204 if (msg->hdr.size > VHOST_USER_PAYLOAD_SIZE) {
5f6f6664 205 error_report("Failed to read msg header."
24e34754 206 " Size %d exceeds the maximum %zu.", msg->hdr.size,
5f6f6664
NN
207 VHOST_USER_PAYLOAD_SIZE);
208 goto fail;
209 }
210
24e34754 211 if (msg->hdr.size) {
5f6f6664 212 p += VHOST_USER_HDR_SIZE;
24e34754 213 size = msg->hdr.size;
5f6f6664
NN
214 r = qemu_chr_fe_read_all(chr, p, size);
215 if (r != size) {
216 error_report("Failed to read msg payload."
24e34754 217 " Read %d instead of %d.", r, msg->hdr.size);
5f6f6664
NN
218 goto fail;
219 }
220 }
221
222 return 0;
223
224fail:
225 return -1;
226}
227
ca525ce5 228static int process_message_reply(struct vhost_dev *dev,
3cf7daf8 229 const VhostUserMsg *msg)
ca525ce5 230{
60cd1102 231 VhostUserMsg msg_reply;
ca525ce5 232
24e34754 233 if ((msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
60cd1102
ZY
234 return 0;
235 }
236
237 if (vhost_user_read(dev, &msg_reply) < 0) {
ca525ce5
PS
238 return -1;
239 }
240
24e34754 241 if (msg_reply.hdr.request != msg->hdr.request) {
ca525ce5
PS
242 error_report("Received unexpected msg type."
243 "Expected %d received %d",
24e34754 244 msg->hdr.request, msg_reply.hdr.request);
ca525ce5
PS
245 return -1;
246 }
247
60cd1102 248 return msg_reply.payload.u64 ? -1 : 0;
ca525ce5
PS
249}
250
21e70425
MAL
251static bool vhost_user_one_time_request(VhostUserRequest request)
252{
253 switch (request) {
254 case VHOST_USER_SET_OWNER:
60915dc4 255 case VHOST_USER_RESET_OWNER:
21e70425
MAL
256 case VHOST_USER_SET_MEM_TABLE:
257 case VHOST_USER_GET_QUEUE_NUM:
c5f048d8 258 case VHOST_USER_NET_SET_MTU:
21e70425
MAL
259 return true;
260 default:
261 return false;
262 }
263}
264
265/* most non-init callers ignore the error */
5f6f6664
NN
266static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
267 int *fds, int fd_num)
268{
2152f3fe
MAL
269 struct vhost_user *u = dev->opaque;
270 CharBackend *chr = u->chr;
24e34754 271 int ret, size = VHOST_USER_HDR_SIZE + msg->hdr.size;
5f6f6664 272
21e70425
MAL
273 /*
274 * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
275 * we just need send it once in the first time. For later such
276 * request, we just ignore it.
277 */
24e34754
MT
278 if (vhost_user_one_time_request(msg->hdr.request) && dev->vq_index != 0) {
279 msg->hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK;
21e70425
MAL
280 return 0;
281 }
282
6fab2f3f 283 if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
f6b85710 284 error_report("Failed to set msg fds.");
6fab2f3f
MAL
285 return -1;
286 }
5f6f6664 287
f6b85710
MAL
288 ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
289 if (ret != size) {
290 error_report("Failed to write msg."
291 " Wrote %d instead of %d.", ret, size);
292 return -1;
293 }
294
295 return 0;
5f6f6664
NN
296}
297
21e70425
MAL
298static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
299 struct vhost_log *log)
b931bfbf 300{
21e70425
MAL
301 int fds[VHOST_MEMORY_MAX_NREGIONS];
302 size_t fd_num = 0;
303 bool shmfd = virtio_has_feature(dev->protocol_features,
304 VHOST_USER_PROTOCOL_F_LOG_SHMFD);
305 VhostUserMsg msg = {
24e34754
MT
306 .hdr.request = VHOST_USER_SET_LOG_BASE,
307 .hdr.flags = VHOST_USER_VERSION,
48854f57 308 .payload.log.mmap_size = log->size * sizeof(*(log->log)),
2b8819c6 309 .payload.log.mmap_offset = 0,
24e34754 310 .hdr.size = sizeof(msg.payload.log),
21e70425
MAL
311 };
312
313 if (shmfd && log->fd != -1) {
314 fds[fd_num++] = log->fd;
315 }
316
c4843a45
MAL
317 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
318 return -1;
319 }
21e70425
MAL
320
321 if (shmfd) {
24e34754 322 msg.hdr.size = 0;
21e70425 323 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 324 return -1;
21e70425
MAL
325 }
326
24e34754 327 if (msg.hdr.request != VHOST_USER_SET_LOG_BASE) {
21e70425
MAL
328 error_report("Received unexpected msg type. "
329 "Expected %d received %d",
24e34754 330 VHOST_USER_SET_LOG_BASE, msg.hdr.request);
21e70425
MAL
331 return -1;
332 }
b931bfbf 333 }
21e70425
MAL
334
335 return 0;
b931bfbf
CO
336}
337
94c9cb31
MT
338static int vhost_user_set_mem_table(struct vhost_dev *dev,
339 struct vhost_memory *mem)
340{
341 int fds[VHOST_MEMORY_MAX_NREGIONS];
342 int i, fd;
343 size_t fd_num = 0;
344 bool reply_supported = virtio_has_feature(dev->protocol_features,
345 VHOST_USER_PROTOCOL_F_REPLY_ACK);
346
347 VhostUserMsg msg = {
24e34754
MT
348 .hdr.request = VHOST_USER_SET_MEM_TABLE,
349 .hdr.flags = VHOST_USER_VERSION,
94c9cb31
MT
350 };
351
352 if (reply_supported) {
24e34754 353 msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
94c9cb31
MT
354 }
355
356 for (i = 0; i < dev->mem->nregions; ++i) {
357 struct vhost_memory_region *reg = dev->mem->regions + i;
358 ram_addr_t offset;
359 MemoryRegion *mr;
360
361 assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
362 mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr,
363 &offset);
364 fd = memory_region_get_fd(mr);
365 if (fd > 0) {
f4bf56fb
JZ
366 if (fd_num == VHOST_MEMORY_MAX_NREGIONS) {
367 error_report("Failed preparing vhost-user memory table msg");
368 return -1;
369 }
94c9cb31
MT
370 msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
371 msg.payload.memory.regions[fd_num].memory_size = reg->memory_size;
372 msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
373 msg.payload.memory.regions[fd_num].mmap_offset = offset;
94c9cb31
MT
374 fds[fd_num++] = fd;
375 }
376 }
377
378 msg.payload.memory.nregions = fd_num;
379
380 if (!fd_num) {
381 error_report("Failed initializing vhost-user memory map, "
382 "consider using -object memory-backend-file share=on");
383 return -1;
384 }
385
24e34754
MT
386 msg.hdr.size = sizeof(msg.payload.memory.nregions);
387 msg.hdr.size += sizeof(msg.payload.memory.padding);
388 msg.hdr.size += fd_num * sizeof(VhostUserMemoryRegion);
94c9cb31
MT
389
390 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
391 return -1;
392 }
393
394 if (reply_supported) {
3cf7daf8 395 return process_message_reply(dev, &msg);
94c9cb31
MT
396 }
397
398 return 0;
399}
400
21e70425
MAL
401static int vhost_user_set_vring_addr(struct vhost_dev *dev,
402 struct vhost_vring_addr *addr)
403{
404 VhostUserMsg msg = {
24e34754
MT
405 .hdr.request = VHOST_USER_SET_VRING_ADDR,
406 .hdr.flags = VHOST_USER_VERSION,
7f4a930e 407 .payload.addr = *addr,
24e34754 408 .hdr.size = sizeof(msg.payload.addr),
21e70425 409 };
5f6f6664 410
c4843a45
MAL
411 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
412 return -1;
413 }
5f6f6664 414
21e70425
MAL
415 return 0;
416}
5f6f6664 417
21e70425
MAL
418static int vhost_user_set_vring_endian(struct vhost_dev *dev,
419 struct vhost_vring_state *ring)
420{
5df04f17
FF
421 bool cross_endian = virtio_has_feature(dev->protocol_features,
422 VHOST_USER_PROTOCOL_F_CROSS_ENDIAN);
423 VhostUserMsg msg = {
24e34754
MT
424 .hdr.request = VHOST_USER_SET_VRING_ENDIAN,
425 .hdr.flags = VHOST_USER_VERSION,
5df04f17 426 .payload.state = *ring,
24e34754 427 .hdr.size = sizeof(msg.payload.state),
5df04f17
FF
428 };
429
430 if (!cross_endian) {
431 error_report("vhost-user trying to send unhandled ioctl");
432 return -1;
433 }
434
435 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
436 return -1;
437 }
438
439 return 0;
21e70425 440}
5f6f6664 441
21e70425
MAL
442static int vhost_set_vring(struct vhost_dev *dev,
443 unsigned long int request,
444 struct vhost_vring_state *ring)
445{
446 VhostUserMsg msg = {
24e34754
MT
447 .hdr.request = request,
448 .hdr.flags = VHOST_USER_VERSION,
7f4a930e 449 .payload.state = *ring,
24e34754 450 .hdr.size = sizeof(msg.payload.state),
21e70425
MAL
451 };
452
c4843a45
MAL
453 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
454 return -1;
455 }
21e70425
MAL
456
457 return 0;
458}
459
460static int vhost_user_set_vring_num(struct vhost_dev *dev,
461 struct vhost_vring_state *ring)
462{
463 return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
464}
465
466static int vhost_user_set_vring_base(struct vhost_dev *dev,
467 struct vhost_vring_state *ring)
468{
469 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
470}
471
472static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
473{
dc3db6ad 474 int i;
21e70425 475
923e2d98 476 if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
5f6f6664 477 return -1;
5f6f6664
NN
478 }
479
dc3db6ad
MT
480 for (i = 0; i < dev->nvqs; ++i) {
481 struct vhost_vring_state state = {
482 .index = dev->vq_index + i,
483 .num = enable,
484 };
485
486 vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state);
487 }
21e70425 488
dc3db6ad
MT
489 return 0;
490}
21e70425
MAL
491
492static int vhost_user_get_vring_base(struct vhost_dev *dev,
493 struct vhost_vring_state *ring)
494{
495 VhostUserMsg msg = {
24e34754
MT
496 .hdr.request = VHOST_USER_GET_VRING_BASE,
497 .hdr.flags = VHOST_USER_VERSION,
7f4a930e 498 .payload.state = *ring,
24e34754 499 .hdr.size = sizeof(msg.payload.state),
21e70425
MAL
500 };
501
c4843a45
MAL
502 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
503 return -1;
504 }
21e70425
MAL
505
506 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 507 return -1;
5f6f6664
NN
508 }
509
24e34754 510 if (msg.hdr.request != VHOST_USER_GET_VRING_BASE) {
21e70425 511 error_report("Received unexpected msg type. Expected %d received %d",
24e34754 512 VHOST_USER_GET_VRING_BASE, msg.hdr.request);
21e70425
MAL
513 return -1;
514 }
5f6f6664 515
24e34754 516 if (msg.hdr.size != sizeof(msg.payload.state)) {
21e70425
MAL
517 error_report("Received bad msg size.");
518 return -1;
5f6f6664
NN
519 }
520
7f4a930e 521 *ring = msg.payload.state;
21e70425 522
5f6f6664
NN
523 return 0;
524}
525
21e70425
MAL
526static int vhost_set_vring_file(struct vhost_dev *dev,
527 VhostUserRequest request,
528 struct vhost_vring_file *file)
c2bea314 529{
9a78a5dd
MAL
530 int fds[VHOST_MEMORY_MAX_NREGIONS];
531 size_t fd_num = 0;
c2bea314 532 VhostUserMsg msg = {
24e34754
MT
533 .hdr.request = request,
534 .hdr.flags = VHOST_USER_VERSION,
7f4a930e 535 .payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK,
24e34754 536 .hdr.size = sizeof(msg.payload.u64),
c2bea314
MAL
537 };
538
21e70425
MAL
539 if (ioeventfd_enabled() && file->fd > 0) {
540 fds[fd_num++] = file->fd;
541 } else {
7f4a930e 542 msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
9a78a5dd
MAL
543 }
544
c4843a45
MAL
545 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
546 return -1;
547 }
9a78a5dd 548
21e70425
MAL
549 return 0;
550}
9a78a5dd 551
21e70425
MAL
552static int vhost_user_set_vring_kick(struct vhost_dev *dev,
553 struct vhost_vring_file *file)
554{
555 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file);
556}
557
558static int vhost_user_set_vring_call(struct vhost_dev *dev,
559 struct vhost_vring_file *file)
560{
561 return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file);
562}
563
564static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
565{
566 VhostUserMsg msg = {
24e34754
MT
567 .hdr.request = request,
568 .hdr.flags = VHOST_USER_VERSION,
7f4a930e 569 .payload.u64 = u64,
24e34754 570 .hdr.size = sizeof(msg.payload.u64),
21e70425
MAL
571 };
572
c4843a45
MAL
573 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
574 return -1;
575 }
21e70425
MAL
576
577 return 0;
578}
579
580static int vhost_user_set_features(struct vhost_dev *dev,
581 uint64_t features)
582{
583 return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features);
584}
585
586static int vhost_user_set_protocol_features(struct vhost_dev *dev,
587 uint64_t features)
588{
589 return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features);
590}
591
592static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
593{
594 VhostUserMsg msg = {
24e34754
MT
595 .hdr.request = request,
596 .hdr.flags = VHOST_USER_VERSION,
21e70425
MAL
597 };
598
599 if (vhost_user_one_time_request(request) && dev->vq_index != 0) {
600 return 0;
9a78a5dd 601 }
c2bea314 602
c4843a45
MAL
603 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
604 return -1;
605 }
21e70425
MAL
606
607 if (vhost_user_read(dev, &msg) < 0) {
c4843a45 608 return -1;
21e70425
MAL
609 }
610
24e34754 611 if (msg.hdr.request != request) {
21e70425 612 error_report("Received unexpected msg type. Expected %d received %d",
24e34754 613 request, msg.hdr.request);
21e70425
MAL
614 return -1;
615 }
616
24e34754 617 if (msg.hdr.size != sizeof(msg.payload.u64)) {
21e70425
MAL
618 error_report("Received bad msg size.");
619 return -1;
620 }
621
7f4a930e 622 *u64 = msg.payload.u64;
21e70425
MAL
623
624 return 0;
625}
626
627static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features)
628{
629 return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features);
630}
631
632static int vhost_user_set_owner(struct vhost_dev *dev)
633{
634 VhostUserMsg msg = {
24e34754
MT
635 .hdr.request = VHOST_USER_SET_OWNER,
636 .hdr.flags = VHOST_USER_VERSION,
21e70425
MAL
637 };
638
c4843a45
MAL
639 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
640 return -1;
641 }
21e70425
MAL
642
643 return 0;
644}
645
646static int vhost_user_reset_device(struct vhost_dev *dev)
647{
648 VhostUserMsg msg = {
24e34754
MT
649 .hdr.request = VHOST_USER_RESET_OWNER,
650 .hdr.flags = VHOST_USER_VERSION,
21e70425
MAL
651 };
652
c4843a45
MAL
653 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
654 return -1;
655 }
21e70425 656
c2bea314
MAL
657 return 0;
658}
659
4c3e257b
CL
660static int vhost_user_slave_handle_config_change(struct vhost_dev *dev)
661{
662 int ret = -1;
663
664 if (!dev->config_ops) {
665 return -1;
666 }
667
668 if (dev->config_ops->vhost_dev_config_notifier) {
669 ret = dev->config_ops->vhost_dev_config_notifier(dev);
670 }
671
672 return ret;
673}
674
4bbeeba0
MAL
675static void slave_read(void *opaque)
676{
677 struct vhost_dev *dev = opaque;
678 struct vhost_user *u = dev->opaque;
69aff030
MT
679 VhostUserHeader hdr = { 0, };
680 VhostUserPayload payload = { 0, };
4bbeeba0
MAL
681 int size, ret = 0;
682
683 /* Read header */
69aff030 684 size = read(u->slave_fd, &hdr, VHOST_USER_HDR_SIZE);
4bbeeba0
MAL
685 if (size != VHOST_USER_HDR_SIZE) {
686 error_report("Failed to read from slave.");
687 goto err;
688 }
689
69aff030 690 if (hdr.size > VHOST_USER_PAYLOAD_SIZE) {
4bbeeba0 691 error_report("Failed to read msg header."
69aff030 692 " Size %d exceeds the maximum %zu.", hdr.size,
4bbeeba0
MAL
693 VHOST_USER_PAYLOAD_SIZE);
694 goto err;
695 }
696
697 /* Read payload */
69aff030
MT
698 size = read(u->slave_fd, &payload, hdr.size);
699 if (size != hdr.size) {
4bbeeba0
MAL
700 error_report("Failed to read payload from slave.");
701 goto err;
702 }
703
69aff030 704 switch (hdr.request) {
6dcdd06e 705 case VHOST_USER_SLAVE_IOTLB_MSG:
69aff030 706 ret = vhost_backend_handle_iotlb_msg(dev, &payload.iotlb);
6dcdd06e 707 break;
4c3e257b
CL
708 case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG :
709 ret = vhost_user_slave_handle_config_change(dev);
710 break;
4bbeeba0
MAL
711 default:
712 error_report("Received unexpected msg type.");
713 ret = -EINVAL;
714 }
715
716 /*
717 * REPLY_ACK feature handling. Other reply types has to be managed
718 * directly in their request handlers.
719 */
69aff030
MT
720 if (hdr.flags & VHOST_USER_NEED_REPLY_MASK) {
721 struct iovec iovec[2];
4bbeeba0 722
4bbeeba0 723
69aff030
MT
724 hdr.flags &= ~VHOST_USER_NEED_REPLY_MASK;
725 hdr.flags |= VHOST_USER_REPLY_MASK;
726
727 payload.u64 = !!ret;
728 hdr.size = sizeof(payload.u64);
729
730 iovec[0].iov_base = &hdr;
731 iovec[0].iov_len = VHOST_USER_HDR_SIZE;
732 iovec[1].iov_base = &payload;
733 iovec[1].iov_len = hdr.size;
734
735 size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec));
736 if (size != VHOST_USER_HDR_SIZE + hdr.size) {
4bbeeba0
MAL
737 error_report("Failed to send msg reply to slave.");
738 goto err;
739 }
740 }
741
742 return;
743
744err:
745 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
746 close(u->slave_fd);
747 u->slave_fd = -1;
748 return;
749}
750
751static int vhost_setup_slave_channel(struct vhost_dev *dev)
752{
753 VhostUserMsg msg = {
24e34754
MT
754 .hdr.request = VHOST_USER_SET_SLAVE_REQ_FD,
755 .hdr.flags = VHOST_USER_VERSION,
4bbeeba0
MAL
756 };
757 struct vhost_user *u = dev->opaque;
758 int sv[2], ret = 0;
759 bool reply_supported = virtio_has_feature(dev->protocol_features,
760 VHOST_USER_PROTOCOL_F_REPLY_ACK);
761
762 if (!virtio_has_feature(dev->protocol_features,
763 VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
764 return 0;
765 }
766
767 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
768 error_report("socketpair() failed");
769 return -1;
770 }
771
772 u->slave_fd = sv[0];
773 qemu_set_fd_handler(u->slave_fd, slave_read, NULL, dev);
774
775 if (reply_supported) {
24e34754 776 msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
4bbeeba0
MAL
777 }
778
779 ret = vhost_user_write(dev, &msg, &sv[1], 1);
780 if (ret) {
781 goto out;
782 }
783
784 if (reply_supported) {
785 ret = process_message_reply(dev, &msg);
786 }
787
788out:
789 close(sv[1]);
790 if (ret) {
791 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
792 close(u->slave_fd);
793 u->slave_fd = -1;
794 }
795
796 return ret;
797}
798
d3dff7a5
DDAG
799/*
800 * Called at the start of an inbound postcopy on reception of the
801 * 'advise' command.
802 */
803static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)
804{
805 struct vhost_user *u = dev->opaque;
806 CharBackend *chr = u->chr;
807 int ufd;
808 VhostUserMsg msg = {
809 .hdr.request = VHOST_USER_POSTCOPY_ADVISE,
810 .hdr.flags = VHOST_USER_VERSION,
811 };
812
813 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
814 error_setg(errp, "Failed to send postcopy_advise to vhost");
815 return -1;
816 }
817
818 if (vhost_user_read(dev, &msg) < 0) {
819 error_setg(errp, "Failed to get postcopy_advise reply from vhost");
820 return -1;
821 }
822
823 if (msg.hdr.request != VHOST_USER_POSTCOPY_ADVISE) {
824 error_setg(errp, "Unexpected msg type. Expected %d received %d",
825 VHOST_USER_POSTCOPY_ADVISE, msg.hdr.request);
826 return -1;
827 }
828
829 if (msg.hdr.size) {
830 error_setg(errp, "Received bad msg size.");
831 return -1;
832 }
833 ufd = qemu_chr_fe_get_msgfd(chr);
834 if (ufd < 0) {
835 error_setg(errp, "%s: Failed to get ufd", __func__);
836 return -1;
837 }
838
839 /* TODO: register ufd with userfault thread */
840 return 0;
841}
842
9ccbfe14
DDAG
843static int vhost_user_postcopy_notifier(NotifierWithReturn *notifier,
844 void *opaque)
845{
846 struct PostcopyNotifyData *pnd = opaque;
847 struct vhost_user *u = container_of(notifier, struct vhost_user,
848 postcopy_notifier);
849 struct vhost_dev *dev = u->dev;
850
851 switch (pnd->reason) {
852 case POSTCOPY_NOTIFY_PROBE:
853 if (!virtio_has_feature(dev->protocol_features,
854 VHOST_USER_PROTOCOL_F_PAGEFAULT)) {
855 /* TODO: Get the device name into this error somehow */
856 error_setg(pnd->errp,
857 "vhost-user backend not capable of postcopy");
858 return -ENOENT;
859 }
860 break;
861
d3dff7a5
DDAG
862 case POSTCOPY_NOTIFY_INBOUND_ADVISE:
863 return vhost_user_postcopy_advise(dev, pnd->errp);
864
9ccbfe14
DDAG
865 default:
866 /* We ignore notifications we don't know */
867 break;
868 }
869
870 return 0;
871}
872
5f6f6664
NN
873static int vhost_user_init(struct vhost_dev *dev, void *opaque)
874{
6dcdd06e 875 uint64_t features, protocol_features;
2152f3fe 876 struct vhost_user *u;
dcb10c00
MT
877 int err;
878
5f6f6664
NN
879 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
880
2152f3fe
MAL
881 u = g_new0(struct vhost_user, 1);
882 u->chr = opaque;
4bbeeba0 883 u->slave_fd = -1;
9ccbfe14 884 u->dev = dev;
2152f3fe 885 dev->opaque = u;
5f6f6664 886
21e70425 887 err = vhost_user_get_features(dev, &features);
dcb10c00
MT
888 if (err < 0) {
889 return err;
890 }
891
892 if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) {
893 dev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
894
21e70425 895 err = vhost_user_get_u64(dev, VHOST_USER_GET_PROTOCOL_FEATURES,
6dcdd06e 896 &protocol_features);
dcb10c00
MT
897 if (err < 0) {
898 return err;
899 }
900
6dcdd06e
MC
901 dev->protocol_features =
902 protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK;
21e70425 903 err = vhost_user_set_protocol_features(dev, dev->protocol_features);
dcb10c00
MT
904 if (err < 0) {
905 return err;
906 }
e2051e9e
YL
907
908 /* query the max queues we support if backend supports Multiple Queue */
909 if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) {
21e70425
MAL
910 err = vhost_user_get_u64(dev, VHOST_USER_GET_QUEUE_NUM,
911 &dev->max_queues);
e2051e9e
YL
912 if (err < 0) {
913 return err;
914 }
915 }
6dcdd06e
MC
916
917 if (virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM) &&
918 !(virtio_has_feature(dev->protocol_features,
919 VHOST_USER_PROTOCOL_F_SLAVE_REQ) &&
920 virtio_has_feature(dev->protocol_features,
921 VHOST_USER_PROTOCOL_F_REPLY_ACK))) {
922 error_report("IOMMU support requires reply-ack and "
923 "slave-req protocol features.");
924 return -1;
925 }
dcb10c00
MT
926 }
927
d2fc4402
MAL
928 if (dev->migration_blocker == NULL &&
929 !virtio_has_feature(dev->protocol_features,
930 VHOST_USER_PROTOCOL_F_LOG_SHMFD)) {
931 error_setg(&dev->migration_blocker,
932 "Migration disabled: vhost-user backend lacks "
933 "VHOST_USER_PROTOCOL_F_LOG_SHMFD feature.");
934 }
935
4bbeeba0
MAL
936 err = vhost_setup_slave_channel(dev);
937 if (err < 0) {
938 return err;
939 }
940
9ccbfe14
DDAG
941 u->postcopy_notifier.notify = vhost_user_postcopy_notifier;
942 postcopy_add_notifier(&u->postcopy_notifier);
943
5f6f6664
NN
944 return 0;
945}
946
947static int vhost_user_cleanup(struct vhost_dev *dev)
948{
2152f3fe
MAL
949 struct vhost_user *u;
950
5f6f6664
NN
951 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
952
2152f3fe 953 u = dev->opaque;
9ccbfe14
DDAG
954 if (u->postcopy_notifier.notify) {
955 postcopy_remove_notifier(&u->postcopy_notifier);
956 u->postcopy_notifier.notify = NULL;
957 }
4bbeeba0 958 if (u->slave_fd >= 0) {
b9ec9bd4 959 qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
4bbeeba0
MAL
960 close(u->slave_fd);
961 u->slave_fd = -1;
962 }
2152f3fe 963 g_free(u);
5f6f6664
NN
964 dev->opaque = 0;
965
966 return 0;
967}
968
fc57fd99
YL
969static int vhost_user_get_vq_index(struct vhost_dev *dev, int idx)
970{
971 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
972
973 return idx;
974}
975
2ce68e4c
IM
976static int vhost_user_memslots_limit(struct vhost_dev *dev)
977{
978 return VHOST_MEMORY_MAX_NREGIONS;
979}
980
1be0ac21
MAL
981static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
982{
983 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
984
985 return virtio_has_feature(dev->protocol_features,
986 VHOST_USER_PROTOCOL_F_LOG_SHMFD);
987}
988
3e866365
TC
989static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
990{
991 VhostUserMsg msg = { 0 };
3e866365
TC
992
993 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
994
995 /* If guest supports GUEST_ANNOUNCE do nothing */
996 if (virtio_has_feature(dev->acked_features, VIRTIO_NET_F_GUEST_ANNOUNCE)) {
997 return 0;
998 }
999
1000 /* if backend supports VHOST_USER_PROTOCOL_F_RARP ask it to send the RARP */
1001 if (virtio_has_feature(dev->protocol_features,
1002 VHOST_USER_PROTOCOL_F_RARP)) {
24e34754
MT
1003 msg.hdr.request = VHOST_USER_SEND_RARP;
1004 msg.hdr.flags = VHOST_USER_VERSION;
7f4a930e 1005 memcpy((char *)&msg.payload.u64, mac_addr, 6);
24e34754 1006 msg.hdr.size = sizeof(msg.payload.u64);
3e866365 1007
c4843a45 1008 return vhost_user_write(dev, &msg, NULL, 0);
3e866365
TC
1009 }
1010 return -1;
1011}
1012
ffe42cc1
MT
1013static bool vhost_user_can_merge(struct vhost_dev *dev,
1014 uint64_t start1, uint64_t size1,
1015 uint64_t start2, uint64_t size2)
1016{
07bdaa41 1017 ram_addr_t offset;
ffe42cc1
MT
1018 int mfd, rfd;
1019 MemoryRegion *mr;
1020
07bdaa41 1021 mr = memory_region_from_host((void *)(uintptr_t)start1, &offset);
4ff87573 1022 mfd = memory_region_get_fd(mr);
ffe42cc1 1023
07bdaa41 1024 mr = memory_region_from_host((void *)(uintptr_t)start2, &offset);
4ff87573 1025 rfd = memory_region_get_fd(mr);
ffe42cc1
MT
1026
1027 return mfd == rfd;
1028}
1029
c5f048d8
MC
1030static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
1031{
1032 VhostUserMsg msg;
1033 bool reply_supported = virtio_has_feature(dev->protocol_features,
1034 VHOST_USER_PROTOCOL_F_REPLY_ACK);
1035
1036 if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) {
1037 return 0;
1038 }
1039
24e34754 1040 msg.hdr.request = VHOST_USER_NET_SET_MTU;
c5f048d8 1041 msg.payload.u64 = mtu;
24e34754
MT
1042 msg.hdr.size = sizeof(msg.payload.u64);
1043 msg.hdr.flags = VHOST_USER_VERSION;
c5f048d8 1044 if (reply_supported) {
24e34754 1045 msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
c5f048d8
MC
1046 }
1047
1048 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1049 return -1;
1050 }
1051
1052 /* If reply_ack supported, slave has to ack specified MTU is valid */
1053 if (reply_supported) {
3cf7daf8 1054 return process_message_reply(dev, &msg);
c5f048d8
MC
1055 }
1056
1057 return 0;
1058}
1059
6dcdd06e
MC
1060static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev,
1061 struct vhost_iotlb_msg *imsg)
1062{
1063 VhostUserMsg msg = {
24e34754
MT
1064 .hdr.request = VHOST_USER_IOTLB_MSG,
1065 .hdr.size = sizeof(msg.payload.iotlb),
1066 .hdr.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
6dcdd06e
MC
1067 .payload.iotlb = *imsg,
1068 };
1069
1070 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1071 return -EFAULT;
1072 }
1073
1074 return process_message_reply(dev, &msg);
1075}
1076
1077
1078static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled)
1079{
1080 /* No-op as the receive channel is not dedicated to IOTLB messages. */
1081}
1082
4c3e257b
CL
1083static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config,
1084 uint32_t config_len)
1085{
1086 VhostUserMsg msg = {
24e34754
MT
1087 .hdr.request = VHOST_USER_GET_CONFIG,
1088 .hdr.flags = VHOST_USER_VERSION,
1089 .hdr.size = VHOST_USER_CONFIG_HDR_SIZE + config_len,
4c3e257b
CL
1090 };
1091
1092 if (config_len > VHOST_USER_MAX_CONFIG_SIZE) {
1093 return -1;
1094 }
1095
1096 msg.payload.config.offset = 0;
1097 msg.payload.config.size = config_len;
1098 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1099 return -1;
1100 }
1101
1102 if (vhost_user_read(dev, &msg) < 0) {
1103 return -1;
1104 }
1105
24e34754 1106 if (msg.hdr.request != VHOST_USER_GET_CONFIG) {
4c3e257b 1107 error_report("Received unexpected msg type. Expected %d received %d",
24e34754 1108 VHOST_USER_GET_CONFIG, msg.hdr.request);
4c3e257b
CL
1109 return -1;
1110 }
1111
24e34754 1112 if (msg.hdr.size != VHOST_USER_CONFIG_HDR_SIZE + config_len) {
4c3e257b
CL
1113 error_report("Received bad msg size.");
1114 return -1;
1115 }
1116
1117 memcpy(config, msg.payload.config.region, config_len);
1118
1119 return 0;
1120}
1121
1122static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
1123 uint32_t offset, uint32_t size, uint32_t flags)
1124{
1125 uint8_t *p;
1126 bool reply_supported = virtio_has_feature(dev->protocol_features,
1127 VHOST_USER_PROTOCOL_F_REPLY_ACK);
1128
1129 VhostUserMsg msg = {
24e34754
MT
1130 .hdr.request = VHOST_USER_SET_CONFIG,
1131 .hdr.flags = VHOST_USER_VERSION,
1132 .hdr.size = VHOST_USER_CONFIG_HDR_SIZE + size,
4c3e257b
CL
1133 };
1134
1135 if (reply_supported) {
24e34754 1136 msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
4c3e257b
CL
1137 }
1138
1139 if (size > VHOST_USER_MAX_CONFIG_SIZE) {
1140 return -1;
1141 }
1142
1143 msg.payload.config.offset = offset,
1144 msg.payload.config.size = size,
1145 msg.payload.config.flags = flags,
1146 p = msg.payload.config.region;
1147 memcpy(p, data, size);
1148
1149 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1150 return -1;
1151 }
1152
1153 if (reply_supported) {
1154 return process_message_reply(dev, &msg);
1155 }
1156
1157 return 0;
1158}
1159
efbfeb81
GA
1160static int vhost_user_crypto_create_session(struct vhost_dev *dev,
1161 void *session_info,
1162 uint64_t *session_id)
1163{
1164 bool crypto_session = virtio_has_feature(dev->protocol_features,
1165 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
1166 CryptoDevBackendSymSessionInfo *sess_info = session_info;
1167 VhostUserMsg msg = {
1168 .hdr.request = VHOST_USER_CREATE_CRYPTO_SESSION,
1169 .hdr.flags = VHOST_USER_VERSION,
1170 .hdr.size = sizeof(msg.payload.session),
1171 };
1172
1173 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
1174
1175 if (!crypto_session) {
1176 error_report("vhost-user trying to send unhandled ioctl");
1177 return -1;
1178 }
1179
1180 memcpy(&msg.payload.session.session_setup_data, sess_info,
1181 sizeof(CryptoDevBackendSymSessionInfo));
1182 if (sess_info->key_len) {
1183 memcpy(&msg.payload.session.key, sess_info->cipher_key,
1184 sess_info->key_len);
1185 }
1186 if (sess_info->auth_key_len > 0) {
1187 memcpy(&msg.payload.session.auth_key, sess_info->auth_key,
1188 sess_info->auth_key_len);
1189 }
1190 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1191 error_report("vhost_user_write() return -1, create session failed");
1192 return -1;
1193 }
1194
1195 if (vhost_user_read(dev, &msg) < 0) {
1196 error_report("vhost_user_read() return -1, create session failed");
1197 return -1;
1198 }
1199
1200 if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) {
1201 error_report("Received unexpected msg type. Expected %d received %d",
1202 VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request);
1203 return -1;
1204 }
1205
1206 if (msg.hdr.size != sizeof(msg.payload.session)) {
1207 error_report("Received bad msg size.");
1208 return -1;
1209 }
1210
1211 if (msg.payload.session.session_id < 0) {
1212 error_report("Bad session id: %" PRId64 "",
1213 msg.payload.session.session_id);
1214 return -1;
1215 }
1216 *session_id = msg.payload.session.session_id;
1217
1218 return 0;
1219}
1220
1221static int
1222vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id)
1223{
1224 bool crypto_session = virtio_has_feature(dev->protocol_features,
1225 VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
1226 VhostUserMsg msg = {
1227 .hdr.request = VHOST_USER_CLOSE_CRYPTO_SESSION,
1228 .hdr.flags = VHOST_USER_VERSION,
1229 .hdr.size = sizeof(msg.payload.u64),
1230 };
1231 msg.payload.u64 = session_id;
1232
1233 if (!crypto_session) {
1234 error_report("vhost-user trying to send unhandled ioctl");
1235 return -1;
1236 }
1237
1238 if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1239 error_report("vhost_user_write() return -1, close session failed");
1240 return -1;
1241 }
1242
1243 return 0;
1244}
1245
5f6f6664
NN
1246const VhostOps user_ops = {
1247 .backend_type = VHOST_BACKEND_TYPE_USER,
5f6f6664 1248 .vhost_backend_init = vhost_user_init,
fc57fd99 1249 .vhost_backend_cleanup = vhost_user_cleanup,
2ce68e4c 1250 .vhost_backend_memslots_limit = vhost_user_memslots_limit,
21e70425
MAL
1251 .vhost_set_log_base = vhost_user_set_log_base,
1252 .vhost_set_mem_table = vhost_user_set_mem_table,
1253 .vhost_set_vring_addr = vhost_user_set_vring_addr,
1254 .vhost_set_vring_endian = vhost_user_set_vring_endian,
1255 .vhost_set_vring_num = vhost_user_set_vring_num,
1256 .vhost_set_vring_base = vhost_user_set_vring_base,
1257 .vhost_get_vring_base = vhost_user_get_vring_base,
1258 .vhost_set_vring_kick = vhost_user_set_vring_kick,
1259 .vhost_set_vring_call = vhost_user_set_vring_call,
1260 .vhost_set_features = vhost_user_set_features,
1261 .vhost_get_features = vhost_user_get_features,
1262 .vhost_set_owner = vhost_user_set_owner,
1263 .vhost_reset_device = vhost_user_reset_device,
1264 .vhost_get_vq_index = vhost_user_get_vq_index,
1265 .vhost_set_vring_enable = vhost_user_set_vring_enable,
1be0ac21 1266 .vhost_requires_shm_log = vhost_user_requires_shm_log,
3e866365 1267 .vhost_migration_done = vhost_user_migration_done,
ffe42cc1 1268 .vhost_backend_can_merge = vhost_user_can_merge,
c5f048d8 1269 .vhost_net_set_mtu = vhost_user_net_set_mtu,
6dcdd06e
MC
1270 .vhost_set_iotlb_callback = vhost_user_set_iotlb_callback,
1271 .vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg,
4c3e257b
CL
1272 .vhost_get_config = vhost_user_get_config,
1273 .vhost_set_config = vhost_user_set_config,
efbfeb81
GA
1274 .vhost_crypto_create_session = vhost_user_crypto_create_session,
1275 .vhost_crypto_close_session = vhost_user_crypto_close_session,
fc57fd99 1276};