vhost-user.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * vhost-user.c
  3. *
  4. * Copyright (c) 2013 Virtual Open Systems Sarl.
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. *
  9. */
  10. #include "qemu/osdep.h"
  11. #include "clients.h"
  12. #include "net/vhost_net.h"
  13. #include "net/vhost-user.h"
  14. #include "hw/virtio/vhost-user.h"
  15. #include "chardev/char-fe.h"
  16. #include "qapi/error.h"
  17. #include "qapi/qapi-commands-net.h"
  18. #include "qemu/config-file.h"
  19. #include "qemu/error-report.h"
  20. #include "qemu/option.h"
  21. #include "trace.h"
  22. typedef struct NetVhostUserState {
  23. NetClientState nc;
  24. CharBackend chr; /* only queue index 0 */
  25. VhostUserState *vhost_user;
  26. VHostNetState *vhost_net;
  27. guint watch;
  28. uint64_t acked_features;
  29. bool started;
  30. } NetVhostUserState;
  31. VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
  32. {
  33. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  34. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  35. return s->vhost_net;
  36. }
  37. uint64_t vhost_user_get_acked_features(NetClientState *nc)
  38. {
  39. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  40. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  41. return s->acked_features;
  42. }
  43. static void vhost_user_stop(int queues, NetClientState *ncs[])
  44. {
  45. NetVhostUserState *s;
  46. int i;
  47. for (i = 0; i < queues; i++) {
  48. assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  49. s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
  50. if (s->vhost_net) {
  51. /* save acked features */
  52. uint64_t features = vhost_net_get_acked_features(s->vhost_net);
  53. if (features) {
  54. s->acked_features = features;
  55. }
  56. vhost_net_cleanup(s->vhost_net);
  57. }
  58. }
  59. }
  60. static int vhost_user_start(int queues, NetClientState *ncs[],
  61. VhostUserState *be)
  62. {
  63. VhostNetOptions options;
  64. struct vhost_net *net = NULL;
  65. NetVhostUserState *s;
  66. int max_queues;
  67. int i;
  68. options.backend_type = VHOST_BACKEND_TYPE_USER;
  69. for (i = 0; i < queues; i++) {
  70. assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  71. s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
  72. options.net_backend = ncs[i];
  73. options.opaque = be;
  74. options.busyloop_timeout = 0;
  75. net = vhost_net_init(&options);
  76. if (!net) {
  77. error_report("failed to init vhost_net for queue %d", i);
  78. goto err;
  79. }
  80. if (i == 0) {
  81. max_queues = vhost_net_get_max_queues(net);
  82. if (queues > max_queues) {
  83. error_report("you are asking more queues than supported: %d",
  84. max_queues);
  85. goto err;
  86. }
  87. }
  88. if (s->vhost_net) {
  89. vhost_net_cleanup(s->vhost_net);
  90. g_free(s->vhost_net);
  91. }
  92. s->vhost_net = net;
  93. }
  94. return 0;
  95. err:
  96. if (net) {
  97. vhost_net_cleanup(net);
  98. g_free(net);
  99. }
  100. vhost_user_stop(i, ncs);
  101. return -1;
  102. }
  103. static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf,
  104. size_t size)
  105. {
  106. /* In case of RARP (message size is 60) notify backup to send a fake RARP.
  107. This fake RARP will be sent by backend only for guest
  108. without GUEST_ANNOUNCE capability.
  109. */
  110. if (size == 60) {
  111. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  112. int r;
  113. static int display_rarp_failure = 1;
  114. char mac_addr[6];
  115. /* extract guest mac address from the RARP message */
  116. memcpy(mac_addr, &buf[6], 6);
  117. r = vhost_net_notify_migration_done(s->vhost_net, mac_addr);
  118. if ((r != 0) && (display_rarp_failure)) {
  119. fprintf(stderr,
  120. "Vhost user backend fails to broadcast fake RARP\n");
  121. fflush(stderr);
  122. display_rarp_failure = 0;
  123. }
  124. }
  125. return size;
  126. }
  127. static void net_vhost_user_cleanup(NetClientState *nc)
  128. {
  129. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  130. if (s->vhost_net) {
  131. vhost_net_cleanup(s->vhost_net);
  132. g_free(s->vhost_net);
  133. s->vhost_net = NULL;
  134. }
  135. if (nc->queue_index == 0) {
  136. if (s->watch) {
  137. g_source_remove(s->watch);
  138. s->watch = 0;
  139. }
  140. qemu_chr_fe_deinit(&s->chr, true);
  141. if (s->vhost_user) {
  142. vhost_user_cleanup(s->vhost_user);
  143. g_free(s->vhost_user);
  144. s->vhost_user = NULL;
  145. }
  146. }
  147. qemu_purge_queued_packets(nc);
  148. }
  149. static bool vhost_user_has_vnet_hdr(NetClientState *nc)
  150. {
  151. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  152. return true;
  153. }
  154. static bool vhost_user_has_ufo(NetClientState *nc)
  155. {
  156. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  157. return true;
  158. }
  159. static NetClientInfo net_vhost_user_info = {
  160. .type = NET_CLIENT_DRIVER_VHOST_USER,
  161. .size = sizeof(NetVhostUserState),
  162. .receive = vhost_user_receive,
  163. .cleanup = net_vhost_user_cleanup,
  164. .has_vnet_hdr = vhost_user_has_vnet_hdr,
  165. .has_ufo = vhost_user_has_ufo,
  166. };
  167. static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
  168. void *opaque)
  169. {
  170. NetVhostUserState *s = opaque;
  171. qemu_chr_fe_disconnect(&s->chr);
  172. return TRUE;
  173. }
  174. static void net_vhost_user_event(void *opaque, int event);
  175. static void chr_closed_bh(void *opaque)
  176. {
  177. const char *name = opaque;
  178. NetClientState *ncs[MAX_QUEUE_NUM];
  179. NetVhostUserState *s;
  180. Error *err = NULL;
  181. int queues;
  182. queues = qemu_find_net_clients_except(name, ncs,
  183. NET_CLIENT_DRIVER_NIC,
  184. MAX_QUEUE_NUM);
  185. assert(queues < MAX_QUEUE_NUM);
  186. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  187. qmp_set_link(name, false, &err);
  188. vhost_user_stop(queues, ncs);
  189. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
  190. NULL, opaque, NULL, true);
  191. if (err) {
  192. error_report_err(err);
  193. }
  194. }
  195. static void net_vhost_user_event(void *opaque, int event)
  196. {
  197. const char *name = opaque;
  198. NetClientState *ncs[MAX_QUEUE_NUM];
  199. NetVhostUserState *s;
  200. Chardev *chr;
  201. Error *err = NULL;
  202. int queues;
  203. queues = qemu_find_net_clients_except(name, ncs,
  204. NET_CLIENT_DRIVER_NIC,
  205. MAX_QUEUE_NUM);
  206. assert(queues < MAX_QUEUE_NUM);
  207. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  208. chr = qemu_chr_fe_get_driver(&s->chr);
  209. trace_vhost_user_event(chr->label, event);
  210. switch (event) {
  211. case CHR_EVENT_OPENED:
  212. if (vhost_user_start(queues, ncs, s->vhost_user) < 0) {
  213. qemu_chr_fe_disconnect(&s->chr);
  214. return;
  215. }
  216. s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
  217. net_vhost_user_watch, s);
  218. qmp_set_link(name, true, &err);
  219. s->started = true;
  220. break;
  221. case CHR_EVENT_CLOSED:
  222. /* a close event may happen during a read/write, but vhost
  223. * code assumes the vhost_dev remains setup, so delay the
  224. * stop & clear to idle.
  225. * FIXME: better handle failure in vhost code, remove bh
  226. */
  227. if (s->watch) {
  228. AioContext *ctx = qemu_get_current_aio_context();
  229. g_source_remove(s->watch);
  230. s->watch = 0;
  231. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL,
  232. NULL, NULL, false);
  233. aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque);
  234. }
  235. break;
  236. }
  237. if (err) {
  238. error_report_err(err);
  239. }
  240. }
  241. static int net_vhost_user_init(NetClientState *peer, const char *device,
  242. const char *name, Chardev *chr,
  243. int queues)
  244. {
  245. Error *err = NULL;
  246. NetClientState *nc, *nc0 = NULL;
  247. VhostUserState *user = NULL;
  248. NetVhostUserState *s = NULL;
  249. int i;
  250. assert(name);
  251. assert(queues > 0);
  252. user = vhost_user_init();
  253. if (!user) {
  254. error_report("failed to init vhost_user");
  255. goto err;
  256. }
  257. for (i = 0; i < queues; i++) {
  258. nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
  259. snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
  260. i, chr->label);
  261. nc->queue_index = i;
  262. if (!nc0) {
  263. nc0 = nc;
  264. s = DO_UPCAST(NetVhostUserState, nc, nc);
  265. if (!qemu_chr_fe_init(&s->chr, chr, &err)) {
  266. error_report_err(err);
  267. goto err;
  268. }
  269. user->chr = &s->chr;
  270. }
  271. s = DO_UPCAST(NetVhostUserState, nc, nc);
  272. s->vhost_user = user;
  273. }
  274. s = DO_UPCAST(NetVhostUserState, nc, nc0);
  275. do {
  276. if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
  277. error_report_err(err);
  278. goto err;
  279. }
  280. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
  281. net_vhost_user_event, NULL, nc0->name, NULL,
  282. true);
  283. } while (!s->started);
  284. assert(s->vhost_net);
  285. return 0;
  286. err:
  287. if (user) {
  288. vhost_user_cleanup(user);
  289. g_free(user);
  290. if (s) {
  291. s->vhost_user = NULL;
  292. }
  293. }
  294. if (nc0) {
  295. qemu_del_net_client(nc0);
  296. }
  297. return -1;
  298. }
  299. static Chardev *net_vhost_claim_chardev(
  300. const NetdevVhostUserOptions *opts, Error **errp)
  301. {
  302. Chardev *chr = qemu_chr_find(opts->chardev);
  303. if (chr == NULL) {
  304. error_setg(errp, "chardev \"%s\" not found", opts->chardev);
  305. return NULL;
  306. }
  307. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) {
  308. error_setg(errp, "chardev \"%s\" is not reconnectable",
  309. opts->chardev);
  310. return NULL;
  311. }
  312. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) {
  313. error_setg(errp, "chardev \"%s\" does not support FD passing",
  314. opts->chardev);
  315. return NULL;
  316. }
  317. return chr;
  318. }
  319. static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
  320. {
  321. const char *name = opaque;
  322. const char *driver, *netdev;
  323. driver = qemu_opt_get(opts, "driver");
  324. netdev = qemu_opt_get(opts, "netdev");
  325. if (!driver || !netdev) {
  326. return 0;
  327. }
  328. if (strcmp(netdev, name) == 0 &&
  329. !g_str_has_prefix(driver, "virtio-net-")) {
  330. error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
  331. return -1;
  332. }
  333. return 0;
  334. }
  335. int net_init_vhost_user(const Netdev *netdev, const char *name,
  336. NetClientState *peer, Error **errp)
  337. {
  338. int queues;
  339. const NetdevVhostUserOptions *vhost_user_opts;
  340. Chardev *chr;
  341. assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
  342. vhost_user_opts = &netdev->u.vhost_user;
  343. chr = net_vhost_claim_chardev(vhost_user_opts, errp);
  344. if (!chr) {
  345. return -1;
  346. }
  347. /* verify net frontend */
  348. if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
  349. (char *)name, errp)) {
  350. return -1;
  351. }
  352. queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
  353. if (queues < 1 || queues > MAX_QUEUE_NUM) {
  354. error_setg(errp,
  355. "vhost-user number of queues must be in range [1, %d]",
  356. MAX_QUEUE_NUM);
  357. return -1;
  358. }
  359. return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
  360. }