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 };
334*37b0b24eSNikita 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