qemu/contrib/libvhost-user/libvhost-user.h
<<
>>
Prefs
   1/*
   2 * Vhost User library
   3 *
   4 * Copyright (c) 2016 Red Hat, Inc.
   5 *
   6 * Authors:
   7 *  Victor Kaplansky <victork@redhat.com>
   8 *  Marc-André Lureau <mlureau@redhat.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or
  11 * later.  See the COPYING file in the top-level directory.
  12 */
  13
  14#ifndef LIBVHOST_USER_H
  15#define LIBVHOST_USER_H
  16
  17#include <stdint.h>
  18#include <stdbool.h>
  19#include <stddef.h>
  20#include <sys/poll.h>
  21#include <linux/vhost.h>
  22#include "standard-headers/linux/virtio_ring.h"
  23
  24/* Based on qemu/hw/virtio/vhost-user.c */
  25#define VHOST_USER_F_PROTOCOL_FEATURES 30
  26#define VHOST_LOG_PAGE 4096
  27
  28#define VHOST_MAX_NR_VIRTQUEUE 8
  29#define VIRTQUEUE_MAX_SIZE 1024
  30
  31#define VHOST_MEMORY_MAX_NREGIONS 8
  32
  33typedef enum VhostSetConfigType {
  34    VHOST_SET_CONFIG_TYPE_MASTER = 0,
  35    VHOST_SET_CONFIG_TYPE_MIGRATION = 1,
  36} VhostSetConfigType;
  37
  38/*
  39 * Maximum size of virtio device config space
  40 */
  41#define VHOST_USER_MAX_CONFIG_SIZE 256
  42
  43enum VhostUserProtocolFeature {
  44    VHOST_USER_PROTOCOL_F_MQ = 0,
  45    VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
  46    VHOST_USER_PROTOCOL_F_RARP = 2,
  47    VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
  48    VHOST_USER_PROTOCOL_F_NET_MTU = 4,
  49    VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5,
  50    VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
  51    VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
  52    VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
  53    VHOST_USER_PROTOCOL_F_CONFIG = 9,
  54
  55    VHOST_USER_PROTOCOL_F_MAX
  56};
  57
  58#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
  59
  60typedef enum VhostUserRequest {
  61    VHOST_USER_NONE = 0,
  62    VHOST_USER_GET_FEATURES = 1,
  63    VHOST_USER_SET_FEATURES = 2,
  64    VHOST_USER_SET_OWNER = 3,
  65    VHOST_USER_RESET_OWNER = 4,
  66    VHOST_USER_SET_MEM_TABLE = 5,
  67    VHOST_USER_SET_LOG_BASE = 6,
  68    VHOST_USER_SET_LOG_FD = 7,
  69    VHOST_USER_SET_VRING_NUM = 8,
  70    VHOST_USER_SET_VRING_ADDR = 9,
  71    VHOST_USER_SET_VRING_BASE = 10,
  72    VHOST_USER_GET_VRING_BASE = 11,
  73    VHOST_USER_SET_VRING_KICK = 12,
  74    VHOST_USER_SET_VRING_CALL = 13,
  75    VHOST_USER_SET_VRING_ERR = 14,
  76    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
  77    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
  78    VHOST_USER_GET_QUEUE_NUM = 17,
  79    VHOST_USER_SET_VRING_ENABLE = 18,
  80    VHOST_USER_SEND_RARP = 19,
  81    VHOST_USER_NET_SET_MTU = 20,
  82    VHOST_USER_SET_SLAVE_REQ_FD = 21,
  83    VHOST_USER_IOTLB_MSG = 22,
  84    VHOST_USER_SET_VRING_ENDIAN = 23,
  85    VHOST_USER_GET_CONFIG = 24,
  86    VHOST_USER_SET_CONFIG = 25,
  87    VHOST_USER_CREATE_CRYPTO_SESSION = 26,
  88    VHOST_USER_CLOSE_CRYPTO_SESSION = 27,
  89    VHOST_USER_POSTCOPY_ADVISE  = 28,
  90    VHOST_USER_POSTCOPY_LISTEN  = 29,
  91    VHOST_USER_POSTCOPY_END     = 30,
  92    VHOST_USER_MAX
  93} VhostUserRequest;
  94
  95typedef struct VhostUserMemoryRegion {
  96    uint64_t guest_phys_addr;
  97    uint64_t memory_size;
  98    uint64_t userspace_addr;
  99    uint64_t mmap_offset;
 100} VhostUserMemoryRegion;
 101
 102typedef struct VhostUserMemory {
 103    uint32_t nregions;
 104    uint32_t padding;
 105    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
 106} VhostUserMemory;
 107
 108typedef struct VhostUserLog {
 109    uint64_t mmap_size;
 110    uint64_t mmap_offset;
 111} VhostUserLog;
 112
 113typedef struct VhostUserConfig {
 114    uint32_t offset;
 115    uint32_t size;
 116    uint32_t flags;
 117    uint8_t region[VHOST_USER_MAX_CONFIG_SIZE];
 118} VhostUserConfig;
 119
 120static VhostUserConfig c __attribute__ ((unused));
 121#define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \
 122                                   + sizeof(c.size) \
 123                                   + sizeof(c.flags))
 124
 125#if defined(_WIN32)
 126# define VU_PACKED __attribute__((gcc_struct, packed))
 127#else
 128# define VU_PACKED __attribute__((packed))
 129#endif
 130
 131typedef struct VhostUserMsg {
 132    VhostUserRequest request;
 133
 134#define VHOST_USER_VERSION_MASK     (0x3)
 135#define VHOST_USER_REPLY_MASK       (0x1 << 2)
 136    uint32_t flags;
 137    uint32_t size; /* the following payload size */
 138
 139    union {
 140#define VHOST_USER_VRING_IDX_MASK   (0xff)
 141#define VHOST_USER_VRING_NOFD_MASK  (0x1 << 8)
 142        uint64_t u64;
 143        struct vhost_vring_state state;
 144        struct vhost_vring_addr addr;
 145        VhostUserMemory memory;
 146        VhostUserLog log;
 147        VhostUserConfig config;
 148    } payload;
 149
 150    int fds[VHOST_MEMORY_MAX_NREGIONS];
 151    int fd_num;
 152    uint8_t *data;
 153} VU_PACKED VhostUserMsg;
 154
 155typedef struct VuDevRegion {
 156    /* Guest Physical address. */
 157    uint64_t gpa;
 158    /* Memory region size. */
 159    uint64_t size;
 160    /* QEMU virtual address (userspace). */
 161    uint64_t qva;
 162    /* Starting offset in our mmaped space. */
 163    uint64_t mmap_offset;
 164    /* Start address of mmaped space. */
 165    uint64_t mmap_addr;
 166} VuDevRegion;
 167
 168typedef struct VuDev VuDev;
 169
 170typedef uint64_t (*vu_get_features_cb) (VuDev *dev);
 171typedef void (*vu_set_features_cb) (VuDev *dev, uint64_t features);
 172typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg,
 173                                  int *do_reply);
 174typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started);
 175typedef bool (*vu_queue_is_processed_in_order_cb) (VuDev *dev, int qidx);
 176typedef int (*vu_get_config_cb) (VuDev *dev, uint8_t *config, uint32_t len);
 177typedef int (*vu_set_config_cb) (VuDev *dev, const uint8_t *data,
 178                                 uint32_t offset, uint32_t size,
 179                                 uint32_t flags);
 180
 181typedef struct VuDevIface {
 182    /* called by VHOST_USER_GET_FEATURES to get the features bitmask */
 183    vu_get_features_cb get_features;
 184    /* enable vhost implementation features */
 185    vu_set_features_cb set_features;
 186    /* get the protocol feature bitmask from the underlying vhost
 187     * implementation */
 188    vu_get_features_cb get_protocol_features;
 189    /* enable protocol features in the underlying vhost implementation. */
 190    vu_set_features_cb set_protocol_features;
 191    /* process_msg is called for each vhost-user message received */
 192    /* skip libvhost-user processing if return value != 0 */
 193    vu_process_msg_cb process_msg;
 194    /* tells when queues can be processed */
 195    vu_queue_set_started_cb queue_set_started;
 196    /*
 197     * If the queue is processed in order, in which case it will be
 198     * resumed to vring.used->idx. This can help to support resuming
 199     * on unmanaged exit/crash.
 200     */
 201    vu_queue_is_processed_in_order_cb queue_is_processed_in_order;
 202    /* get the config space of the device */
 203    vu_get_config_cb get_config;
 204    /* set the config space of the device */
 205    vu_set_config_cb set_config;
 206} VuDevIface;
 207
 208typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx);
 209
 210typedef struct VuRing {
 211    unsigned int num;
 212    struct vring_desc *desc;
 213    struct vring_avail *avail;
 214    struct vring_used *used;
 215    uint64_t log_guest_addr;
 216    uint32_t flags;
 217} VuRing;
 218
 219typedef struct VuVirtq {
 220    VuRing vring;
 221
 222    /* Next head to pop */
 223    uint16_t last_avail_idx;
 224
 225    /* Last avail_idx read from VQ. */
 226    uint16_t shadow_avail_idx;
 227
 228    uint16_t used_idx;
 229
 230    /* Last used index value we have signalled on */
 231    uint16_t signalled_used;
 232
 233    /* Last used index value we have signalled on */
 234    bool signalled_used_valid;
 235
 236    /* Notification enabled? */
 237    bool notification;
 238
 239    int inuse;
 240
 241    vu_queue_handler_cb handler;
 242
 243    int call_fd;
 244    int kick_fd;
 245    int err_fd;
 246    unsigned int enable;
 247    bool started;
 248} VuVirtq;
 249
 250enum VuWatchCondtion {
 251    VU_WATCH_IN = POLLIN,
 252    VU_WATCH_OUT = POLLOUT,
 253    VU_WATCH_PRI = POLLPRI,
 254    VU_WATCH_ERR = POLLERR,
 255    VU_WATCH_HUP = POLLHUP,
 256};
 257
 258typedef void (*vu_panic_cb) (VuDev *dev, const char *err);
 259typedef void (*vu_watch_cb) (VuDev *dev, int condition, void *data);
 260typedef void (*vu_set_watch_cb) (VuDev *dev, int fd, int condition,
 261                                 vu_watch_cb cb, void *data);
 262typedef void (*vu_remove_watch_cb) (VuDev *dev, int fd);
 263
 264struct VuDev {
 265    int sock;
 266    uint32_t nregions;
 267    VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
 268    VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
 269    int log_call_fd;
 270    int slave_fd;
 271    uint64_t log_size;
 272    uint8_t *log_table;
 273    uint64_t features;
 274    uint64_t protocol_features;
 275    bool broken;
 276
 277    /* @set_watch: add or update the given fd to the watch set,
 278     * call cb when condition is met */
 279    vu_set_watch_cb set_watch;
 280
 281    /* @remove_watch: remove the given fd from the watch set */
 282    vu_remove_watch_cb remove_watch;
 283
 284    /* @panic: encountered an unrecoverable error, you may try to
 285     * re-initialize */
 286    vu_panic_cb panic;
 287    const VuDevIface *iface;
 288
 289    /* Postcopy data */
 290    int postcopy_ufd;
 291    bool postcopy_listening;
 292};
 293
 294typedef struct VuVirtqElement {
 295    unsigned int index;
 296    unsigned int out_num;
 297    unsigned int in_num;
 298    struct iovec *in_sg;
 299    struct iovec *out_sg;
 300} VuVirtqElement;
 301
 302/**
 303 * vu_init:
 304 * @dev: a VuDev context
 305 * @socket: the socket connected to vhost-user master
 306 * @panic: a panic callback
 307 * @set_watch: a set_watch callback
 308 * @remove_watch: a remove_watch callback
 309 * @iface: a VuDevIface structure with vhost-user device callbacks
 310 *
 311 * Intializes a VuDev vhost-user context.
 312 **/
 313void vu_init(VuDev *dev,
 314             int socket,
 315             vu_panic_cb panic,
 316             vu_set_watch_cb set_watch,
 317             vu_remove_watch_cb remove_watch,
 318             const VuDevIface *iface);
 319
 320
 321/**
 322 * vu_deinit:
 323 * @dev: a VuDev context
 324 *
 325 * Cleans up the VuDev context
 326 */
 327void vu_deinit(VuDev *dev);
 328
 329/**
 330 * vu_dispatch:
 331 * @dev: a VuDev context
 332 *
 333 * Process one vhost-user message.
 334 *
 335 * Returns: TRUE on success, FALSE on failure.
 336 */
 337bool vu_dispatch(VuDev *dev);
 338
 339/**
 340 * vu_gpa_to_va:
 341 * @dev: a VuDev context
 342 * @plen: guest memory size
 343 * @guest_addr: guest address
 344 *
 345 * Translate a guest address to a pointer. Returns NULL on failure.
 346 */
 347void *vu_gpa_to_va(VuDev *dev, uint64_t *plen, uint64_t guest_addr);
 348
 349/**
 350 * vu_get_queue:
 351 * @dev: a VuDev context
 352 * @qidx: queue index
 353 *
 354 * Returns the queue number @qidx.
 355 */
 356VuVirtq *vu_get_queue(VuDev *dev, int qidx);
 357
 358/**
 359 * vu_set_queue_handler:
 360 * @dev: a VuDev context
 361 * @vq: a VuVirtq queue
 362 * @handler: the queue handler callback
 363 *
 364 * Set the queue handler. This function may be called several times
 365 * for the same queue. If called with NULL @handler, the handler is
 366 * removed.
 367 */
 368void vu_set_queue_handler(VuDev *dev, VuVirtq *vq,
 369                          vu_queue_handler_cb handler);
 370
 371
 372/**
 373 * vu_queue_set_notification:
 374 * @dev: a VuDev context
 375 * @vq: a VuVirtq queue
 376 * @enable: state
 377 *
 378 * Set whether the queue notifies (via event index or interrupt)
 379 */
 380void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);
 381
 382/**
 383 * vu_queue_enabled:
 384 * @dev: a VuDev context
 385 * @vq: a VuVirtq queue
 386 *
 387 * Returns: whether the queue is enabled.
 388 */
 389bool vu_queue_enabled(VuDev *dev, VuVirtq *vq);
 390
 391/**
 392 * vu_queue_started:
 393 * @dev: a VuDev context
 394 * @vq: a VuVirtq queue
 395 *
 396 * Returns: whether the queue is started.
 397 */
 398bool vu_queue_started(const VuDev *dev, const VuVirtq *vq);
 399
 400/**
 401 * vu_queue_empty:
 402 * @dev: a VuDev context
 403 * @vq: a VuVirtq queue
 404 *
 405 * Returns: true if the queue is empty or not ready.
 406 */
 407bool vu_queue_empty(VuDev *dev, VuVirtq *vq);
 408
 409/**
 410 * vu_queue_notify:
 411 * @dev: a VuDev context
 412 * @vq: a VuVirtq queue
 413 *
 414 * Request to notify the queue via callfd (skipped if unnecessary)
 415 */
 416void vu_queue_notify(VuDev *dev, VuVirtq *vq);
 417
 418/**
 419 * vu_queue_pop:
 420 * @dev: a VuDev context
 421 * @vq: a VuVirtq queue
 422 * @sz: the size of struct to return (must be >= VuVirtqElement)
 423 *
 424 * Returns: a VuVirtqElement filled from the queue or NULL. The
 425 * returned element must be free()-d by the caller.
 426 */
 427void *vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz);
 428
 429/**
 430 * vu_queue_rewind:
 431 * @dev: a VuDev context
 432 * @vq: a VuVirtq queue
 433 * @num: number of elements to push back
 434 *
 435 * Pretend that elements weren't popped from the virtqueue.  The next
 436 * virtqueue_pop() will refetch the oldest element.
 437 *
 438 * Returns: true on success, false if @num is greater than the number of in use
 439 * elements.
 440 */
 441bool vu_queue_rewind(VuDev *dev, VuVirtq *vq, unsigned int num);
 442
 443/**
 444 * vu_queue_fill:
 445 * @dev: a VuDev context
 446 * @vq: a VuVirtq queue
 447 * @elem: a VuVirtqElement
 448 * @len: length in bytes to write
 449 * @idx: optional offset for the used ring index (0 in general)
 450 *
 451 * Fill the used ring with @elem element.
 452 */
 453void vu_queue_fill(VuDev *dev, VuVirtq *vq,
 454                   const VuVirtqElement *elem,
 455                   unsigned int len, unsigned int idx);
 456
 457/**
 458 * vu_queue_push:
 459 * @dev: a VuDev context
 460 * @vq: a VuVirtq queue
 461 * @elem: a VuVirtqElement
 462 * @len: length in bytes to write
 463 *
 464 * Helper that combines vu_queue_fill() with a vu_queue_flush().
 465 */
 466void vu_queue_push(VuDev *dev, VuVirtq *vq,
 467                   const VuVirtqElement *elem, unsigned int len);
 468
 469/**
 470 * vu_queue_flush:
 471 * @dev: a VuDev context
 472 * @vq: a VuVirtq queue
 473 * @num: number of elements to flush
 474 *
 475 * Mark the last number of elements as done (used.idx is updated by
 476 * num elements).
 477*/
 478void vu_queue_flush(VuDev *dev, VuVirtq *vq, unsigned int num);
 479
 480/**
 481 * vu_queue_get_avail_bytes:
 482 * @dev: a VuDev context
 483 * @vq: a VuVirtq queue
 484 * @in_bytes: in bytes
 485 * @out_bytes: out bytes
 486 * @max_in_bytes: stop counting after max_in_bytes
 487 * @max_out_bytes: stop counting after max_out_bytes
 488 *
 489 * Count the number of available bytes, up to max_in_bytes/max_out_bytes.
 490 */
 491void vu_queue_get_avail_bytes(VuDev *vdev, VuVirtq *vq, unsigned int *in_bytes,
 492                              unsigned int *out_bytes,
 493                              unsigned max_in_bytes, unsigned max_out_bytes);
 494
 495/**
 496 * vu_queue_avail_bytes:
 497 * @dev: a VuDev context
 498 * @vq: a VuVirtq queue
 499 * @in_bytes: expected in bytes
 500 * @out_bytes: expected out bytes
 501 *
 502 * Returns: true if in_bytes <= in_total && out_bytes <= out_total
 503 */
 504bool vu_queue_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int in_bytes,
 505                          unsigned int out_bytes);
 506
 507#endif /* LIBVHOST_USER_H */
 508