2
0

vhost-user-bridge.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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 "contrib/libvhost-user/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. do {
  283. ret = recvmsg(vubr->backend_udp_sock, &msg, 0);
  284. } while (ret == -1 && (errno == EINTR));
  285. if (i == 0) {
  286. iov_restore_front(elem->in_sg, sg, hdrlen);
  287. }
  288. if (ret == -1) {
  289. if (errno == EWOULDBLOCK) {
  290. vu_queue_rewind(dev, vq, 1);
  291. break;
  292. }
  293. vubr_die("recvmsg()");
  294. }
  295. total += ret;
  296. iov_truncate(elem->in_sg, elem->in_num, total);
  297. vu_queue_fill(dev, vq, elem, total, i++);
  298. free(elem);
  299. elem = NULL;
  300. break; /* could loop if DONTWAIT worked? */
  301. }
  302. if (mhdr_cnt) {
  303. mhdr.num_buffers = i;
  304. iov_from_buf(mhdr_sg, mhdr_cnt,
  305. 0,
  306. &mhdr.num_buffers, sizeof mhdr.num_buffers);
  307. }
  308. vu_queue_flush(dev, vq, i);
  309. vu_queue_notify(dev, vq);
  310. free(elem);
  311. }
  312. static void
  313. vubr_receive_cb(int sock, void *ctx)
  314. {
  315. VubrDev *vubr = (VubrDev *)ctx;
  316. if (!vu_dispatch(&vubr->vudev)) {
  317. fprintf(stderr, "Error while dispatching\n");
  318. }
  319. }
  320. typedef struct WatchData {
  321. VuDev *dev;
  322. vu_watch_cb cb;
  323. void *data;
  324. } WatchData;
  325. static void
  326. watch_cb(int sock, void *ctx)
  327. {
  328. struct WatchData *wd = ctx;
  329. wd->cb(wd->dev, VU_WATCH_IN, wd->data);
  330. }
  331. static void
  332. vubr_set_watch(VuDev *dev, int fd, int condition,
  333. vu_watch_cb cb, void *data)
  334. {
  335. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  336. static WatchData watches[FD_SETSIZE];
  337. struct WatchData *wd = &watches[fd];
  338. wd->cb = cb;
  339. wd->data = data;
  340. wd->dev = dev;
  341. dispatcher_add(&vubr->dispatcher, fd, wd, watch_cb);
  342. }
  343. static void
  344. vubr_remove_watch(VuDev *dev, int fd)
  345. {
  346. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  347. dispatcher_remove(&vubr->dispatcher, fd);
  348. }
  349. static int
  350. vubr_send_rarp_exec(VuDev *dev, VhostUserMsg *vmsg)
  351. {
  352. DPRINT("Function %s() not implemented yet.\n", __func__);
  353. return 0;
  354. }
  355. static int
  356. vubr_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
  357. {
  358. switch (vmsg->request) {
  359. case VHOST_USER_SEND_RARP:
  360. *do_reply = vubr_send_rarp_exec(dev, vmsg);
  361. return 1;
  362. default:
  363. /* let the library handle the rest */
  364. return 0;
  365. }
  366. return 0;
  367. }
  368. static void
  369. vubr_set_features(VuDev *dev, uint64_t features)
  370. {
  371. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  372. if ((features & (1ULL << VIRTIO_F_VERSION_1)) ||
  373. (features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) {
  374. vubr->hdrlen = 12;
  375. } else {
  376. vubr->hdrlen = 10;
  377. }
  378. }
  379. static uint64_t
  380. vubr_get_features(VuDev *dev)
  381. {
  382. return 1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE |
  383. 1ULL << VIRTIO_NET_F_MRG_RXBUF |
  384. 1ULL << VIRTIO_F_VERSION_1;
  385. }
  386. static void
  387. vubr_queue_set_started(VuDev *dev, int qidx, bool started)
  388. {
  389. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  390. VuVirtq *vq = vu_get_queue(dev, qidx);
  391. if (started && vubr->notifier.fd >= 0) {
  392. vu_set_queue_host_notifier(dev, vq, vubr->notifier.fd,
  393. qemu_real_host_page_size,
  394. qidx * qemu_real_host_page_size);
  395. }
  396. if (qidx % 2 == 1) {
  397. vu_set_queue_handler(dev, vq, started ? vubr_handle_tx : NULL);
  398. }
  399. }
  400. static void
  401. vubr_panic(VuDev *dev, const char *msg)
  402. {
  403. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  404. fprintf(stderr, "PANIC: %s\n", msg);
  405. dispatcher_remove(&vubr->dispatcher, dev->sock);
  406. vubr->quit = 1;
  407. }
  408. static bool
  409. vubr_queue_is_processed_in_order(VuDev *dev, int qidx)
  410. {
  411. return true;
  412. }
  413. static const VuDevIface vuiface = {
  414. .get_features = vubr_get_features,
  415. .set_features = vubr_set_features,
  416. .process_msg = vubr_process_msg,
  417. .queue_set_started = vubr_queue_set_started,
  418. .queue_is_processed_in_order = vubr_queue_is_processed_in_order,
  419. };
  420. static void
  421. vubr_accept_cb(int sock, void *ctx)
  422. {
  423. VubrDev *dev = (VubrDev *)ctx;
  424. int conn_fd;
  425. struct sockaddr_un un;
  426. socklen_t len = sizeof(un);
  427. conn_fd = accept(sock, (struct sockaddr *) &un, &len);
  428. if (conn_fd == -1) {
  429. vubr_die("accept()");
  430. }
  431. DPRINT("Got connection from remote peer on sock %d\n", conn_fd);
  432. if (!vu_init(&dev->vudev,
  433. VHOST_USER_BRIDGE_MAX_QUEUES,
  434. conn_fd,
  435. vubr_panic,
  436. vubr_set_watch,
  437. vubr_remove_watch,
  438. &vuiface)) {
  439. fprintf(stderr, "Failed to initialize libvhost-user\n");
  440. exit(1);
  441. }
  442. dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb);
  443. dispatcher_remove(&dev->dispatcher, sock);
  444. }
  445. static VubrDev *
  446. vubr_new(const char *path, bool client)
  447. {
  448. VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev));
  449. struct sockaddr_un un;
  450. CallbackFunc cb;
  451. size_t len;
  452. /* Get a UNIX socket. */
  453. dev->sock = socket(AF_UNIX, SOCK_STREAM, 0);
  454. if (dev->sock == -1) {
  455. vubr_die("socket");
  456. }
  457. dev->notifier.fd = -1;
  458. un.sun_family = AF_UNIX;
  459. strcpy(un.sun_path, path);
  460. len = sizeof(un.sun_family) + strlen(path);
  461. if (!client) {
  462. unlink(path);
  463. if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) {
  464. vubr_die("bind");
  465. }
  466. if (listen(dev->sock, 1) == -1) {
  467. vubr_die("listen");
  468. }
  469. cb = vubr_accept_cb;
  470. DPRINT("Waiting for connections on UNIX socket %s ...\n", path);
  471. } else {
  472. if (connect(dev->sock, (struct sockaddr *)&un, len) == -1) {
  473. vubr_die("connect");
  474. }
  475. if (!vu_init(&dev->vudev,
  476. VHOST_USER_BRIDGE_MAX_QUEUES,
  477. dev->sock,
  478. vubr_panic,
  479. vubr_set_watch,
  480. vubr_remove_watch,
  481. &vuiface)) {
  482. fprintf(stderr, "Failed to initialize libvhost-user\n");
  483. exit(1);
  484. }
  485. cb = vubr_receive_cb;
  486. }
  487. dispatcher_init(&dev->dispatcher);
  488. dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, cb);
  489. return dev;
  490. }
  491. static void *notifier_thread(void *arg)
  492. {
  493. VuDev *dev = (VuDev *)arg;
  494. VubrDev *vubr = container_of(dev, VubrDev, vudev);
  495. int pagesize = qemu_real_host_page_size;
  496. int qidx;
  497. while (true) {
  498. for (qidx = 0; qidx < VHOST_USER_BRIDGE_MAX_QUEUES; qidx++) {
  499. uint16_t *n = vubr->notifier.addr + pagesize * qidx;
  500. if (*n == qidx) {
  501. *n = 0xffff;
  502. /* We won't miss notifications if we reset
  503. * the memory first. */
  504. smp_mb();
  505. DPRINT("Got a notification for queue%d via host notifier.\n",
  506. qidx);
  507. if (qidx % 2 == 1) {
  508. vubr_handle_tx(dev, qidx);
  509. }
  510. }
  511. usleep(1000);
  512. }
  513. }
  514. return NULL;
  515. }
  516. static void
  517. vubr_host_notifier_setup(VubrDev *dev)
  518. {
  519. char template[] = "/tmp/vubr-XXXXXX";
  520. pthread_t thread;
  521. size_t length;
  522. void *addr;
  523. int fd;
  524. length = qemu_real_host_page_size * VHOST_USER_BRIDGE_MAX_QUEUES;
  525. fd = mkstemp(template);
  526. if (fd < 0) {
  527. vubr_die("mkstemp()");
  528. }
  529. if (posix_fallocate(fd, 0, length) != 0) {
  530. vubr_die("posix_fallocate()");
  531. }
  532. addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  533. if (addr == MAP_FAILED) {
  534. vubr_die("mmap()");
  535. }
  536. memset(addr, 0xff, length);
  537. if (pthread_create(&thread, NULL, notifier_thread, &dev->vudev) != 0) {
  538. vubr_die("pthread_create()");
  539. }
  540. dev->notifier.fd = fd;
  541. dev->notifier.addr = addr;
  542. dev->notifier.thread = thread;
  543. }
  544. static void
  545. vubr_set_host(struct sockaddr_in *saddr, const char *host)
  546. {
  547. if (qemu_isdigit(host[0])) {
  548. if (!inet_aton(host, &saddr->sin_addr)) {
  549. fprintf(stderr, "inet_aton() failed.\n");
  550. exit(1);
  551. }
  552. } else {
  553. struct hostent *he = gethostbyname(host);
  554. if (!he) {
  555. fprintf(stderr, "gethostbyname() failed.\n");
  556. exit(1);
  557. }
  558. saddr->sin_addr = *(struct in_addr *)he->h_addr;
  559. }
  560. }
  561. static void
  562. vubr_backend_udp_setup(VubrDev *dev,
  563. const char *local_host,
  564. const char *local_port,
  565. const char *remote_host,
  566. const char *remote_port)
  567. {
  568. int sock;
  569. const char *r;
  570. int lport, rport;
  571. lport = strtol(local_port, (char **)&r, 0);
  572. if (r == local_port) {
  573. fprintf(stderr, "lport parsing failed.\n");
  574. exit(1);
  575. }
  576. rport = strtol(remote_port, (char **)&r, 0);
  577. if (r == remote_port) {
  578. fprintf(stderr, "rport parsing failed.\n");
  579. exit(1);
  580. }
  581. struct sockaddr_in si_local = {
  582. .sin_family = AF_INET,
  583. .sin_port = htons(lport),
  584. };
  585. vubr_set_host(&si_local, local_host);
  586. /* setup destination for sends */
  587. dev->backend_udp_dest = (struct sockaddr_in) {
  588. .sin_family = AF_INET,
  589. .sin_port = htons(rport),
  590. };
  591. vubr_set_host(&dev->backend_udp_dest, remote_host);
  592. sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  593. if (sock == -1) {
  594. vubr_die("socket");
  595. }
  596. if (bind(sock, (struct sockaddr *)&si_local, sizeof(si_local)) == -1) {
  597. vubr_die("bind");
  598. }
  599. dev->backend_udp_sock = sock;
  600. dispatcher_add(&dev->dispatcher, sock, dev, vubr_backend_recv_cb);
  601. DPRINT("Waiting for data from udp backend on %s:%d...\n",
  602. local_host, lport);
  603. }
  604. static void
  605. vubr_run(VubrDev *dev)
  606. {
  607. while (!dev->quit) {
  608. /* timeout 200ms */
  609. dispatcher_wait(&dev->dispatcher, 200000);
  610. /* Here one can try polling strategy. */
  611. }
  612. }
  613. static int
  614. vubr_parse_host_port(const char **host, const char **port, const char *buf)
  615. {
  616. char *p = strchr(buf, ':');
  617. if (!p) {
  618. return -1;
  619. }
  620. *p = '\0';
  621. *host = strdup(buf);
  622. *port = strdup(p + 1);
  623. return 0;
  624. }
  625. #define DEFAULT_UD_SOCKET "/tmp/vubr.sock"
  626. #define DEFAULT_LHOST "127.0.0.1"
  627. #define DEFAULT_LPORT "4444"
  628. #define DEFAULT_RHOST "127.0.0.1"
  629. #define DEFAULT_RPORT "5555"
  630. static const char *ud_socket_path = DEFAULT_UD_SOCKET;
  631. static const char *lhost = DEFAULT_LHOST;
  632. static const char *lport = DEFAULT_LPORT;
  633. static const char *rhost = DEFAULT_RHOST;
  634. static const char *rport = DEFAULT_RPORT;
  635. int
  636. main(int argc, char *argv[])
  637. {
  638. VubrDev *dev;
  639. int opt;
  640. bool client = false;
  641. bool host_notifier = false;
  642. while ((opt = getopt(argc, argv, "l:r:u:cH")) != -1) {
  643. switch (opt) {
  644. case 'l':
  645. if (vubr_parse_host_port(&lhost, &lport, optarg) < 0) {
  646. goto out;
  647. }
  648. break;
  649. case 'r':
  650. if (vubr_parse_host_port(&rhost, &rport, optarg) < 0) {
  651. goto out;
  652. }
  653. break;
  654. case 'u':
  655. ud_socket_path = strdup(optarg);
  656. break;
  657. case 'c':
  658. client = true;
  659. break;
  660. case 'H':
  661. host_notifier = true;
  662. break;
  663. default:
  664. goto out;
  665. }
  666. }
  667. DPRINT("ud socket: %s (%s)\n", ud_socket_path,
  668. client ? "client" : "server");
  669. DPRINT("local: %s:%s\n", lhost, lport);
  670. DPRINT("remote: %s:%s\n", rhost, rport);
  671. dev = vubr_new(ud_socket_path, client);
  672. if (!dev) {
  673. return 1;
  674. }
  675. if (host_notifier) {
  676. vubr_host_notifier_setup(dev);
  677. }
  678. vubr_backend_udp_setup(dev, lhost, lport, rhost, rport);
  679. vubr_run(dev);
  680. vu_deinit(&dev->vudev);
  681. return 0;
  682. out:
  683. fprintf(stderr, "Usage: %s ", argv[0]);
  684. fprintf(stderr, "[-c] [-H] [-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n");
  685. fprintf(stderr, "\t-u path to unix doman socket. default: %s\n",
  686. DEFAULT_UD_SOCKET);
  687. fprintf(stderr, "\t-l local host and port. default: %s:%s\n",
  688. DEFAULT_LHOST, DEFAULT_LPORT);
  689. fprintf(stderr, "\t-r remote host and port. default: %s:%s\n",
  690. DEFAULT_RHOST, DEFAULT_RPORT);
  691. fprintf(stderr, "\t-c client mode\n");
  692. fprintf(stderr, "\t-H use host notifier\n");
  693. return 1;
  694. }