]> Git Repo - qemu.git/blobdiff - tests/vhost-user-bridge.c
tests: virtio-9p: add walk operation test
[qemu.git] / tests / vhost-user-bridge.c
index 9fb09f1df463bdfcd3a4486e647973ace2e06358..775e031069e6069675e21453b9eed10bbe597e80 100644 (file)
 
 #define _FILE_OFFSET_BITS 64
 
-#include <stddef.h>
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
+#include "qemu/osdep.h"
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/unistd.h>
-#include <sys/mman.h>
 #include <sys/eventfd.h>
 #include <arpa/inet.h>
-#include <ctype.h>
 #include <netdb.h>
-
 #include <linux/vhost.h>
 
 #include "qemu/atomic.h"
@@ -186,6 +174,8 @@ typedef struct VubrVirtq {
 
 #define VHOST_MEMORY_MAX_NREGIONS    8
 #define VHOST_USER_F_PROTOCOL_FEATURES 30
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1             32
 
 #define VHOST_LOG_PAGE 4096
 
@@ -294,6 +284,7 @@ typedef struct VubrDev {
     struct sockaddr_in backend_udp_dest;
     int ready;
     uint64_t features;
+    int hdrlen;
 } VubrDev;
 
 static const char *vubr_request_str[] = {
@@ -420,7 +411,7 @@ vubr_message_read(int conn_fd, VhostUserMsg *vmsg)
     if (vmsg->size > sizeof(vmsg->payload)) {
         fprintf(stderr,
                 "Error: too big message request: %d, size: vmsg->size: %u, "
-                "while sizeof(vmsg->payload) = %lu\n",
+                "while sizeof(vmsg->payload) = %zu\n",
                 vmsg->request, vmsg->size, sizeof(vmsg->payload));
         exit(1);
     }
@@ -484,7 +475,8 @@ vubr_backend_udp_recvbuf(VubrDev *dev, uint8_t *buf, size_t buflen)
 static void
 vubr_consume_raw_packet(VubrDev *dev, uint8_t *buf, uint32_t len)
 {
-    int hdrlen = sizeof(struct virtio_net_hdr_v1);
+    int hdrlen = dev->hdrlen;
+    DPRINT("    hdrlen = %d\n", dev->hdrlen);
 
     if (VHOST_USER_BRIDGE_DEBUG) {
         print_buffer(buf, len);
@@ -546,6 +538,7 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len)
     struct vring_avail *avail = vq->avail;
     struct vring_used *used = vq->used;
     uint64_t log_guest_addr = vq->log_guest_addr;
+    int32_t remaining_len = len;
 
     unsigned int size = vq->size;
 
@@ -560,36 +553,49 @@ vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len)
     uint16_t d_index = avail->ring[a_index];
 
     int i = d_index;
+    uint32_t written_len = 0;
 
-    DPRINT("Post packet to guest on vq:\n");
-    DPRINT("    size             = %d\n", vq->size);
-    DPRINT("    last_avail_index = %d\n", vq->last_avail_index);
-    DPRINT("    last_used_index  = %d\n", vq->last_used_index);
-    DPRINT("    a_index = %d\n", a_index);
-    DPRINT("    u_index = %d\n", u_index);
-    DPRINT("    d_index = %d\n", d_index);
-    DPRINT("    desc[%d].addr    = 0x%016"PRIx64"\n", i, desc[i].addr);
-    DPRINT("    desc[%d].len     = %d\n", i, desc[i].len);
-    DPRINT("    desc[%d].flags   = %d\n", i, desc[i].flags);
-    DPRINT("    avail->idx = %d\n", avail_index);
-    DPRINT("    used->idx  = %d\n", used->idx);
-
-    if (!(desc[i].flags & VRING_DESC_F_WRITE)) {
-        /* FIXME: we should find writable descriptor. */
-        fprintf(stderr, "Error: descriptor is not writable. Exiting.\n");
-        exit(1);
-    }
+    do {
+        DPRINT("Post packet to guest on vq:\n");
+        DPRINT("    size             = %d\n", vq->size);
+        DPRINT("    last_avail_index = %d\n", vq->last_avail_index);
+        DPRINT("    last_used_index  = %d\n", vq->last_used_index);
+        DPRINT("    a_index = %d\n", a_index);
+        DPRINT("    u_index = %d\n", u_index);
+        DPRINT("    d_index = %d\n", d_index);
+        DPRINT("    desc[%d].addr    = 0x%016"PRIx64"\n", i, desc[i].addr);
+        DPRINT("    desc[%d].len     = %d\n", i, desc[i].len);
+        DPRINT("    desc[%d].flags   = %d\n", i, desc[i].flags);
+        DPRINT("    avail->idx = %d\n", avail_index);
+        DPRINT("    used->idx  = %d\n", used->idx);
+
+        if (!(desc[i].flags & VRING_DESC_F_WRITE)) {
+            /* FIXME: we should find writable descriptor. */
+            fprintf(stderr, "Error: descriptor is not writable. Exiting.\n");
+            exit(1);
+        }
 
-    void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr);
-    uint32_t chunk_len = desc[i].len;
+        void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr);
+        uint32_t chunk_len = desc[i].len;
+        uint32_t chunk_write_len = MIN(remaining_len, chunk_len);
 
-    if (len <= chunk_len) {
-        memcpy(chunk_start, buf, len);
-        vubr_log_write(dev, desc[i].addr, len);
-    } else {
-        fprintf(stderr,
-                "Received too long packet from the backend. Dropping...\n");
-        return;
+        memcpy(chunk_start, buf + written_len, chunk_write_len);
+        vubr_log_write(dev, desc[i].addr, chunk_write_len);
+        remaining_len -= chunk_write_len;
+        written_len += chunk_write_len;
+
+        if ((remaining_len == 0) || !(desc[i].flags & VRING_DESC_F_NEXT)) {
+            break;
+        }
+
+        i = desc[i].next;
+    } while (1);
+
+    if (remaining_len > 0) {
+            fprintf(stderr,
+                    "Too long packet for RX, remaining_len = %d, Dropping...\n",
+                    remaining_len);
+            return;
     }
 
     /* Add descriptor to the used ring. */
@@ -632,7 +638,7 @@ vubr_process_desc(VubrDev *dev, VubrVirtq *vq)
     DPRINT("Chunks: ");
     i = d_index;
     do {
-        void *chunk_start = (void *)gpa_to_va(dev, desc[i].addr);
+        void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr);
         uint32_t chunk_len = desc[i].len;
 
         assert(!(desc[i].flags & VRING_DESC_F_WRITE));
@@ -697,7 +703,7 @@ vubr_backend_recv_cb(int sock, void *ctx)
     VubrVirtq *rx_vq = &dev->vq[0];
     uint8_t buf[4096];
     struct virtio_net_hdr_v1 *hdr = (struct virtio_net_hdr_v1 *)buf;
-    int hdrlen = sizeof(struct virtio_net_hdr_v1);
+    int hdrlen = dev->hdrlen;
     int buflen = sizeof(buf);
     int len;
 
@@ -706,6 +712,7 @@ vubr_backend_recv_cb(int sock, void *ctx)
     }
 
     DPRINT("\n\n   ***   IN UDP RECEIVE CALLBACK    ***\n\n");
+    DPRINT("    hdrlen = %d\n", hdrlen);
 
     uint16_t avail_index = atomic_mb_read(&rx_vq->avail->idx);
 
@@ -717,10 +724,12 @@ vubr_backend_recv_cb(int sock, void *ctx)
         return;
     }
 
+    memset(buf, 0, hdrlen);
+    /* TODO: support mergeable buffers. */
+    if (hdrlen == 12)
+        hdr->num_buffers = 1;
     len = vubr_backend_udp_recvbuf(dev, buf + hdrlen, buflen - hdrlen);
 
-    *hdr = (struct virtio_net_hdr_v1) { };
-    hdr->num_buffers = 1;
     vubr_post_buffer(dev, rx_vq, buf, len + hdrlen);
 }
 
@@ -768,7 +777,15 @@ static int
 vubr_set_features_exec(VubrDev *dev, VhostUserMsg *vmsg)
 {
     DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64);
+
     dev->features = vmsg->payload.u64;
+    if ((dev->features & (1ULL << VIRTIO_F_VERSION_1)) ||
+        (dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) {
+        dev->hdrlen = 12;
+    } else {
+        dev->hdrlen = 10;
+    }
+
     return 0;
 }
 
@@ -841,7 +858,7 @@ vubr_set_mem_table_exec(VubrDev *dev, VhostUserMsg *vmsg)
         if (mmap_addr == MAP_FAILED) {
             vubr_die("mmap");
         }
-        dev_region->mmap_addr = (uint64_t) mmap_addr;
+        dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr;
         DPRINT("    mmap_addr:       0x%016"PRIx64"\n", dev_region->mmap_addr);
 
         close(vmsg->fds[i]);
@@ -915,9 +932,9 @@ vubr_set_vring_addr_exec(VubrDev *dev, VhostUserMsg *vmsg)
     DPRINT("    avail_user_addr:  0x%016llx\n", vra->avail_user_addr);
     DPRINT("    log_guest_addr:   0x%016llx\n", vra->log_guest_addr);
 
-    vq->desc = (struct vring_desc *)qva_to_va(dev, vra->desc_user_addr);
-    vq->used = (struct vring_used *)qva_to_va(dev, vra->used_user_addr);
-    vq->avail = (struct vring_avail *)qva_to_va(dev, vra->avail_user_addr);
+    vq->desc = (struct vring_desc *)(uintptr_t)qva_to_va(dev, vra->desc_user_addr);
+    vq->used = (struct vring_used *)(uintptr_t)qva_to_va(dev, vra->used_user_addr);
+    vq->avail = (struct vring_avail *)(uintptr_t)qva_to_va(dev, vra->avail_user_addr);
     vq->log_guest_addr = vra->log_guest_addr;
 
     DPRINT("Setting virtq addresses:\n");
@@ -926,6 +943,13 @@ vubr_set_vring_addr_exec(VubrDev *dev, VhostUserMsg *vmsg)
     DPRINT("    vring_avail at %p\n", vq->avail);
 
     vq->last_used_index = vq->used->idx;
+
+    if (vq->last_avail_index != vq->used->idx) {
+        DPRINT("Last avail index != used index: %d != %d, resuming",
+               vq->last_avail_index, vq->used->idx);
+        vq->last_avail_index = vq->used->idx;
+    }
+
     return 0;
 }
 
@@ -1184,12 +1208,13 @@ vubr_accept_cb(int sock, void *ctx)
 }
 
 static VubrDev *
-vubr_new(const char *path)
+vubr_new(const char *path, bool client)
 {
     VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev));
     dev->nregions = 0;
     int i;
     struct sockaddr_un un;
+    CallbackFunc cb;
     size_t len;
 
     for (i = 0; i < MAX_NR_VIRTQUEUE; i++) {
@@ -1218,21 +1243,30 @@ vubr_new(const char *path)
     un.sun_family = AF_UNIX;
     strcpy(un.sun_path, path);
     len = sizeof(un.sun_family) + strlen(path);
-    unlink(path);
 
-    if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) {
-        vubr_die("bind");
-    }
+    if (!client) {
+        unlink(path);
+
+        if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) {
+            vubr_die("bind");
+        }
+
+        if (listen(dev->sock, 1) == -1) {
+            vubr_die("listen");
+        }
+        cb = vubr_accept_cb;
 
-    if (listen(dev->sock, 1) == -1) {
-        vubr_die("listen");
+        DPRINT("Waiting for connections on UNIX socket %s ...\n", path);
+    } else {
+        if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
+            vubr_die("connect");
+        }
+        cb = vubr_receive_cb;
     }
 
     dispatcher_init(&dev->dispatcher);
-    dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev,
-                   vubr_accept_cb);
+    dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, cb);
 
-    DPRINT("Waiting for connections on UNIX socket %s ...\n", path);
     return dev;
 }
 
@@ -1349,8 +1383,9 @@ main(int argc, char *argv[])
 {
     VubrDev *dev;
     int opt;
+    bool client = false;
 
-    while ((opt = getopt(argc, argv, "l:r:u:")) != -1) {
+    while ((opt = getopt(argc, argv, "l:r:u:c")) != -1) {
 
         switch (opt) {
         case 'l':
@@ -1366,16 +1401,20 @@ main(int argc, char *argv[])
         case 'u':
             ud_socket_path = strdup(optarg);
             break;
+        case 'c':
+            client = true;
+            break;
         default:
             goto out;
         }
     }
 
-    DPRINT("ud socket: %s\n", ud_socket_path);
+    DPRINT("ud socket: %s (%s)\n", ud_socket_path,
+           client ? "client" : "server");
     DPRINT("local:     %s:%s\n", lhost, lport);
     DPRINT("remote:    %s:%s\n", rhost, rport);
 
-    dev = vubr_new(ud_socket_path);
+    dev = vubr_new(ud_socket_path, client);
     if (!dev) {
         return 1;
     }
@@ -1386,13 +1425,14 @@ main(int argc, char *argv[])
 
 out:
     fprintf(stderr, "Usage: %s ", argv[0]);
-    fprintf(stderr, "[-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n");
+    fprintf(stderr, "[-c] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n");
     fprintf(stderr, "\t-u path to unix doman socket. default: %s\n",
             DEFAULT_UD_SOCKET);
     fprintf(stderr, "\t-l local host and port. default: %s:%s\n",
             DEFAULT_LHOST, DEFAULT_LPORT);
     fprintf(stderr, "\t-r remote host and port. default: %s:%s\n",
             DEFAULT_RHOST, DEFAULT_RPORT);
+    fprintf(stderr, "\t-c client mode\n");
 
     return 1;
 }
This page took 0.034321 seconds and 4 git commands to generate.