vhost-user.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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 int vhost_user_set_vnet_endianness(NetClientState *nc,
  150. bool enable)
  151. {
  152. /* Nothing to do. If the server supports
  153. * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the
  154. * vnet header endianness from there. If it doesn't, negotiation
  155. * fails.
  156. */
  157. return 0;
  158. }
  159. static bool vhost_user_has_vnet_hdr(NetClientState *nc)
  160. {
  161. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  162. return true;
  163. }
  164. static bool vhost_user_has_ufo(NetClientState *nc)
  165. {
  166. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  167. return true;
  168. }
  169. static NetClientInfo net_vhost_user_info = {
  170. .type = NET_CLIENT_DRIVER_VHOST_USER,
  171. .size = sizeof(NetVhostUserState),
  172. .receive = vhost_user_receive,
  173. .cleanup = net_vhost_user_cleanup,
  174. .has_vnet_hdr = vhost_user_has_vnet_hdr,
  175. .has_ufo = vhost_user_has_ufo,
  176. .set_vnet_be = vhost_user_set_vnet_endianness,
  177. .set_vnet_le = vhost_user_set_vnet_endianness,
  178. };
  179. static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
  180. void *opaque)
  181. {
  182. NetVhostUserState *s = opaque;
  183. qemu_chr_fe_disconnect(&s->chr);
  184. return TRUE;
  185. }
  186. static void net_vhost_user_event(void *opaque, QEMUChrEvent event);
  187. static void chr_closed_bh(void *opaque)
  188. {
  189. const char *name = opaque;
  190. NetClientState *ncs[MAX_QUEUE_NUM];
  191. NetVhostUserState *s;
  192. Error *err = NULL;
  193. int queues;
  194. queues = qemu_find_net_clients_except(name, ncs,
  195. NET_CLIENT_DRIVER_NIC,
  196. MAX_QUEUE_NUM);
  197. assert(queues < MAX_QUEUE_NUM);
  198. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  199. if (s->vhost_net) {
  200. s->acked_features = vhost_net_get_acked_features(s->vhost_net);
  201. }
  202. qmp_set_link(name, false, &err);
  203. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
  204. NULL, opaque, NULL, true);
  205. if (err) {
  206. error_report_err(err);
  207. }
  208. }
  209. static void net_vhost_user_event(void *opaque, QEMUChrEvent event)
  210. {
  211. const char *name = opaque;
  212. NetClientState *ncs[MAX_QUEUE_NUM];
  213. NetVhostUserState *s;
  214. Chardev *chr;
  215. Error *err = NULL;
  216. int queues;
  217. queues = qemu_find_net_clients_except(name, ncs,
  218. NET_CLIENT_DRIVER_NIC,
  219. MAX_QUEUE_NUM);
  220. assert(queues < MAX_QUEUE_NUM);
  221. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  222. chr = qemu_chr_fe_get_driver(&s->chr);
  223. trace_vhost_user_event(chr->label, event);
  224. switch (event) {
  225. case CHR_EVENT_OPENED:
  226. if (vhost_user_start(queues, ncs, s->vhost_user) < 0) {
  227. qemu_chr_fe_disconnect(&s->chr);
  228. return;
  229. }
  230. s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
  231. net_vhost_user_watch, s);
  232. qmp_set_link(name, true, &err);
  233. s->started = true;
  234. break;
  235. case CHR_EVENT_CLOSED:
  236. /* a close event may happen during a read/write, but vhost
  237. * code assumes the vhost_dev remains setup, so delay the
  238. * stop & clear to idle.
  239. * FIXME: better handle failure in vhost code, remove bh
  240. */
  241. if (s->watch) {
  242. AioContext *ctx = qemu_get_current_aio_context();
  243. g_source_remove(s->watch);
  244. s->watch = 0;
  245. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL,
  246. NULL, NULL, false);
  247. aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque);
  248. }
  249. break;
  250. case CHR_EVENT_BREAK:
  251. case CHR_EVENT_MUX_IN:
  252. case CHR_EVENT_MUX_OUT:
  253. /* Ignore */
  254. break;
  255. }
  256. if (err) {
  257. error_report_err(err);
  258. }
  259. }
  260. static int net_vhost_user_init(NetClientState *peer, const char *device,
  261. const char *name, Chardev *chr,
  262. int queues)
  263. {
  264. Error *err = NULL;
  265. NetClientState *nc, *nc0 = NULL;
  266. NetVhostUserState *s = NULL;
  267. VhostUserState *user;
  268. int i;
  269. assert(name);
  270. assert(queues > 0);
  271. user = g_new0(struct VhostUserState, 1);
  272. for (i = 0; i < queues; i++) {
  273. nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
  274. snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
  275. i, chr->label);
  276. nc->queue_index = i;
  277. if (!nc0) {
  278. nc0 = nc;
  279. s = DO_UPCAST(NetVhostUserState, nc, nc);
  280. if (!qemu_chr_fe_init(&s->chr, chr, &err) ||
  281. !vhost_user_init(user, &s->chr, &err)) {
  282. error_report_err(err);
  283. goto err;
  284. }
  285. }
  286. s = DO_UPCAST(NetVhostUserState, nc, nc);
  287. s->vhost_user = user;
  288. }
  289. s = DO_UPCAST(NetVhostUserState, nc, nc0);
  290. do {
  291. if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
  292. error_report_err(err);
  293. goto err;
  294. }
  295. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
  296. net_vhost_user_event, NULL, nc0->name, NULL,
  297. true);
  298. } while (!s->started);
  299. assert(s->vhost_net);
  300. return 0;
  301. err:
  302. if (user) {
  303. vhost_user_cleanup(user);
  304. g_free(user);
  305. if (s) {
  306. s->vhost_user = NULL;
  307. }
  308. }
  309. if (nc0) {
  310. qemu_del_net_client(nc0);
  311. }
  312. return -1;
  313. }
  314. static Chardev *net_vhost_claim_chardev(
  315. const NetdevVhostUserOptions *opts, Error **errp)
  316. {
  317. Chardev *chr = qemu_chr_find(opts->chardev);
  318. if (chr == NULL) {
  319. error_setg(errp, "chardev \"%s\" not found", opts->chardev);
  320. return NULL;
  321. }
  322. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) {
  323. error_setg(errp, "chardev \"%s\" is not reconnectable",
  324. opts->chardev);
  325. return NULL;
  326. }
  327. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) {
  328. error_setg(errp, "chardev \"%s\" does not support FD passing",
  329. opts->chardev);
  330. return NULL;
  331. }
  332. return chr;
  333. }
  334. static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
  335. {
  336. const char *name = opaque;
  337. const char *driver, *netdev;
  338. driver = qemu_opt_get(opts, "driver");
  339. netdev = qemu_opt_get(opts, "netdev");
  340. if (!driver || !netdev) {
  341. return 0;
  342. }
  343. if (strcmp(netdev, name) == 0 &&
  344. !g_str_has_prefix(driver, "virtio-net-")) {
  345. error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
  346. return -1;
  347. }
  348. return 0;
  349. }
  350. int net_init_vhost_user(const Netdev *netdev, const char *name,
  351. NetClientState *peer, Error **errp)
  352. {
  353. int queues;
  354. const NetdevVhostUserOptions *vhost_user_opts;
  355. Chardev *chr;
  356. assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
  357. vhost_user_opts = &netdev->u.vhost_user;
  358. chr = net_vhost_claim_chardev(vhost_user_opts, errp);
  359. if (!chr) {
  360. return -1;
  361. }
  362. /* verify net frontend */
  363. if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
  364. (char *)name, errp)) {
  365. return -1;
  366. }
  367. queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
  368. if (queues < 1 || queues > MAX_QUEUE_NUM) {
  369. error_setg(errp,
  370. "vhost-user number of queues must be in range [1, %d]",
  371. MAX_QUEUE_NUM);
  372. return -1;
  373. }
  374. return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
  375. }