xref: /qemu/tests/vhost-user-bridge.c (revision 37b0b24e)
13595e2ebSVictor Kaplansky /*
23595e2ebSVictor Kaplansky  * Vhost User Bridge
33595e2ebSVictor Kaplansky  *
43595e2ebSVictor Kaplansky  * Copyright (c) 2015 Red Hat, Inc.
53595e2ebSVictor Kaplansky  *
63595e2ebSVictor Kaplansky  * Authors:
73595e2ebSVictor Kaplansky  *  Victor Kaplansky <victork@redhat.com>
83595e2ebSVictor Kaplansky  *
93595e2ebSVictor Kaplansky  * This work is licensed under the terms of the GNU GPL, version 2 or
103595e2ebSVictor Kaplansky  * later.  See the COPYING file in the top-level directory.
113595e2ebSVictor Kaplansky  */
123595e2ebSVictor Kaplansky 
133595e2ebSVictor Kaplansky /*
143595e2ebSVictor Kaplansky  * TODO:
153595e2ebSVictor Kaplansky  *     - main should get parameters from the command line.
165c93c473SVictor Kaplansky  *     - implement all request handlers. Still not implemented:
175c93c473SVictor Kaplansky  *          vubr_get_queue_num_exec()
185c93c473SVictor Kaplansky  *          vubr_send_rarp_exec()
193595e2ebSVictor Kaplansky  *     - test for broken requests and virtqueue.
203595e2ebSVictor Kaplansky  *     - implement features defined by Virtio 1.0 spec.
213595e2ebSVictor Kaplansky  *     - support mergeable buffers and indirect descriptors.
223595e2ebSVictor Kaplansky  *     - implement clean shutdown.
233595e2ebSVictor Kaplansky  *     - implement non-blocking writes to UDP backend.
243595e2ebSVictor Kaplansky  *     - implement polling strategy.
255c93c473SVictor Kaplansky  *     - implement clean starting/stopping of vq processing
265c93c473SVictor Kaplansky  *     - implement clean starting/stopping of used and buffers
275c93c473SVictor Kaplansky  *       dirty page logging.
283595e2ebSVictor Kaplansky  */
293595e2ebSVictor Kaplansky 
305c93c473SVictor Kaplansky #define _FILE_OFFSET_BITS 64
315c93c473SVictor Kaplansky 
32681c28a3SPeter Maydell #include "qemu/osdep.h"
33b7d89466SMarkus Armbruster #include "qemu/atomic.h"
34856dfd8aSMarkus Armbruster #include "qemu/ctype.h"
35e10e798cSMarc-André Lureau #include "qemu/iov.h"
363595e2ebSVictor Kaplansky #include "standard-headers/linux/virtio_net.h"
370df750e9SMarc-André Lureau #include "libvhost-user.h"
383595e2ebSVictor Kaplansky 
393595e2ebSVictor Kaplansky #define VHOST_USER_BRIDGE_DEBUG 1
403595e2ebSVictor Kaplansky 
413595e2ebSVictor Kaplansky #define DPRINT(...) \
423595e2ebSVictor Kaplansky     do { \
433595e2ebSVictor Kaplansky         if (VHOST_USER_BRIDGE_DEBUG) { \
443595e2ebSVictor Kaplansky             printf(__VA_ARGS__); \
453595e2ebSVictor Kaplansky         } \
463595e2ebSVictor Kaplansky     } while (0)
473595e2ebSVictor Kaplansky 
486f5fd837SStefan Hajnoczi enum {
496f5fd837SStefan Hajnoczi     VHOST_USER_BRIDGE_MAX_QUEUES = 8,
506f5fd837SStefan Hajnoczi };
516f5fd837SStefan Hajnoczi 
523595e2ebSVictor Kaplansky typedef void (*CallbackFunc)(int sock, void *ctx);
533595e2ebSVictor Kaplansky 
543595e2ebSVictor Kaplansky typedef struct Event {
553595e2ebSVictor Kaplansky     void *ctx;
563595e2ebSVictor Kaplansky     CallbackFunc callback;
573595e2ebSVictor Kaplansky } Event;
583595e2ebSVictor Kaplansky 
593595e2ebSVictor Kaplansky typedef struct Dispatcher {
603595e2ebSVictor Kaplansky     int max_sock;
613595e2ebSVictor Kaplansky     fd_set fdset;
623595e2ebSVictor Kaplansky     Event events[FD_SETSIZE];
633595e2ebSVictor Kaplansky } Dispatcher;
643595e2ebSVictor Kaplansky 
65e10e798cSMarc-André Lureau typedef struct VubrDev {
66e10e798cSMarc-André Lureau     VuDev vudev;
67e10e798cSMarc-André Lureau     Dispatcher dispatcher;
68e10e798cSMarc-André Lureau     int backend_udp_sock;
69e10e798cSMarc-André Lureau     struct sockaddr_in backend_udp_dest;
70e10e798cSMarc-André Lureau     int hdrlen;
71e10e798cSMarc-André Lureau     int sock;
72e10e798cSMarc-André Lureau     int ready;
73e10e798cSMarc-André Lureau     int quit;
74e3af2928STiwei Bie     struct {
75e3af2928STiwei Bie         int fd;
76e3af2928STiwei Bie         void *addr;
77e3af2928STiwei Bie         pthread_t thread;
78e3af2928STiwei Bie     } notifier;
79e10e798cSMarc-André Lureau } VubrDev;
80e10e798cSMarc-André Lureau 
813595e2ebSVictor Kaplansky static void
vubr_die(const char * s)823595e2ebSVictor Kaplansky vubr_die(const char *s)
833595e2ebSVictor Kaplansky {
843595e2ebSVictor Kaplansky     perror(s);
853595e2ebSVictor Kaplansky     exit(1);
863595e2ebSVictor Kaplansky }
873595e2ebSVictor Kaplansky 
883595e2ebSVictor Kaplansky static int
dispatcher_init(Dispatcher * dispr)893595e2ebSVictor Kaplansky dispatcher_init(Dispatcher *dispr)
903595e2ebSVictor Kaplansky {
913595e2ebSVictor Kaplansky     FD_ZERO(&dispr->fdset);
923595e2ebSVictor Kaplansky     dispr->max_sock = -1;
933595e2ebSVictor Kaplansky     return 0;
943595e2ebSVictor Kaplansky }
953595e2ebSVictor Kaplansky 
963595e2ebSVictor Kaplansky static int
dispatcher_add(Dispatcher * dispr,int sock,void * ctx,CallbackFunc cb)973595e2ebSVictor Kaplansky dispatcher_add(Dispatcher *dispr, int sock, void *ctx, CallbackFunc cb)
983595e2ebSVictor Kaplansky {
993595e2ebSVictor Kaplansky     if (sock >= FD_SETSIZE) {
1003595e2ebSVictor Kaplansky         fprintf(stderr,
1013595e2ebSVictor Kaplansky                 "Error: Failed to add new event. sock %d should be less than %d\n",
1023595e2ebSVictor Kaplansky                 sock, FD_SETSIZE);
1033595e2ebSVictor Kaplansky         return -1;
1043595e2ebSVictor Kaplansky     }
1053595e2ebSVictor Kaplansky 
1063595e2ebSVictor Kaplansky     dispr->events[sock].ctx = ctx;
1073595e2ebSVictor Kaplansky     dispr->events[sock].callback = cb;
1083595e2ebSVictor Kaplansky 
1093595e2ebSVictor Kaplansky     FD_SET(sock, &dispr->fdset);
1103595e2ebSVictor Kaplansky     if (sock > dispr->max_sock) {
1113595e2ebSVictor Kaplansky         dispr->max_sock = sock;
1123595e2ebSVictor Kaplansky     }
1133595e2ebSVictor Kaplansky     DPRINT("Added sock %d for watching. max_sock: %d\n",
1143595e2ebSVictor Kaplansky            sock, dispr->max_sock);
1153595e2ebSVictor Kaplansky     return 0;
1163595e2ebSVictor Kaplansky }
1173595e2ebSVictor Kaplansky 
1183595e2ebSVictor Kaplansky static int
dispatcher_remove(Dispatcher * dispr,int sock)1193595e2ebSVictor Kaplansky dispatcher_remove(Dispatcher *dispr, int sock)
1203595e2ebSVictor Kaplansky {
1213595e2ebSVictor Kaplansky     if (sock >= FD_SETSIZE) {
1223595e2ebSVictor Kaplansky         fprintf(stderr,
1233595e2ebSVictor Kaplansky                 "Error: Failed to remove event. sock %d should be less than %d\n",
1243595e2ebSVictor Kaplansky                 sock, FD_SETSIZE);
1253595e2ebSVictor Kaplansky         return -1;
1263595e2ebSVictor Kaplansky     }
1273595e2ebSVictor Kaplansky 
1283595e2ebSVictor Kaplansky     FD_CLR(sock, &dispr->fdset);
1296d0b908aSVictor Kaplansky     DPRINT("Sock %d removed from dispatcher watch.\n", sock);
1303595e2ebSVictor Kaplansky     return 0;
1313595e2ebSVictor Kaplansky }
1323595e2ebSVictor Kaplansky 
1333595e2ebSVictor Kaplansky /* timeout in us */
1343595e2ebSVictor Kaplansky static int
dispatcher_wait(Dispatcher * dispr,uint32_t timeout)1353595e2ebSVictor Kaplansky dispatcher_wait(Dispatcher *dispr, uint32_t timeout)
1363595e2ebSVictor Kaplansky {
1373595e2ebSVictor Kaplansky     struct timeval tv;
1383595e2ebSVictor Kaplansky     tv.tv_sec = timeout / 1000000;
1393595e2ebSVictor Kaplansky     tv.tv_usec = timeout % 1000000;
1403595e2ebSVictor Kaplansky 
1413595e2ebSVictor Kaplansky     fd_set fdset = dispr->fdset;
1423595e2ebSVictor Kaplansky 
1433595e2ebSVictor Kaplansky     /* wait until some of sockets become readable. */
1443595e2ebSVictor Kaplansky     int rc = select(dispr->max_sock + 1, &fdset, 0, 0, &tv);
1453595e2ebSVictor Kaplansky 
1463595e2ebSVictor Kaplansky     if (rc == -1) {
1473595e2ebSVictor Kaplansky         vubr_die("select");
1483595e2ebSVictor Kaplansky     }
1493595e2ebSVictor Kaplansky 
1503595e2ebSVictor Kaplansky     /* Timeout */
1513595e2ebSVictor Kaplansky     if (rc == 0) {
1523595e2ebSVictor Kaplansky         return 0;
1533595e2ebSVictor Kaplansky     }
1543595e2ebSVictor Kaplansky 
1553595e2ebSVictor Kaplansky     /* Now call callback for every ready socket. */
1563595e2ebSVictor Kaplansky 
1573595e2ebSVictor Kaplansky     int sock;
1586d0b908aSVictor Kaplansky     for (sock = 0; sock < dispr->max_sock + 1; sock++) {
1596d0b908aSVictor Kaplansky         /* The callback on a socket can remove other sockets from the
1606d0b908aSVictor Kaplansky          * dispatcher, thus we have to check that the socket is
1616d0b908aSVictor Kaplansky          * still not removed from dispatcher's list
1626d0b908aSVictor Kaplansky          */
1636d0b908aSVictor Kaplansky         if (FD_ISSET(sock, &fdset) && FD_ISSET(sock, &dispr->fdset)) {
1643595e2ebSVictor Kaplansky             Event *e = &dispr->events[sock];
1653595e2ebSVictor Kaplansky             e->callback(sock, e->ctx);
1663595e2ebSVictor Kaplansky         }
1676d0b908aSVictor Kaplansky     }
1683595e2ebSVictor Kaplansky 
1693595e2ebSVictor Kaplansky     return 0;
1703595e2ebSVictor Kaplansky }
1713595e2ebSVictor Kaplansky 
1723595e2ebSVictor Kaplansky static void
vubr_handle_tx(VuDev * dev,int qidx)173e10e798cSMarc-André Lureau vubr_handle_tx(VuDev *dev, int qidx)
1743595e2ebSVictor Kaplansky {
175e10e798cSMarc-André Lureau     VuVirtq *vq = vu_get_queue(dev, qidx);
176e10e798cSMarc-André Lureau     VubrDev *vubr = container_of(dev, VubrDev, vudev);
177e10e798cSMarc-André Lureau     int hdrlen = vubr->hdrlen;
178e10e798cSMarc-André Lureau     VuVirtqElement *elem = NULL;
1793595e2ebSVictor Kaplansky 
180e10e798cSMarc-André Lureau     assert(qidx % 2);
1813595e2ebSVictor Kaplansky 
182e10e798cSMarc-André Lureau     for (;;) {
183e10e798cSMarc-André Lureau         ssize_t ret;
184e10e798cSMarc-André Lureau         unsigned int out_num;
185e10e798cSMarc-André Lureau         struct iovec sg[VIRTQUEUE_MAX_SIZE], *out_sg;
1863595e2ebSVictor Kaplansky 
187e10e798cSMarc-André Lureau         elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
188e10e798cSMarc-André Lureau         if (!elem) {
1893595e2ebSVictor Kaplansky             break;
1903595e2ebSVictor Kaplansky         }
191e10e798cSMarc-André Lureau 
192e10e798cSMarc-André Lureau         out_num = elem->out_num;
193e10e798cSMarc-André Lureau         out_sg = elem->out_sg;
194e10e798cSMarc-André Lureau         if (out_num < 1) {
195e10e798cSMarc-André Lureau             fprintf(stderr, "virtio-net header not in first element\n");
196e10e798cSMarc-André Lureau             break;
1973595e2ebSVictor Kaplansky         }
1983595e2ebSVictor Kaplansky         if (VHOST_USER_BRIDGE_DEBUG) {
199e10e798cSMarc-André Lureau             iov_hexdump(out_sg, out_num, stderr, "TX:", 1024);
2003595e2ebSVictor Kaplansky         }
2013595e2ebSVictor Kaplansky 
202e10e798cSMarc-André Lureau         if (hdrlen) {
203e10e798cSMarc-André Lureau             unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
204e10e798cSMarc-André Lureau                                        out_sg, out_num,
205e10e798cSMarc-André Lureau                                        hdrlen, -1);
206e10e798cSMarc-André Lureau             out_num = sg_num;
207e10e798cSMarc-André Lureau             out_sg = sg;
2085c93c473SVictor Kaplansky         }
2095c93c473SVictor Kaplansky 
210e10e798cSMarc-André Lureau         struct msghdr msg = {
211e10e798cSMarc-André Lureau             .msg_name = (struct sockaddr *) &vubr->backend_udp_dest,
212e10e798cSMarc-André Lureau             .msg_namelen = sizeof(struct sockaddr_in),
213e10e798cSMarc-André Lureau             .msg_iov = out_sg,
214e10e798cSMarc-André Lureau             .msg_iovlen = out_num,
215e10e798cSMarc-André Lureau         };
216e10e798cSMarc-André Lureau         do {
217e10e798cSMarc-André Lureau             ret = sendmsg(vubr->backend_udp_sock, &msg, 0);
218e10e798cSMarc-André Lureau         } while (ret == -1 && (errno == EAGAIN || errno == EINTR));
219e10e798cSMarc-André Lureau 
220e10e798cSMarc-André Lureau         if (ret == -1) {
221e10e798cSMarc-André Lureau             vubr_die("sendmsg()");
2223595e2ebSVictor Kaplansky         }
223e10e798cSMarc-André Lureau 
224e10e798cSMarc-André Lureau         vu_queue_push(dev, vq, elem, 0);
225e10e798cSMarc-André Lureau         vu_queue_notify(dev, vq);
226e10e798cSMarc-André Lureau 
227e10e798cSMarc-André Lureau         free(elem);
228e10e798cSMarc-André Lureau         elem = NULL;
229e10e798cSMarc-André Lureau     }
230e10e798cSMarc-André Lureau 
231e10e798cSMarc-André Lureau     free(elem);
2323595e2ebSVictor Kaplansky }
2333595e2ebSVictor Kaplansky 
234277238f9SMarc-André Lureau 
235277238f9SMarc-André Lureau /* this function reverse the effect of iov_discard_front() it must be
236277238f9SMarc-André Lureau  * called with 'front' being the original struct iovec and 'bytes'
237277238f9SMarc-André Lureau  * being the number of bytes you shaved off
238277238f9SMarc-André Lureau  */
2393595e2ebSVictor Kaplansky static void
iov_restore_front(struct iovec * front,struct iovec * iov,size_t bytes)240e10e798cSMarc-André Lureau iov_restore_front(struct iovec *front, struct iovec *iov, size_t bytes)
2415c93c473SVictor Kaplansky {
242e10e798cSMarc-André Lureau     struct iovec *cur;
243e10e798cSMarc-André Lureau 
244277238f9SMarc-André Lureau     for (cur = front; cur != iov; cur++) {
245277238f9SMarc-André Lureau         assert(bytes >= cur->iov_len);
246e10e798cSMarc-André Lureau         bytes -= cur->iov_len;
247e10e798cSMarc-André Lureau     }
248e10e798cSMarc-André Lureau 
249e10e798cSMarc-André Lureau     cur->iov_base -= bytes;
250e10e798cSMarc-André Lureau     cur->iov_len += bytes;
2515c93c473SVictor Kaplansky }
2525c93c473SVictor Kaplansky 
2535c93c473SVictor Kaplansky static void
iov_truncate(struct iovec * iov,unsigned iovc,size_t bytes)254e10e798cSMarc-André Lureau iov_truncate(struct iovec *iov, unsigned iovc, size_t bytes)
2555c93c473SVictor Kaplansky {
256e10e798cSMarc-André Lureau     unsigned i;
2575c93c473SVictor Kaplansky 
258e10e798cSMarc-André Lureau     for (i = 0; i < iovc; i++, iov++) {
259e10e798cSMarc-André Lureau         if (bytes < iov->iov_len) {
260e10e798cSMarc-André Lureau             iov->iov_len = bytes;
2615c93c473SVictor Kaplansky             return;
2625c93c473SVictor Kaplansky         }
2635c93c473SVictor Kaplansky 
264e10e798cSMarc-André Lureau         bytes -= iov->iov_len;
2655c93c473SVictor Kaplansky     }
2665c93c473SVictor Kaplansky 
267e10e798cSMarc-André Lureau     assert(!"couldn't truncate iov");
2683595e2ebSVictor Kaplansky }
2693595e2ebSVictor Kaplansky 
2703595e2ebSVictor Kaplansky static void
vubr_backend_recv_cb(int sock,void * ctx)2713595e2ebSVictor Kaplansky vubr_backend_recv_cb(int sock, void *ctx)
2723595e2ebSVictor Kaplansky {
273e10e798cSMarc-André Lureau     VubrDev *vubr = (VubrDev *) ctx;
274e10e798cSMarc-André Lureau     VuDev *dev = &vubr->vudev;
275e10e798cSMarc-André Lureau     VuVirtq *vq = vu_get_queue(dev, 0);
276e10e798cSMarc-André Lureau     VuVirtqElement *elem = NULL;
277e10e798cSMarc-André Lureau     struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
278e10e798cSMarc-André Lureau     struct virtio_net_hdr_mrg_rxbuf mhdr;
279e10e798cSMarc-André Lureau     unsigned mhdr_cnt = 0;
280e10e798cSMarc-André Lureau     int hdrlen = vubr->hdrlen;
281e10e798cSMarc-André Lureau     int i = 0;
282e10e798cSMarc-André Lureau     struct virtio_net_hdr hdr = {
283e10e798cSMarc-André Lureau         .flags = 0,
284e10e798cSMarc-André Lureau         .gso_type = VIRTIO_NET_HDR_GSO_NONE
285e10e798cSMarc-André Lureau     };
2865c93c473SVictor Kaplansky 
2873595e2ebSVictor Kaplansky     DPRINT("\n\n   ***   IN UDP RECEIVE CALLBACK    ***\n\n");
288a28c393cSVictor Kaplansky     DPRINT("    hdrlen = %d\n", hdrlen);
2893595e2ebSVictor Kaplansky 
290e10e798cSMarc-André Lureau     if (!vu_queue_enabled(dev, vq) ||
29112176528SDr. David Alan Gilbert         !vu_queue_started(dev, vq) ||
292e10e798cSMarc-André Lureau         !vu_queue_avail_bytes(dev, vq, hdrlen, 0)) {
2933595e2ebSVictor Kaplansky         DPRINT("Got UDP packet, but no available descriptors on RX virtq.\n");
2943595e2ebSVictor Kaplansky         return;
2953595e2ebSVictor Kaplansky     }
2963595e2ebSVictor Kaplansky 
297241187c1SEric Blake     while (1) {
298e10e798cSMarc-André Lureau         struct iovec *sg;
299e10e798cSMarc-André Lureau         ssize_t ret, total = 0;
300e10e798cSMarc-André Lureau         unsigned int num;
3013595e2ebSVictor Kaplansky 
302e10e798cSMarc-André Lureau         elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
303e10e798cSMarc-André Lureau         if (!elem) {
304e10e798cSMarc-André Lureau             break;
3053595e2ebSVictor Kaplansky         }
3063595e2ebSVictor Kaplansky 
307e10e798cSMarc-André Lureau         if (elem->in_num < 1) {
308e10e798cSMarc-André Lureau             fprintf(stderr, "virtio-net contains no in buffers\n");
309e10e798cSMarc-André Lureau             break;
3103595e2ebSVictor Kaplansky         }
3113595e2ebSVictor Kaplansky 
312e10e798cSMarc-André Lureau         sg = elem->in_sg;
313e10e798cSMarc-André Lureau         num = elem->in_num;
314e10e798cSMarc-André Lureau         if (i == 0) {
315e10e798cSMarc-André Lureau             if (hdrlen == 12) {
316e10e798cSMarc-André Lureau                 mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
317e10e798cSMarc-André Lureau                                     sg, elem->in_num,
318e10e798cSMarc-André Lureau                                     offsetof(typeof(mhdr), num_buffers),
319e10e798cSMarc-André Lureau                                     sizeof(mhdr.num_buffers));
320e10e798cSMarc-André Lureau             }
321e10e798cSMarc-André Lureau             iov_from_buf(sg, elem->in_num, 0, &hdr, sizeof hdr);
322e10e798cSMarc-André Lureau             total += hdrlen;
323277238f9SMarc-André Lureau             ret = iov_discard_front(&sg, &num, hdrlen);
324277238f9SMarc-André Lureau             assert(ret == hdrlen);
3253595e2ebSVictor Kaplansky         }
3263595e2ebSVictor Kaplansky 
327e10e798cSMarc-André Lureau         struct msghdr msg = {
328e10e798cSMarc-André Lureau             .msg_name = (struct sockaddr *) &vubr->backend_udp_dest,
329e10e798cSMarc-André Lureau             .msg_namelen = sizeof(struct sockaddr_in),
330e10e798cSMarc-André Lureau             .msg_iov = sg,
3318f1d22d9SMarc-André Lureau             .msg_iovlen = num,
332e10e798cSMarc-André Lureau             .msg_flags = MSG_DONTWAIT,
333e10e798cSMarc-André Lureau         };
33437b0b24eSNikita Ivanov         ret = RETRY_ON_EINTR(recvmsg(vubr->backend_udp_sock, &msg, 0));
3355c93c473SVictor Kaplansky 
336e10e798cSMarc-André Lureau         if (i == 0) {
337e10e798cSMarc-André Lureau             iov_restore_front(elem->in_sg, sg, hdrlen);
3383595e2ebSVictor Kaplansky         }
3393595e2ebSVictor Kaplansky 
340e10e798cSMarc-André Lureau         if (ret == -1) {
341e10e798cSMarc-André Lureau             if (errno == EWOULDBLOCK) {
342e10e798cSMarc-André Lureau                 vu_queue_rewind(dev, vq, 1);
343e10e798cSMarc-André Lureau                 break;
344a28c393cSVictor Kaplansky             }
345a28c393cSVictor Kaplansky 
346e10e798cSMarc-André Lureau             vubr_die("recvmsg()");
3473595e2ebSVictor Kaplansky         }
3483595e2ebSVictor Kaplansky 
349e10e798cSMarc-André Lureau         total += ret;
350e10e798cSMarc-André Lureau         iov_truncate(elem->in_sg, elem->in_num, total);
351e10e798cSMarc-André Lureau         vu_queue_fill(dev, vq, elem, total, i++);
352e10e798cSMarc-André Lureau 
353e10e798cSMarc-André Lureau         free(elem);
354e10e798cSMarc-André Lureau         elem = NULL;
355241187c1SEric Blake 
356241187c1SEric Blake         break;        /* could loop if DONTWAIT worked? */
357241187c1SEric Blake     }
358e10e798cSMarc-André Lureau 
359e10e798cSMarc-André Lureau     if (mhdr_cnt) {
360e10e798cSMarc-André Lureau         mhdr.num_buffers = i;
361e10e798cSMarc-André Lureau         iov_from_buf(mhdr_sg, mhdr_cnt,
362e10e798cSMarc-André Lureau                      0,
363e10e798cSMarc-André Lureau                      &mhdr.num_buffers, sizeof mhdr.num_buffers);
3643595e2ebSVictor Kaplansky     }
3653595e2ebSVictor Kaplansky 
366e10e798cSMarc-André Lureau     vu_queue_flush(dev, vq, i);
367e10e798cSMarc-André Lureau     vu_queue_notify(dev, vq);
3685c93c473SVictor Kaplansky 
369e10e798cSMarc-André Lureau     free(elem);
3703595e2ebSVictor Kaplansky }
3713595e2ebSVictor Kaplansky 
3723595e2ebSVictor Kaplansky static void
vubr_receive_cb(int sock,void * ctx)3733595e2ebSVictor Kaplansky vubr_receive_cb(int sock, void *ctx)
3743595e2ebSVictor Kaplansky {
375e10e798cSMarc-André Lureau     VubrDev *vubr = (VubrDev *)ctx;
3763595e2ebSVictor Kaplansky 
377e10e798cSMarc-André Lureau     if (!vu_dispatch(&vubr->vudev)) {
378e10e798cSMarc-André Lureau         fprintf(stderr, "Error while dispatching\n");
3793595e2ebSVictor Kaplansky     }
3803595e2ebSVictor Kaplansky }
3813595e2ebSVictor Kaplansky 
382e10e798cSMarc-André Lureau typedef struct WatchData {
383e10e798cSMarc-André Lureau     VuDev *dev;
384e10e798cSMarc-André Lureau     vu_watch_cb cb;
385e10e798cSMarc-André Lureau     void *data;
386e10e798cSMarc-André Lureau } WatchData;
387e10e798cSMarc-André Lureau 
388e10e798cSMarc-André Lureau static void
watch_cb(int sock,void * ctx)389e10e798cSMarc-André Lureau watch_cb(int sock, void *ctx)
390e10e798cSMarc-André Lureau {
391e10e798cSMarc-André Lureau     struct WatchData *wd = ctx;
392e10e798cSMarc-André Lureau 
393e10e798cSMarc-André Lureau     wd->cb(wd->dev, VU_WATCH_IN, wd->data);
394e10e798cSMarc-André Lureau }
395e10e798cSMarc-André Lureau 
396e10e798cSMarc-André Lureau static void
vubr_set_watch(VuDev * dev,int fd,int condition,vu_watch_cb cb,void * data)397e10e798cSMarc-André Lureau vubr_set_watch(VuDev *dev, int fd, int condition,
398e10e798cSMarc-André Lureau                vu_watch_cb cb, void *data)
399e10e798cSMarc-André Lureau {
400e10e798cSMarc-André Lureau     VubrDev *vubr = container_of(dev, VubrDev, vudev);
401e10e798cSMarc-André Lureau     static WatchData watches[FD_SETSIZE];
402e10e798cSMarc-André Lureau     struct WatchData *wd = &watches[fd];
403e10e798cSMarc-André Lureau 
404e10e798cSMarc-André Lureau     wd->cb = cb;
405e10e798cSMarc-André Lureau     wd->data = data;
406e10e798cSMarc-André Lureau     wd->dev = dev;
407e10e798cSMarc-André Lureau     dispatcher_add(&vubr->dispatcher, fd, wd, watch_cb);
408e10e798cSMarc-André Lureau }
409e10e798cSMarc-André Lureau 
410e10e798cSMarc-André Lureau static void
vubr_remove_watch(VuDev * dev,int fd)411e10e798cSMarc-André Lureau vubr_remove_watch(VuDev *dev, int fd)
412e10e798cSMarc-André Lureau {
413e10e798cSMarc-André Lureau     VubrDev *vubr = container_of(dev, VubrDev, vudev);
414e10e798cSMarc-André Lureau 
415e10e798cSMarc-André Lureau     dispatcher_remove(&vubr->dispatcher, fd);
416e10e798cSMarc-André Lureau }
417e10e798cSMarc-André Lureau 
418e10e798cSMarc-André Lureau static int
vubr_send_rarp_exec(VuDev * dev,VhostUserMsg * vmsg)419e10e798cSMarc-André Lureau vubr_send_rarp_exec(VuDev *dev, VhostUserMsg *vmsg)
420e10e798cSMarc-André Lureau {
421e10e798cSMarc-André Lureau     DPRINT("Function %s() not implemented yet.\n", __func__);
422e10e798cSMarc-André Lureau     return 0;
423e10e798cSMarc-André Lureau }
424e10e798cSMarc-André Lureau 
425e10e798cSMarc-André Lureau static int
vubr_process_msg(VuDev * dev,VhostUserMsg * vmsg,int * do_reply)426e10e798cSMarc-André Lureau vubr_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
427e10e798cSMarc-André Lureau {
428e10e798cSMarc-André Lureau     switch (vmsg->request) {
429e10e798cSMarc-André Lureau     case VHOST_USER_SEND_RARP:
430e10e798cSMarc-André Lureau         *do_reply = vubr_send_rarp_exec(dev, vmsg);
431e10e798cSMarc-André Lureau         return 1;
432e10e798cSMarc-André Lureau     default:
433e10e798cSMarc-André Lureau         /* let the library handle the rest */
434e10e798cSMarc-André Lureau         return 0;
435e10e798cSMarc-André Lureau     }
436e10e798cSMarc-André Lureau 
437e10e798cSMarc-André Lureau     return 0;
438e10e798cSMarc-André Lureau }
439e10e798cSMarc-André Lureau 
440e10e798cSMarc-André Lureau static void
vubr_set_features(VuDev * dev,uint64_t features)441e10e798cSMarc-André Lureau vubr_set_features(VuDev *dev, uint64_t features)
442e10e798cSMarc-André Lureau {
443e10e798cSMarc-André Lureau     VubrDev *vubr = container_of(dev, VubrDev, vudev);
444e10e798cSMarc-André Lureau 
445e10e798cSMarc-André Lureau     if ((features & (1ULL << VIRTIO_F_VERSION_1)) ||
446e10e798cSMarc-André Lureau         (features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) {
447e10e798cSMarc-André Lureau         vubr->hdrlen = 12;
448e10e798cSMarc-André Lureau     } else {
449e10e798cSMarc-André Lureau         vubr->hdrlen = 10;
450e10e798cSMarc-André Lureau     }
451e10e798cSMarc-André Lureau }
452e10e798cSMarc-André Lureau 
453e10e798cSMarc-André Lureau static uint64_t
vubr_get_features(VuDev * dev)454e10e798cSMarc-André Lureau vubr_get_features(VuDev *dev)
455e10e798cSMarc-André Lureau {
456e10e798cSMarc-André Lureau     return 1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE |
457e3af2928STiwei Bie         1ULL << VIRTIO_NET_F_MRG_RXBUF |
458e3af2928STiwei Bie         1ULL << VIRTIO_F_VERSION_1;
459e10e798cSMarc-André Lureau }
460e10e798cSMarc-André Lureau 
461e10e798cSMarc-André Lureau static void
vubr_queue_set_started(VuDev * dev,int qidx,bool started)462e10e798cSMarc-André Lureau vubr_queue_set_started(VuDev *dev, int qidx, bool started)
463e10e798cSMarc-André Lureau {
464e3af2928STiwei Bie     VubrDev *vubr = container_of(dev, VubrDev, vudev);
465e10e798cSMarc-André Lureau     VuVirtq *vq = vu_get_queue(dev, qidx);
466e10e798cSMarc-André Lureau 
467e3af2928STiwei Bie     if (started && vubr->notifier.fd >= 0) {
468e3af2928STiwei Bie         vu_set_queue_host_notifier(dev, vq, vubr->notifier.fd,
4698e3b0cbbSMarc-André Lureau                                    qemu_real_host_page_size(),
4708e3b0cbbSMarc-André Lureau                                    qidx * qemu_real_host_page_size());
471e3af2928STiwei Bie     }
472e3af2928STiwei Bie 
473e10e798cSMarc-André Lureau     if (qidx % 2 == 1) {
474e10e798cSMarc-André Lureau         vu_set_queue_handler(dev, vq, started ? vubr_handle_tx : NULL);
475e10e798cSMarc-André Lureau     }
476e10e798cSMarc-André Lureau }
477e10e798cSMarc-André Lureau 
478e10e798cSMarc-André Lureau static void
vubr_panic(VuDev * dev,const char * msg)479e10e798cSMarc-André Lureau vubr_panic(VuDev *dev, const char *msg)
480e10e798cSMarc-André Lureau {
481e10e798cSMarc-André Lureau     VubrDev *vubr = container_of(dev, VubrDev, vudev);
482e10e798cSMarc-André Lureau 
483e10e798cSMarc-André Lureau     fprintf(stderr, "PANIC: %s\n", msg);
484e10e798cSMarc-André Lureau 
485e10e798cSMarc-André Lureau     dispatcher_remove(&vubr->dispatcher, dev->sock);
486e10e798cSMarc-André Lureau     vubr->quit = 1;
487e10e798cSMarc-André Lureau }
488e10e798cSMarc-André Lureau 
489672339f7SMarc-André Lureau static bool
vubr_queue_is_processed_in_order(VuDev * dev,int qidx)490672339f7SMarc-André Lureau vubr_queue_is_processed_in_order(VuDev *dev, int qidx)
491672339f7SMarc-André Lureau {
492672339f7SMarc-André Lureau     return true;
493672339f7SMarc-André Lureau }
494672339f7SMarc-André Lureau 
495e10e798cSMarc-André Lureau static const VuDevIface vuiface = {
496e10e798cSMarc-André Lureau     .get_features = vubr_get_features,
497e10e798cSMarc-André Lureau     .set_features = vubr_set_features,
498e10e798cSMarc-André Lureau     .process_msg = vubr_process_msg,
499e10e798cSMarc-André Lureau     .queue_set_started = vubr_queue_set_started,
500672339f7SMarc-André Lureau     .queue_is_processed_in_order = vubr_queue_is_processed_in_order,
501e10e798cSMarc-André Lureau };
502e10e798cSMarc-André Lureau 
5033595e2ebSVictor Kaplansky static void
vubr_accept_cb(int sock,void * ctx)5043595e2ebSVictor Kaplansky vubr_accept_cb(int sock, void *ctx)
5053595e2ebSVictor Kaplansky {
5063595e2ebSVictor Kaplansky     VubrDev *dev = (VubrDev *)ctx;
5073595e2ebSVictor Kaplansky     int conn_fd;
5083595e2ebSVictor Kaplansky     struct sockaddr_un un;
5093595e2ebSVictor Kaplansky     socklen_t len = sizeof(un);
5103595e2ebSVictor Kaplansky 
5113595e2ebSVictor Kaplansky     conn_fd = accept(sock, (struct sockaddr *) &un, &len);
5123595e2ebSVictor Kaplansky     if (conn_fd == -1) {
5133595e2ebSVictor Kaplansky         vubr_die("accept()");
5143595e2ebSVictor Kaplansky     }
5153595e2ebSVictor Kaplansky     DPRINT("Got connection from remote peer on sock %d\n", conn_fd);
516e10e798cSMarc-André Lureau 
5176f5fd837SStefan Hajnoczi     if (!vu_init(&dev->vudev,
5186f5fd837SStefan Hajnoczi                  VHOST_USER_BRIDGE_MAX_QUEUES,
519e10e798cSMarc-André Lureau                  conn_fd,
520e10e798cSMarc-André Lureau                  vubr_panic,
521049f5550SCoiby Xu                  NULL,
522e10e798cSMarc-André Lureau                  vubr_set_watch,
523e10e798cSMarc-André Lureau                  vubr_remove_watch,
5246f5fd837SStefan Hajnoczi                  &vuiface)) {
5256f5fd837SStefan Hajnoczi         fprintf(stderr, "Failed to initialize libvhost-user\n");
5266f5fd837SStefan Hajnoczi         exit(1);
5276f5fd837SStefan Hajnoczi     }
528e10e798cSMarc-André Lureau 
5293595e2ebSVictor Kaplansky     dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb);
53098206d4eSMarc-André Lureau     dispatcher_remove(&dev->dispatcher, sock);
5313595e2ebSVictor Kaplansky }
5323595e2ebSVictor Kaplansky 
5333595e2ebSVictor Kaplansky static VubrDev *
vubr_new(const char * path,bool client)534aef8486eSMarc-André Lureau vubr_new(const char *path, bool client)
5353595e2ebSVictor Kaplansky {
5363595e2ebSVictor Kaplansky     VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev));
5373595e2ebSVictor Kaplansky     struct sockaddr_un un;
538aef8486eSMarc-André Lureau     CallbackFunc cb;
5393595e2ebSVictor Kaplansky     size_t len;
5403595e2ebSVictor Kaplansky 
541f8843514SPeter Maydell     if (strlen(path) >= sizeof(un.sun_path)) {
542f8843514SPeter Maydell         fprintf(stderr, "unix domain socket path '%s' is too long\n", path);
543f8843514SPeter Maydell         exit(1);
544f8843514SPeter Maydell     }
545f8843514SPeter Maydell 
5463595e2ebSVictor Kaplansky     /* Get a UNIX socket. */
5473595e2ebSVictor Kaplansky     dev->sock = socket(AF_UNIX, SOCK_STREAM, 0);
5483595e2ebSVictor Kaplansky     if (dev->sock == -1) {
5493595e2ebSVictor Kaplansky         vubr_die("socket");
5503595e2ebSVictor Kaplansky     }
5513595e2ebSVictor Kaplansky 
552e3af2928STiwei Bie     dev->notifier.fd = -1;
553e3af2928STiwei Bie 
5543595e2ebSVictor Kaplansky     un.sun_family = AF_UNIX;
5553595e2ebSVictor Kaplansky     strcpy(un.sun_path, path);
5563595e2ebSVictor Kaplansky     len = sizeof(un.sun_family) + strlen(path);
557aef8486eSMarc-André Lureau 
558aef8486eSMarc-André Lureau     if (!client) {
5593595e2ebSVictor Kaplansky         unlink(path);
5603595e2ebSVictor Kaplansky 
5613595e2ebSVictor Kaplansky         if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) {
5623595e2ebSVictor Kaplansky             vubr_die("bind");
5633595e2ebSVictor Kaplansky         }
5643595e2ebSVictor Kaplansky 
5653595e2ebSVictor Kaplansky         if (listen(dev->sock, 1) == -1) {
5663595e2ebSVictor Kaplansky             vubr_die("listen");
5673595e2ebSVictor Kaplansky         }
568aef8486eSMarc-André Lureau         cb = vubr_accept_cb;
5693595e2ebSVictor Kaplansky 
5703595e2ebSVictor Kaplansky         DPRINT("Waiting for connections on UNIX socket %s ...\n", path);
571aef8486eSMarc-André Lureau     } else {
572aef8486eSMarc-André Lureau         if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
573aef8486eSMarc-André Lureau             vubr_die("connect");
574aef8486eSMarc-André Lureau         }
5756f5fd837SStefan Hajnoczi 
5766f5fd837SStefan Hajnoczi         if (!vu_init(&dev->vudev,
5776f5fd837SStefan Hajnoczi                      VHOST_USER_BRIDGE_MAX_QUEUES,
578e10e798cSMarc-André Lureau                      dev->sock,
579e10e798cSMarc-André Lureau                      vubr_panic,
580049f5550SCoiby Xu                      NULL,
581e10e798cSMarc-André Lureau                      vubr_set_watch,
582e10e798cSMarc-André Lureau                      vubr_remove_watch,
5836f5fd837SStefan Hajnoczi                      &vuiface)) {
5846f5fd837SStefan Hajnoczi             fprintf(stderr, "Failed to initialize libvhost-user\n");
5856f5fd837SStefan Hajnoczi             exit(1);
5866f5fd837SStefan Hajnoczi         }
5876f5fd837SStefan Hajnoczi 
588aef8486eSMarc-André Lureau         cb = vubr_receive_cb;
589aef8486eSMarc-André Lureau     }
590aef8486eSMarc-André Lureau 
591aef8486eSMarc-André Lureau     dispatcher_init(&dev->dispatcher);
592e10e798cSMarc-André Lureau 
593aef8486eSMarc-André Lureau     dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, cb);
594aef8486eSMarc-André Lureau 
5953595e2ebSVictor Kaplansky     return dev;
5963595e2ebSVictor Kaplansky }
5973595e2ebSVictor Kaplansky 
notifier_thread(void * arg)598e3af2928STiwei Bie static void *notifier_thread(void *arg)
599e3af2928STiwei Bie {
600e3af2928STiwei Bie     VuDev *dev = (VuDev *)arg;
601e3af2928STiwei Bie     VubrDev *vubr = container_of(dev, VubrDev, vudev);
6028e3b0cbbSMarc-André Lureau     int pagesize = qemu_real_host_page_size();
603e3af2928STiwei Bie     int qidx;
604e3af2928STiwei Bie 
605e3af2928STiwei Bie     while (true) {
6066f5fd837SStefan Hajnoczi         for (qidx = 0; qidx < VHOST_USER_BRIDGE_MAX_QUEUES; qidx++) {
607e3af2928STiwei Bie             uint16_t *n = vubr->notifier.addr + pagesize * qidx;
608e3af2928STiwei Bie 
609e3af2928STiwei Bie             if (*n == qidx) {
610e3af2928STiwei Bie                 *n = 0xffff;
611e3af2928STiwei Bie                 /* We won't miss notifications if we reset
612e3af2928STiwei Bie                  * the memory first. */
613e3af2928STiwei Bie                 smp_mb();
614e3af2928STiwei Bie 
615e3af2928STiwei Bie                 DPRINT("Got a notification for queue%d via host notifier.\n",
616e3af2928STiwei Bie                        qidx);
617e3af2928STiwei Bie 
618e3af2928STiwei Bie                 if (qidx % 2 == 1) {
619e3af2928STiwei Bie                     vubr_handle_tx(dev, qidx);
620e3af2928STiwei Bie                 }
621e3af2928STiwei Bie             }
622e3af2928STiwei Bie             usleep(1000);
623e3af2928STiwei Bie         }
624e3af2928STiwei Bie     }
625e3af2928STiwei Bie 
626e3af2928STiwei Bie     return NULL;
627e3af2928STiwei Bie }
628e3af2928STiwei Bie 
629e3af2928STiwei Bie static void
vubr_host_notifier_setup(VubrDev * dev)630e3af2928STiwei Bie vubr_host_notifier_setup(VubrDev *dev)
631e3af2928STiwei Bie {
632e3af2928STiwei Bie     pthread_t thread;
633e3af2928STiwei Bie     size_t length;
634e3af2928STiwei Bie     void *addr;
635e3af2928STiwei Bie     int fd;
636e3af2928STiwei Bie 
6378e3b0cbbSMarc-André Lureau     length = qemu_real_host_page_size() * VHOST_USER_BRIDGE_MAX_QUEUES;
638e3af2928STiwei Bie 
639786e46eeSBin Meng     fd = g_file_open_tmp("vubr-XXXXXX", NULL, NULL);
640e3af2928STiwei Bie     if (fd < 0) {
641e3af2928STiwei Bie         vubr_die("mkstemp()");
642e3af2928STiwei Bie     }
643e3af2928STiwei Bie 
644e3af2928STiwei Bie     if (posix_fallocate(fd, 0, length) != 0) {
645e3af2928STiwei Bie         vubr_die("posix_fallocate()");
646e3af2928STiwei Bie     }
647e3af2928STiwei Bie 
648e3af2928STiwei Bie     addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
649e3af2928STiwei Bie     if (addr == MAP_FAILED) {
650e3af2928STiwei Bie         vubr_die("mmap()");
651e3af2928STiwei Bie     }
652e3af2928STiwei Bie 
653e3af2928STiwei Bie     memset(addr, 0xff, length);
654e3af2928STiwei Bie 
655e3af2928STiwei Bie     if (pthread_create(&thread, NULL, notifier_thread, &dev->vudev) != 0) {
656e3af2928STiwei Bie         vubr_die("pthread_create()");
657e3af2928STiwei Bie     }
658e3af2928STiwei Bie 
659e3af2928STiwei Bie     dev->notifier.fd = fd;
660e3af2928STiwei Bie     dev->notifier.addr = addr;
661e3af2928STiwei Bie     dev->notifier.thread = thread;
662e3af2928STiwei Bie }
663e3af2928STiwei Bie 
6643595e2ebSVictor Kaplansky static void
vubr_set_host(struct sockaddr_in * saddr,const char * host)6657cf32491SVictor Kaplansky vubr_set_host(struct sockaddr_in *saddr, const char *host)
6663595e2ebSVictor Kaplansky {
667d18dc3afSMarkus Armbruster     if (qemu_isdigit(host[0])) {
6687cf32491SVictor Kaplansky         if (!inet_aton(host, &saddr->sin_addr)) {
6693595e2ebSVictor Kaplansky             fprintf(stderr, "inet_aton() failed.\n");
6703595e2ebSVictor Kaplansky             exit(1);
6713595e2ebSVictor Kaplansky         }
6727cf32491SVictor Kaplansky     } else {
6737cf32491SVictor Kaplansky         struct hostent *he = gethostbyname(host);
6747cf32491SVictor Kaplansky 
6757cf32491SVictor Kaplansky         if (!he) {
6767cf32491SVictor Kaplansky             fprintf(stderr, "gethostbyname() failed.\n");
6777cf32491SVictor Kaplansky             exit(1);
6787cf32491SVictor Kaplansky         }
6797cf32491SVictor Kaplansky         saddr->sin_addr = *(struct in_addr *)he->h_addr;
6807cf32491SVictor Kaplansky     }
6817cf32491SVictor Kaplansky }
6827cf32491SVictor Kaplansky 
6837cf32491SVictor Kaplansky static void
vubr_backend_udp_setup(VubrDev * dev,const char * local_host,const char * local_port,const char * remote_host,const char * remote_port)6847cf32491SVictor Kaplansky vubr_backend_udp_setup(VubrDev *dev,
6857cf32491SVictor Kaplansky                        const char *local_host,
6867cf32491SVictor Kaplansky                        const char *local_port,
6877cf32491SVictor Kaplansky                        const char *remote_host,
6887cf32491SVictor Kaplansky                        const char *remote_port)
6897cf32491SVictor Kaplansky {
6907cf32491SVictor Kaplansky     int sock;
6917cf32491SVictor Kaplansky     const char *r;
6927cf32491SVictor Kaplansky 
6937cf32491SVictor Kaplansky     int lport, rport;
6947cf32491SVictor Kaplansky 
6957cf32491SVictor Kaplansky     lport = strtol(local_port, (char **)&r, 0);
6967cf32491SVictor Kaplansky     if (r == local_port) {
6977cf32491SVictor Kaplansky         fprintf(stderr, "lport parsing failed.\n");
6987cf32491SVictor Kaplansky         exit(1);
6997cf32491SVictor Kaplansky     }
7007cf32491SVictor Kaplansky 
7017cf32491SVictor Kaplansky     rport = strtol(remote_port, (char **)&r, 0);
7027cf32491SVictor Kaplansky     if (r == remote_port) {
7037cf32491SVictor Kaplansky         fprintf(stderr, "rport parsing failed.\n");
7047cf32491SVictor Kaplansky         exit(1);
7057cf32491SVictor Kaplansky     }
7067cf32491SVictor Kaplansky 
7077cf32491SVictor Kaplansky     struct sockaddr_in si_local = {
7087cf32491SVictor Kaplansky         .sin_family = AF_INET,
7097cf32491SVictor Kaplansky         .sin_port = htons(lport),
7107cf32491SVictor Kaplansky     };
7117cf32491SVictor Kaplansky 
7127cf32491SVictor Kaplansky     vubr_set_host(&si_local, local_host);
7133595e2ebSVictor Kaplansky 
7143595e2ebSVictor Kaplansky     /* setup destination for sends */
7153595e2ebSVictor Kaplansky     dev->backend_udp_dest = (struct sockaddr_in) {
7163595e2ebSVictor Kaplansky         .sin_family = AF_INET,
7177cf32491SVictor Kaplansky         .sin_port = htons(rport),
7183595e2ebSVictor Kaplansky     };
7197cf32491SVictor Kaplansky     vubr_set_host(&dev->backend_udp_dest, remote_host);
7203595e2ebSVictor Kaplansky 
7213595e2ebSVictor Kaplansky     sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
7223595e2ebSVictor Kaplansky     if (sock == -1) {
7233595e2ebSVictor Kaplansky         vubr_die("socket");
7243595e2ebSVictor Kaplansky     }
7253595e2ebSVictor Kaplansky 
7263595e2ebSVictor Kaplansky     if (bind(sock, (struct sockaddr *)&si_local, sizeof(si_local)) == -1) {
7273595e2ebSVictor Kaplansky         vubr_die("bind");
7283595e2ebSVictor Kaplansky     }
7293595e2ebSVictor Kaplansky 
7303595e2ebSVictor Kaplansky     dev->backend_udp_sock = sock;
7313595e2ebSVictor Kaplansky     dispatcher_add(&dev->dispatcher, sock, dev, vubr_backend_recv_cb);
7323595e2ebSVictor Kaplansky     DPRINT("Waiting for data from udp backend on %s:%d...\n",
7337cf32491SVictor Kaplansky            local_host, lport);
7343595e2ebSVictor Kaplansky }
7353595e2ebSVictor Kaplansky 
7363595e2ebSVictor Kaplansky static void
vubr_run(VubrDev * dev)7373595e2ebSVictor Kaplansky vubr_run(VubrDev *dev)
7383595e2ebSVictor Kaplansky {
739e10e798cSMarc-André Lureau     while (!dev->quit) {
7403595e2ebSVictor Kaplansky         /* timeout 200ms */
7413595e2ebSVictor Kaplansky         dispatcher_wait(&dev->dispatcher, 200000);
7423595e2ebSVictor Kaplansky         /* Here one can try polling strategy. */
7433595e2ebSVictor Kaplansky     }
7443595e2ebSVictor Kaplansky }
7453595e2ebSVictor Kaplansky 
7467cf32491SVictor Kaplansky static int
vubr_parse_host_port(const char ** host,const char ** port,const char * buf)7477cf32491SVictor Kaplansky vubr_parse_host_port(const char **host, const char **port, const char *buf)
7487cf32491SVictor Kaplansky {
7497cf32491SVictor Kaplansky     char *p = strchr(buf, ':');
7507cf32491SVictor Kaplansky 
7517cf32491SVictor Kaplansky     if (!p) {
7527cf32491SVictor Kaplansky         return -1;
7537cf32491SVictor Kaplansky     }
7547cf32491SVictor Kaplansky     *p = '\0';
7557cf32491SVictor Kaplansky     *host = strdup(buf);
7567cf32491SVictor Kaplansky     *port = strdup(p + 1);
7577cf32491SVictor Kaplansky     return 0;
7587cf32491SVictor Kaplansky }
7597cf32491SVictor Kaplansky 
7607cf32491SVictor Kaplansky #define DEFAULT_UD_SOCKET "/tmp/vubr.sock"
7617cf32491SVictor Kaplansky #define DEFAULT_LHOST "127.0.0.1"
7627cf32491SVictor Kaplansky #define DEFAULT_LPORT "4444"
7637cf32491SVictor Kaplansky #define DEFAULT_RHOST "127.0.0.1"
7647cf32491SVictor Kaplansky #define DEFAULT_RPORT "5555"
7657cf32491SVictor Kaplansky 
7667cf32491SVictor Kaplansky static const char *ud_socket_path = DEFAULT_UD_SOCKET;
7677cf32491SVictor Kaplansky static const char *lhost = DEFAULT_LHOST;
7687cf32491SVictor Kaplansky static const char *lport = DEFAULT_LPORT;
7697cf32491SVictor Kaplansky static const char *rhost = DEFAULT_RHOST;
7707cf32491SVictor Kaplansky static const char *rport = DEFAULT_RPORT;
7717cf32491SVictor Kaplansky 
7723595e2ebSVictor Kaplansky int
main(int argc,char * argv[])7733595e2ebSVictor Kaplansky main(int argc, char *argv[])
7743595e2ebSVictor Kaplansky {
7753595e2ebSVictor Kaplansky     VubrDev *dev;
7767cf32491SVictor Kaplansky     int opt;
777aef8486eSMarc-André Lureau     bool client = false;
778e3af2928STiwei Bie     bool host_notifier = false;
7793595e2ebSVictor Kaplansky 
780e3af2928STiwei Bie     while ((opt = getopt(argc, argv, "l:r:u:cH")) != -1) {
7817cf32491SVictor Kaplansky 
7827cf32491SVictor Kaplansky         switch (opt) {
7837cf32491SVictor Kaplansky         case 'l':
7847cf32491SVictor Kaplansky             if (vubr_parse_host_port(&lhost, &lport, optarg) < 0) {
7857cf32491SVictor Kaplansky                 goto out;
7867cf32491SVictor Kaplansky             }
7877cf32491SVictor Kaplansky             break;
7887cf32491SVictor Kaplansky         case 'r':
7897cf32491SVictor Kaplansky             if (vubr_parse_host_port(&rhost, &rport, optarg) < 0) {
7907cf32491SVictor Kaplansky                 goto out;
7917cf32491SVictor Kaplansky             }
7927cf32491SVictor Kaplansky             break;
7937cf32491SVictor Kaplansky         case 'u':
7947cf32491SVictor Kaplansky             ud_socket_path = strdup(optarg);
7957cf32491SVictor Kaplansky             break;
796aef8486eSMarc-André Lureau         case 'c':
797aef8486eSMarc-André Lureau             client = true;
798aef8486eSMarc-André Lureau             break;
799e3af2928STiwei Bie         case 'H':
800e3af2928STiwei Bie             host_notifier = true;
801e3af2928STiwei Bie             break;
8027cf32491SVictor Kaplansky         default:
8037cf32491SVictor Kaplansky             goto out;
8047cf32491SVictor Kaplansky         }
8057cf32491SVictor Kaplansky     }
8067cf32491SVictor Kaplansky 
807aef8486eSMarc-André Lureau     DPRINT("ud socket: %s (%s)\n", ud_socket_path,
808aef8486eSMarc-André Lureau            client ? "client" : "server");
8097cf32491SVictor Kaplansky     DPRINT("local:     %s:%s\n", lhost, lport);
8107cf32491SVictor Kaplansky     DPRINT("remote:    %s:%s\n", rhost, rport);
8117cf32491SVictor Kaplansky 
812aef8486eSMarc-André Lureau     dev = vubr_new(ud_socket_path, client);
8133595e2ebSVictor Kaplansky     if (!dev) {
8143595e2ebSVictor Kaplansky         return 1;
8153595e2ebSVictor Kaplansky     }
8163595e2ebSVictor Kaplansky 
817e3af2928STiwei Bie     if (host_notifier) {
818e3af2928STiwei Bie         vubr_host_notifier_setup(dev);
819e3af2928STiwei Bie     }
820e3af2928STiwei Bie 
8217cf32491SVictor Kaplansky     vubr_backend_udp_setup(dev, lhost, lport, rhost, rport);
8223595e2ebSVictor Kaplansky     vubr_run(dev);
823e10e798cSMarc-André Lureau 
824e10e798cSMarc-André Lureau     vu_deinit(&dev->vudev);
825e10e798cSMarc-André Lureau 
8263595e2ebSVictor Kaplansky     return 0;
8277cf32491SVictor Kaplansky 
8287cf32491SVictor Kaplansky out:
8297cf32491SVictor Kaplansky     fprintf(stderr, "Usage: %s ", argv[0]);
830e3af2928STiwei Bie     fprintf(stderr, "[-c] [-H] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n");
8316b3dc992SPeter Maydell     fprintf(stderr, "\t-u path to unix domain socket. default: %s\n",
8327cf32491SVictor Kaplansky             DEFAULT_UD_SOCKET);
8337cf32491SVictor Kaplansky     fprintf(stderr, "\t-l local host and port. default: %s:%s\n",
8347cf32491SVictor Kaplansky             DEFAULT_LHOST, DEFAULT_LPORT);
8357cf32491SVictor Kaplansky     fprintf(stderr, "\t-r remote host and port. default: %s:%s\n",
8367cf32491SVictor Kaplansky             DEFAULT_RHOST, DEFAULT_RPORT);
837aef8486eSMarc-André Lureau     fprintf(stderr, "\t-c client mode\n");
838e3af2928STiwei Bie     fprintf(stderr, "\t-H use host notifier\n");
8397cf32491SVictor Kaplansky 
8407cf32491SVictor Kaplansky     return 1;
8413595e2ebSVictor Kaplansky }
842