vhost-user-bridge.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /*
  2. * Vhost User Bridge
  3. *
  4. * Copyright (c) 2015 Red Hat, Inc.
  5. *
  6. * Authors:
  7. * Victor Kaplansky <victork@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or
  10. * later. See the COPYING file in the top-level directory.
  11. */
  12. /*
  13. * TODO:
  14. * - main should get parameters from the command line.
  15. * - implement all request handlers. Still not implemented:
  16. * vubr_get_queue_num_exec()
  17. * vubr_send_rarp_exec()
  18. * - test for broken requests and virtqueue.
  19. * - implement features defined by Virtio 1.0 spec.
  20. * - support mergeable buffers and indirect descriptors.
  21. * - implement clean shutdown.
  22. * - implement non-blocking writes to UDP backend.
  23. * - implement polling strategy.
  24. * - implement clean starting/stopping of vq processing
  25. * - implement clean starting/stopping of used and buffers
  26. * dirty page logging.
  27. */
  28. #define _FILE_OFFSET_BITS 64
  29. #include "qemu/osdep.h"
  30. #include "qemu/atomic.h"
  31. #include "qemu/ctype.h"
  32. #include "qemu/iov.h"
  33. #include "standard-headers/linux/virtio_net.h"
  34. #include "libvhost-user.h"
  35. #define VHOST_USER_BRIDGE_DEBUG 1
  36. #define DPRINT(...) \
  37. do { \
  38. if (VHOST_USER_BRIDGE_DEBUG) { \
  39. printf(__VA_ARGS__); \
  40. } \
  41. } while (0)
  42. enum {
  43. VHOST_USER_BRIDGE_MAX_QUEUES = 8,
  44. };
  45. typedef void (*CallbackFunc)(int sock, void *ctx);
  46. typedef struct Event {
  47. void *ctx;
  48. CallbackFunc callback;
  49. } Event;
  50. typedef struct Dispatcher {
  51. int max_sock;
  52. fd_set fdset;
  53. Event events[FD_SETSIZE];
  54. } Dispatcher;
  55. typedef struct VubrDev {
  56. VuDev vudev;
  57. Dispatcher dispatcher;
  58. int backend_udp_sock;
  59. struct sockaddr_in backend_udp_dest;
  60. int hdrlen;
  61. int sock;
  62. int ready;
  63. int quit;
  64. struct {
  65. int fd;
  66. void *addr;
  67. pthread_t thread;
  68. } notifier;
  69. } VubrDev;
  70. static void
  71. vubr_die(const char *s)
  72. {
  73. perror(s);
  74. exit(1);
  75. }
  76. static int
  77. dispatcher_init(Dispatcher *dispr)
  78. {
  79. FD_ZERO(&dispr->fdset);
  80. dispr->max_sock = -1;
  81. return 0;
  82. }
  83. static int
  84. dispatcher_add(Dispatcher *dispr, int sock, void *ctx, CallbackFunc cb)
  85. {
  86. if (sock >= FD_SETSIZE) {
  87. fprintf(stderr,
  88. "Error: Failed to add new event. sock %d should be less than %d\n",
  89. sock, FD_SETSIZE);
  90. return -1;
  91. }
  92. dispr->events[sock].ctx = ctx;
  93. dispr->events[sock].callback = cb;
  94. FD_SET(sock, &dispr->fdset);
  95. if (sock > dispr->max_sock) {
  96. dispr->max_sock = sock;
  97. }
  98. DPRINT("Added sock %d for watching. max_sock: %d\n",
  99. sock, dispr->max_sock);
  100. return 0;
  101. }
  102. static int
  103. dispatcher_remove(Dispatcher *dispr, int sock)
  104. {
  105. if (sock >= FD_SETSIZE) {
  106. fprintf(stderr,
  107. "Error: Failed to remove event. sock %d should be less than %d\n",
  108. sock, FD_SETSIZE);
  109. return -1;
  110. }
  111. FD_CLR(sock, &dispr->fdset);
  112. DPRINT("Sock %d removed from dispatcher watch.\n", sock);
  113. return 0;
  114. }
  115. /* timeout in us */
  116. static int
  117. dispatcher_wait(Dispatcher *dispr, uint32_t timeout)
  118. {
  119. struct timeval tv;
  120. tv.tv_sec = timeout / 1000000;
  121. tv.tv_usec = timeout % 1000000;
  122. fd_set fdset = dispr->fdset;
  123. /* wait until some of sockets become readable. */
  124. int rc = select(dispr->max_sock + 1, &fdset, 0, 0, &tv);
  125. if (rc == -1) {
  126. vubr_die("select");
  127. }
  128. /* Timeout */
  129. if (rc == 0) {
  130. return 0;
  131. }
  132. /* Now call callback for every ready socket. */
  133. int sock;
  134. for (sock = 0; sock < dispr->max_sock + 1; sock++) {
  135. /* The callback on a socket can remove other sockets from the
  136. * dispatcher, thus we have to check that the socket is
  137. * still not removed from dispatcher's list
  138. */
  139. if (FD_ISSET(sock, &fdset) && FD_ISSET(sock, &dispr->fdset)) {
  140. Event *e = &dispr->events[sock];
  141. e->callback(sock, e->ctx);
  142. }
  143. }
  144. return 0;
  145. }
  146. static void
  147. vubr_handle_tx(VuDev *dev, int qidx)
  148. {
  149. VuVirtq *vq = vu_get_queue(dev, qidx);
  150. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  151. int hdrlen = vubr->hdrlen;
  152. VuVirtqElement *elem = NULL;
  153. assert(qidx % 2);
  154. for (;;) {
  155. ssize_t ret;
  156. unsigned int out_num;
  157. struct iovec sg[VIRTQUEUE_MAX_SIZE], *out_sg;
  158. elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
  159. if (!elem) {
  160. break;
  161. }
  162. out_num = elem->out_num;
  163. out_sg = elem->out_sg;
  164. if (out_num < 1) {
  165. fprintf(stderr, "virtio-net header not in first element\n");
  166. break;
  167. }
  168. if (VHOST_USER_BRIDGE_DEBUG) {
  169. iov_hexdump(out_sg, out_num, stderr, "TX:", 1024);
  170. }
  171. if (hdrlen) {
  172. unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
  173. out_sg, out_num,
  174. hdrlen, -1);
  175. out_num = sg_num;
  176. out_sg = sg;
  177. }
  178. struct msghdr msg = {
  179. .msg_name = (struct sockaddr *) &vubr->backend_udp_dest,
  180. .msg_namelen = sizeof(struct sockaddr_in),
  181. .msg_iov = out_sg,
  182. .msg_iovlen = out_num,
  183. };
  184. do {
  185. ret = sendmsg(vubr->backend_udp_sock, &msg, 0);
  186. } while (ret == -1 && (errno == EAGAIN || errno == EINTR));
  187. if (ret == -1) {
  188. vubr_die("sendmsg()");
  189. }
  190. vu_queue_push(dev, vq, elem, 0);
  191. vu_queue_notify(dev, vq);
  192. free(elem);
  193. elem = NULL;
  194. }
  195. free(elem);
  196. }
  197. /* this function reverse the effect of iov_discard_front() it must be
  198. * called with 'front' being the original struct iovec and 'bytes'
  199. * being the number of bytes you shaved off
  200. */
  201. static void
  202. iov_restore_front(struct iovec *front, struct iovec *iov, size_t bytes)
  203. {
  204. struct iovec *cur;
  205. for (cur = front; cur != iov; cur++) {
  206. assert(bytes >= cur->iov_len);
  207. bytes -= cur->iov_len;
  208. }
  209. cur->iov_base -= bytes;
  210. cur->iov_len += bytes;
  211. }
  212. static void
  213. iov_truncate(struct iovec *iov, unsigned iovc, size_t bytes)
  214. {
  215. unsigned i;
  216. for (i = 0; i < iovc; i++, iov++) {
  217. if (bytes < iov->iov_len) {
  218. iov->iov_len = bytes;
  219. return;
  220. }
  221. bytes -= iov->iov_len;
  222. }
  223. assert(!"couldn't truncate iov");
  224. }
  225. static void
  226. vubr_backend_recv_cb(int sock, void *ctx)
  227. {
  228. VubrDev *vubr = (VubrDev *) ctx;
  229. VuDev *dev = &vubr->vudev;
  230. VuVirtq *vq = vu_get_queue(dev, 0);
  231. VuVirtqElement *elem = NULL;
  232. struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
  233. struct virtio_net_hdr_mrg_rxbuf mhdr;
  234. unsigned mhdr_cnt = 0;
  235. int hdrlen = vubr->hdrlen;
  236. int i = 0;
  237. struct virtio_net_hdr hdr = {
  238. .flags = 0,
  239. .gso_type = VIRTIO_NET_HDR_GSO_NONE
  240. };
  241. DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n");
  242. DPRINT(" hdrlen = %d\n", hdrlen);
  243. if (!vu_queue_enabled(dev, vq) ||
  244. !vu_queue_started(dev, vq) ||
  245. !vu_queue_avail_bytes(dev, vq, hdrlen, 0)) {
  246. DPRINT("Got UDP packet, but no available descriptors on RX virtq.\n");
  247. return;
  248. }
  249. while (1) {
  250. struct iovec *sg;
  251. ssize_t ret, total = 0;
  252. unsigned int num;
  253. elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
  254. if (!elem) {
  255. break;
  256. }
  257. if (elem->in_num < 1) {
  258. fprintf(stderr, "virtio-net contains no in buffers\n");
  259. break;
  260. }
  261. sg = elem->in_sg;
  262. num = elem->in_num;
  263. if (i == 0) {
  264. if (hdrlen == 12) {
  265. mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
  266. sg, elem->in_num,
  267. offsetof(typeof(mhdr), num_buffers),
  268. sizeof(mhdr.num_buffers));
  269. }
  270. iov_from_buf(sg, elem->in_num, 0, &hdr, sizeof hdr);
  271. total += hdrlen;
  272. ret = iov_discard_front(&sg, &num, hdrlen);
  273. assert(ret == hdrlen);
  274. }
  275. struct msghdr msg = {
  276. .msg_name = (struct sockaddr *) &vubr->backend_udp_dest,
  277. .msg_namelen = sizeof(struct sockaddr_in),
  278. .msg_iov = sg,
  279. .msg_iovlen = num,
  280. .msg_flags = MSG_DONTWAIT,
  281. };
  282. ret = RETRY_ON_EINTR(recvmsg(vubr->backend_udp_sock, &msg, 0));
  283. if (i == 0) {
  284. iov_restore_front(elem->in_sg, sg, hdrlen);
  285. }
  286. if (ret == -1) {
  287. if (errno == EWOULDBLOCK) {
  288. vu_queue_rewind(dev, vq, 1);
  289. break;
  290. }
  291. vubr_die("recvmsg()");
  292. }
  293. total += ret;
  294. iov_truncate(elem->in_sg, elem->in_num, total);
  295. vu_queue_fill(dev, vq, elem, total, i++);
  296. free(elem);
  297. elem = NULL;
  298. break; /* could loop if DONTWAIT worked? */
  299. }
  300. if (mhdr_cnt) {
  301. mhdr.num_buffers = i;
  302. iov_from_buf(mhdr_sg, mhdr_cnt,
  303. 0,
  304. &mhdr.num_buffers, sizeof mhdr.num_buffers);
  305. }
  306. vu_queue_flush(dev, vq, i);
  307. vu_queue_notify(dev, vq);
  308. free(elem);
  309. }
  310. static void
  311. vubr_receive_cb(int sock, void *ctx)
  312. {
  313. VubrDev *vubr = (VubrDev *)ctx;
  314. if (!vu_dispatch(&vubr->vudev)) {
  315. fprintf(stderr, "Error while dispatching\n");
  316. }
  317. }
  318. typedef struct WatchData {
  319. VuDev *dev;
  320. vu_watch_cb cb;
  321. void *data;
  322. } WatchData;
  323. static void
  324. watch_cb(int sock, void *ctx)
  325. {
  326. struct WatchData *wd = ctx;
  327. wd->cb(wd->dev, VU_WATCH_IN, wd->data);
  328. }
  329. static void
  330. vubr_set_watch(VuDev *dev, int fd, int condition,
  331. vu_watch_cb cb, void *data)
  332. {
  333. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  334. static WatchData watches[FD_SETSIZE];
  335. struct WatchData *wd = &watches[fd];
  336. wd->cb = cb;
  337. wd->data = data;
  338. wd->dev = dev;
  339. dispatcher_add(&vubr->dispatcher, fd, wd, watch_cb);
  340. }
  341. static void
  342. vubr_remove_watch(VuDev *dev, int fd)
  343. {
  344. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  345. dispatcher_remove(&vubr->dispatcher, fd);
  346. }
  347. static int
  348. vubr_send_rarp_exec(VuDev *dev, VhostUserMsg *vmsg)
  349. {
  350. DPRINT("Function %s() not implemented yet.\n", __func__);
  351. return 0;
  352. }
  353. static int
  354. vubr_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
  355. {
  356. switch (vmsg->request) {
  357. case VHOST_USER_SEND_RARP:
  358. *do_reply = vubr_send_rarp_exec(dev, vmsg);
  359. return 1;
  360. default:
  361. /* let the library handle the rest */
  362. return 0;
  363. }
  364. return 0;
  365. }
  366. static void
  367. vubr_set_features(VuDev *dev, uint64_t features)
  368. {
  369. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  370. if ((features & (1ULL << VIRTIO_F_VERSION_1)) ||
  371. (features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) {
  372. vubr->hdrlen = 12;
  373. } else {
  374. vubr->hdrlen = 10;
  375. }
  376. }
  377. static uint64_t
  378. vubr_get_features(VuDev *dev)
  379. {
  380. return 1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE |
  381. 1ULL << VIRTIO_NET_F_MRG_RXBUF |
  382. 1ULL << VIRTIO_F_VERSION_1;
  383. }
  384. static void
  385. vubr_queue_set_started(VuDev *dev, int qidx, bool started)
  386. {
  387. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  388. VuVirtq *vq = vu_get_queue(dev, qidx);
  389. if (started && vubr->notifier.fd >= 0) {
  390. vu_set_queue_host_notifier(dev, vq, vubr->notifier.fd,
  391. qemu_real_host_page_size(),
  392. qidx * qemu_real_host_page_size());
  393. }
  394. if (qidx % 2 == 1) {
  395. vu_set_queue_handler(dev, vq, started ? vubr_handle_tx : NULL);
  396. }
  397. }
  398. static void
  399. vubr_panic(VuDev *dev, const char *msg)
  400. {
  401. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  402. fprintf(stderr, "PANIC: %s\n", msg);
  403. dispatcher_remove(&vubr->dispatcher, dev->sock);
  404. vubr->quit = 1;
  405. }
  406. static bool
  407. vubr_queue_is_processed_in_order(VuDev *dev, int qidx)
  408. {
  409. return true;
  410. }
  411. static const VuDevIface vuiface = {
  412. .get_features = vubr_get_features,
  413. .set_features = vubr_set_features,
  414. .process_msg = vubr_process_msg,
  415. .queue_set_started = vubr_queue_set_started,
  416. .queue_is_processed_in_order = vubr_queue_is_processed_in_order,
  417. };
  418. static void
  419. vubr_accept_cb(int sock, void *ctx)
  420. {
  421. VubrDev *dev = (VubrDev *)ctx;
  422. int conn_fd;
  423. struct sockaddr_un un;
  424. socklen_t len = sizeof(un);
  425. conn_fd = accept(sock, (struct sockaddr *) &un, &len);
  426. if (conn_fd == -1) {
  427. vubr_die("accept()");
  428. }
  429. DPRINT("Got connection from remote peer on sock %d\n", conn_fd);
  430. if (!vu_init(&dev->vudev,
  431. VHOST_USER_BRIDGE_MAX_QUEUES,
  432. conn_fd,
  433. vubr_panic,
  434. NULL,
  435. vubr_set_watch,
  436. vubr_remove_watch,
  437. &vuiface)) {
  438. fprintf(stderr, "Failed to initialize libvhost-user\n");
  439. exit(1);
  440. }
  441. dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb);
  442. dispatcher_remove(&dev->dispatcher, sock);
  443. }
  444. static VubrDev *
  445. vubr_new(const char *path, bool client)
  446. {
  447. VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev));
  448. struct sockaddr_un un;
  449. CallbackFunc cb;
  450. size_t len;
  451. if (strlen(path) >= sizeof(un.sun_path)) {
  452. fprintf(stderr, "unix domain socket path '%s' is too long\n", path);
  453. exit(1);
  454. }
  455. /* Get a UNIX socket. */
  456. dev->sock = socket(AF_UNIX, SOCK_STREAM, 0);
  457. if (dev->sock == -1) {
  458. vubr_die("socket");
  459. }
  460. dev->notifier.fd = -1;
  461. un.sun_family = AF_UNIX;
  462. strcpy(un.sun_path, path);
  463. len = sizeof(un.sun_family) + strlen(path);
  464. if (!client) {
  465. unlink(path);
  466. if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) {
  467. vubr_die("bind");
  468. }
  469. if (listen(dev->sock, 1) == -1) {
  470. vubr_die("listen");
  471. }
  472. cb = vubr_accept_cb;
  473. DPRINT("Waiting for connections on UNIX socket %s ...\n", path);
  474. } else {
  475. if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
  476. vubr_die("connect");
  477. }
  478. if (!vu_init(&dev->vudev,
  479. VHOST_USER_BRIDGE_MAX_QUEUES,
  480. dev->sock,
  481. vubr_panic,
  482. NULL,
  483. vubr_set_watch,
  484. vubr_remove_watch,
  485. &vuiface)) {
  486. fprintf(stderr, "Failed to initialize libvhost-user\n");
  487. exit(1);
  488. }
  489. cb = vubr_receive_cb;
  490. }
  491. dispatcher_init(&dev->dispatcher);
  492. dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, cb);
  493. return dev;
  494. }
  495. static void *notifier_thread(void *arg)
  496. {
  497. VuDev *dev = (VuDev *)arg;
  498. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  499. int pagesize = qemu_real_host_page_size();
  500. int qidx;
  501. while (true) {
  502. for (qidx = 0; qidx < VHOST_USER_BRIDGE_MAX_QUEUES; qidx++) {
  503. uint16_t *n = vubr->notifier.addr + pagesize * qidx;
  504. if (*n == qidx) {
  505. *n = 0xffff;
  506. /* We won't miss notifications if we reset
  507. * the memory first. */
  508. smp_mb();
  509. DPRINT("Got a notification for queue%d via host notifier.\n",
  510. qidx);
  511. if (qidx % 2 == 1) {
  512. vubr_handle_tx(dev, qidx);
  513. }
  514. }
  515. usleep(1000);
  516. }
  517. }
  518. return NULL;
  519. }
  520. static void
  521. vubr_host_notifier_setup(VubrDev *dev)
  522. {
  523. pthread_t thread;
  524. size_t length;
  525. void *addr;
  526. int fd;
  527. length = qemu_real_host_page_size() * VHOST_USER_BRIDGE_MAX_QUEUES;
  528. fd = g_file_open_tmp("vubr-XXXXXX", NULL, NULL);
  529. if (fd < 0) {
  530. vubr_die("mkstemp()");
  531. }
  532. if (posix_fallocate(fd, 0, length) != 0) {
  533. vubr_die("posix_fallocate()");
  534. }
  535. addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  536. if (addr == MAP_FAILED) {
  537. vubr_die("mmap()");
  538. }
  539. memset(addr, 0xff, length);
  540. if (pthread_create(&thread, NULL, notifier_thread, &dev->vudev) != 0) {
  541. vubr_die("pthread_create()");
  542. }
  543. dev->notifier.fd = fd;
  544. dev->notifier.addr = addr;
  545. dev->notifier.thread = thread;
  546. }
  547. static void
  548. vubr_set_host(struct sockaddr_in *saddr, const char *host)
  549. {
  550. if (qemu_isdigit(host[0])) {
  551. if (!inet_aton(host, &saddr->sin_addr)) {
  552. fprintf(stderr, "inet_aton() failed.\n");
  553. exit(1);
  554. }
  555. } else {
  556. struct hostent *he = gethostbyname(host);
  557. if (!he) {
  558. fprintf(stderr, "gethostbyname() failed.\n");
  559. exit(1);
  560. }
  561. saddr->sin_addr = *(struct in_addr *)he->h_addr;
  562. }
  563. }
  564. static void
  565. vubr_backend_udp_setup(VubrDev *dev,
  566. const char *local_host,
  567. const char *local_port,
  568. const char *remote_host,
  569. const char *remote_port)
  570. {
  571. int sock;
  572. const char *r;
  573. int lport, rport;
  574. lport = strtol(local_port, (char **)&r, 0);
  575. if (r == local_port) {
  576. fprintf(stderr, "lport parsing failed.\n");
  577. exit(1);
  578. }
  579. rport = strtol(remote_port, (char **)&r, 0);
  580. if (r == remote_port) {
  581. fprintf(stderr, "rport parsing failed.\n");
  582. exit(1);
  583. }
  584. struct sockaddr_in si_local = {
  585. .sin_family = AF_INET,
  586. .sin_port = htons(lport),
  587. };
  588. vubr_set_host(&si_local, local_host);
  589. /* setup destination for sends */
  590. dev->backend_udp_dest = (struct sockaddr_in) {
  591. .sin_family = AF_INET,
  592. .sin_port = htons(rport),
  593. };
  594. vubr_set_host(&dev->backend_udp_dest, remote_host);
  595. sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  596. if (sock == -1) {
  597. vubr_die("socket");
  598. }
  599. if (bind(sock, (struct sockaddr *)&si_local, sizeof(si_local)) == -1) {
  600. vubr_die("bind");
  601. }
  602. dev->backend_udp_sock = sock;
  603. dispatcher_add(&dev->dispatcher, sock, dev, vubr_backend_recv_cb);
  604. DPRINT("Waiting for data from udp backend on %s:%d...\n",
  605. local_host, lport);
  606. }
  607. static void
  608. vubr_run(VubrDev *dev)
  609. {
  610. while (!dev->quit) {
  611. /* timeout 200ms */
  612. dispatcher_wait(&dev->dispatcher, 200000);
  613. /* Here one can try polling strategy. */
  614. }
  615. }
  616. static int
  617. vubr_parse_host_port(const char **host, const char **port, const char *buf)
  618. {
  619. char *p = strchr(buf, ':');
  620. if (!p) {
  621. return -1;
  622. }
  623. *p = '\0';
  624. *host = strdup(buf);
  625. *port = strdup(p + 1);
  626. return 0;
  627. }
  628. #define DEFAULT_UD_SOCKET "/tmp/vubr.sock"
  629. #define DEFAULT_LHOST "127.0.0.1"
  630. #define DEFAULT_LPORT "4444"
  631. #define DEFAULT_RHOST "127.0.0.1"
  632. #define DEFAULT_RPORT "5555"
  633. static const char *ud_socket_path = DEFAULT_UD_SOCKET;
  634. static const char *lhost = DEFAULT_LHOST;
  635. static const char *lport = DEFAULT_LPORT;
  636. static const char *rhost = DEFAULT_RHOST;
  637. static const char *rport = DEFAULT_RPORT;
  638. int
  639. main(int argc, char *argv[])
  640. {
  641. VubrDev *dev;
  642. int opt;
  643. bool client = false;
  644. bool host_notifier = false;
  645. while ((opt = getopt(argc, argv, "l:r:u:cH")) != -1) {
  646. switch (opt) {
  647. case 'l':
  648. if (vubr_parse_host_port(&lhost, &lport, optarg) < 0) {
  649. goto out;
  650. }
  651. break;
  652. case 'r':
  653. if (vubr_parse_host_port(&rhost, &rport, optarg) < 0) {
  654. goto out;
  655. }
  656. break;
  657. case 'u':
  658. ud_socket_path = strdup(optarg);
  659. break;
  660. case 'c':
  661. client = true;
  662. break;
  663. case 'H':
  664. host_notifier = true;
  665. break;
  666. default:
  667. goto out;
  668. }
  669. }
  670. DPRINT("ud socket: %s (%s)\n", ud_socket_path,
  671. client ? "client" : "server");
  672. DPRINT("local: %s:%s\n", lhost, lport);
  673. DPRINT("remote: %s:%s\n", rhost, rport);
  674. dev = vubr_new(ud_socket_path, client);
  675. if (!dev) {
  676. return 1;
  677. }
  678. if (host_notifier) {
  679. vubr_host_notifier_setup(dev);
  680. }
  681. vubr_backend_udp_setup(dev, lhost, lport, rhost, rport);
  682. vubr_run(dev);
  683. vu_deinit(&dev->vudev);
  684. return 0;
  685. out:
  686. fprintf(stderr, "Usage: %s ", argv[0]);
  687. fprintf(stderr, "[-c] [-H] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n");
  688. fprintf(stderr, "\t-u path to unix domain socket. default: %s\n",
  689. DEFAULT_UD_SOCKET);
  690. fprintf(stderr, "\t-l local host and port. default: %s:%s\n",
  691. DEFAULT_LHOST, DEFAULT_LPORT);
  692. fprintf(stderr, "\t-r remote host and port. default: %s:%s\n",
  693. DEFAULT_RHOST, DEFAULT_RPORT);
  694. fprintf(stderr, "\t-c client mode\n");
  695. fprintf(stderr, "\t-H use host notifier\n");
  696. return 1;
  697. }