vhost-user.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. void vhost_user_save_acked_features(NetClientState *nc)
  44. {
  45. NetVhostUserState *s;
  46. s = DO_UPCAST(NetVhostUserState, nc, nc);
  47. if (s->vhost_net) {
  48. uint64_t features = vhost_net_get_acked_features(s->vhost_net);
  49. if (features) {
  50. s->acked_features = features;
  51. }
  52. }
  53. }
  54. static void vhost_user_stop(int queues, NetClientState *ncs[])
  55. {
  56. int i;
  57. NetVhostUserState *s;
  58. for (i = 0; i < queues; i++) {
  59. assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  60. s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
  61. if (s->vhost_net) {
  62. vhost_user_save_acked_features(ncs[i]);
  63. vhost_net_cleanup(s->vhost_net);
  64. }
  65. }
  66. }
  67. static int vhost_user_start(int queues, NetClientState *ncs[],
  68. VhostUserState *be)
  69. {
  70. VhostNetOptions options;
  71. struct vhost_net *net = NULL;
  72. NetVhostUserState *s;
  73. int max_queues;
  74. int i;
  75. options.backend_type = VHOST_BACKEND_TYPE_USER;
  76. for (i = 0; i < queues; i++) {
  77. assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  78. s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
  79. options.net_backend = ncs[i];
  80. options.opaque = be;
  81. options.busyloop_timeout = 0;
  82. options.nvqs = 2;
  83. net = vhost_net_init(&options);
  84. if (!net) {
  85. error_report("failed to init vhost_net for queue %d", i);
  86. goto err;
  87. }
  88. if (i == 0) {
  89. max_queues = vhost_net_get_max_queues(net);
  90. if (queues > max_queues) {
  91. error_report("you are asking more queues than supported: %d",
  92. max_queues);
  93. goto err;
  94. }
  95. }
  96. if (s->vhost_net) {
  97. vhost_net_cleanup(s->vhost_net);
  98. g_free(s->vhost_net);
  99. }
  100. s->vhost_net = net;
  101. }
  102. return 0;
  103. err:
  104. if (net) {
  105. vhost_net_cleanup(net);
  106. g_free(net);
  107. }
  108. vhost_user_stop(i, ncs);
  109. return -1;
  110. }
  111. static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf,
  112. size_t size)
  113. {
  114. /* In case of RARP (message size is 60) notify backup to send a fake RARP.
  115. This fake RARP will be sent by backend only for guest
  116. without GUEST_ANNOUNCE capability.
  117. */
  118. if (size == 60) {
  119. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  120. int r;
  121. static int display_rarp_failure = 1;
  122. char mac_addr[6];
  123. /* extract guest mac address from the RARP message */
  124. memcpy(mac_addr, &buf[6], 6);
  125. r = vhost_net_notify_migration_done(s->vhost_net, mac_addr);
  126. if ((r != 0) && (display_rarp_failure)) {
  127. fprintf(stderr,
  128. "Vhost user backend fails to broadcast fake RARP\n");
  129. fflush(stderr);
  130. display_rarp_failure = 0;
  131. }
  132. }
  133. return size;
  134. }
  135. static void net_vhost_user_cleanup(NetClientState *nc)
  136. {
  137. NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
  138. if (s->vhost_net) {
  139. vhost_net_cleanup(s->vhost_net);
  140. g_free(s->vhost_net);
  141. s->vhost_net = NULL;
  142. }
  143. if (nc->queue_index == 0) {
  144. if (s->watch) {
  145. g_source_remove(s->watch);
  146. s->watch = 0;
  147. }
  148. qemu_chr_fe_deinit(&s->chr, true);
  149. if (s->vhost_user) {
  150. vhost_user_cleanup(s->vhost_user);
  151. g_free(s->vhost_user);
  152. s->vhost_user = NULL;
  153. }
  154. }
  155. qemu_purge_queued_packets(nc);
  156. }
  157. static int vhost_user_set_vnet_endianness(NetClientState *nc,
  158. bool enable)
  159. {
  160. /* Nothing to do. If the server supports
  161. * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the
  162. * vnet header endianness from there. If it doesn't, negotiation
  163. * fails.
  164. */
  165. return 0;
  166. }
  167. static bool vhost_user_has_vnet_hdr(NetClientState *nc)
  168. {
  169. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  170. return true;
  171. }
  172. static bool vhost_user_has_ufo(NetClientState *nc)
  173. {
  174. assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
  175. return true;
  176. }
  177. static bool vhost_user_check_peer_type(NetClientState *nc, ObjectClass *oc,
  178. Error **errp)
  179. {
  180. const char *driver = object_class_get_name(oc);
  181. if (!g_str_has_prefix(driver, "virtio-net-")) {
  182. error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
  183. return false;
  184. }
  185. return true;
  186. }
  187. static NetClientInfo net_vhost_user_info = {
  188. .type = NET_CLIENT_DRIVER_VHOST_USER,
  189. .size = sizeof(NetVhostUserState),
  190. .receive = vhost_user_receive,
  191. .cleanup = net_vhost_user_cleanup,
  192. .has_vnet_hdr = vhost_user_has_vnet_hdr,
  193. .has_ufo = vhost_user_has_ufo,
  194. .set_vnet_be = vhost_user_set_vnet_endianness,
  195. .set_vnet_le = vhost_user_set_vnet_endianness,
  196. .check_peer_type = vhost_user_check_peer_type,
  197. };
  198. static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond,
  199. void *opaque)
  200. {
  201. NetVhostUserState *s = opaque;
  202. qemu_chr_fe_disconnect(&s->chr);
  203. return TRUE;
  204. }
  205. static void net_vhost_user_event(void *opaque, QEMUChrEvent event);
  206. static void chr_closed_bh(void *opaque)
  207. {
  208. const char *name = opaque;
  209. NetClientState *ncs[MAX_QUEUE_NUM];
  210. NetVhostUserState *s;
  211. Error *err = NULL;
  212. int queues, i;
  213. queues = qemu_find_net_clients_except(name, ncs,
  214. NET_CLIENT_DRIVER_NIC,
  215. MAX_QUEUE_NUM);
  216. assert(queues < MAX_QUEUE_NUM);
  217. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  218. for (i = queues -1; i >= 0; i--) {
  219. vhost_user_save_acked_features(ncs[i]);
  220. }
  221. qmp_set_link(name, false, &err);
  222. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
  223. NULL, opaque, NULL, true);
  224. if (err) {
  225. error_report_err(err);
  226. }
  227. }
  228. static void net_vhost_user_event(void *opaque, QEMUChrEvent event)
  229. {
  230. const char *name = opaque;
  231. NetClientState *ncs[MAX_QUEUE_NUM];
  232. NetVhostUserState *s;
  233. Chardev *chr;
  234. Error *err = NULL;
  235. int queues;
  236. queues = qemu_find_net_clients_except(name, ncs,
  237. NET_CLIENT_DRIVER_NIC,
  238. MAX_QUEUE_NUM);
  239. assert(queues < MAX_QUEUE_NUM);
  240. s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
  241. chr = qemu_chr_fe_get_driver(&s->chr);
  242. trace_vhost_user_event(chr->label, event);
  243. switch (event) {
  244. case CHR_EVENT_OPENED:
  245. if (vhost_user_start(queues, ncs, s->vhost_user) < 0) {
  246. qemu_chr_fe_disconnect(&s->chr);
  247. return;
  248. }
  249. s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
  250. net_vhost_user_watch, s);
  251. qmp_set_link(name, true, &err);
  252. s->started = true;
  253. break;
  254. case CHR_EVENT_CLOSED:
  255. /* a close event may happen during a read/write, but vhost
  256. * code assumes the vhost_dev remains setup, so delay the
  257. * stop & clear to idle.
  258. * FIXME: better handle failure in vhost code, remove bh
  259. */
  260. if (s->watch) {
  261. AioContext *ctx = qemu_get_current_aio_context();
  262. g_source_remove(s->watch);
  263. s->watch = 0;
  264. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL,
  265. NULL, NULL, false);
  266. aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque);
  267. }
  268. break;
  269. case CHR_EVENT_BREAK:
  270. case CHR_EVENT_MUX_IN:
  271. case CHR_EVENT_MUX_OUT:
  272. /* Ignore */
  273. break;
  274. }
  275. if (err) {
  276. error_report_err(err);
  277. }
  278. }
  279. static int net_vhost_user_init(NetClientState *peer, const char *device,
  280. const char *name, Chardev *chr,
  281. int queues)
  282. {
  283. Error *err = NULL;
  284. NetClientState *nc, *nc0 = NULL;
  285. NetVhostUserState *s = NULL;
  286. VhostUserState *user;
  287. int i;
  288. assert(name);
  289. assert(queues > 0);
  290. user = g_new0(struct VhostUserState, 1);
  291. for (i = 0; i < queues; i++) {
  292. nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
  293. qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label);
  294. nc->queue_index = i;
  295. if (!nc0) {
  296. nc0 = nc;
  297. s = DO_UPCAST(NetVhostUserState, nc, nc);
  298. if (!qemu_chr_fe_init(&s->chr, chr, &err) ||
  299. !vhost_user_init(user, &s->chr, &err)) {
  300. error_report_err(err);
  301. goto err;
  302. }
  303. }
  304. s = DO_UPCAST(NetVhostUserState, nc, nc);
  305. s->vhost_user = user;
  306. }
  307. s = DO_UPCAST(NetVhostUserState, nc, nc0);
  308. do {
  309. if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
  310. error_report_err(err);
  311. goto err;
  312. }
  313. qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
  314. net_vhost_user_event, NULL, nc0->name, NULL,
  315. true);
  316. } while (!s->started);
  317. assert(s->vhost_net);
  318. return 0;
  319. err:
  320. if (user) {
  321. vhost_user_cleanup(user);
  322. g_free(user);
  323. if (s) {
  324. s->vhost_user = NULL;
  325. }
  326. }
  327. if (nc0) {
  328. qemu_del_net_client(nc0);
  329. }
  330. return -1;
  331. }
  332. static Chardev *net_vhost_claim_chardev(
  333. const NetdevVhostUserOptions *opts, Error **errp)
  334. {
  335. Chardev *chr = qemu_chr_find(opts->chardev);
  336. if (chr == NULL) {
  337. error_setg(errp, "chardev \"%s\" not found", opts->chardev);
  338. return NULL;
  339. }
  340. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) {
  341. error_setg(errp, "chardev \"%s\" is not reconnectable",
  342. opts->chardev);
  343. return NULL;
  344. }
  345. if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) {
  346. error_setg(errp, "chardev \"%s\" does not support FD passing",
  347. opts->chardev);
  348. return NULL;
  349. }
  350. return chr;
  351. }
  352. int net_init_vhost_user(const Netdev *netdev, const char *name,
  353. NetClientState *peer, Error **errp)
  354. {
  355. int queues;
  356. const NetdevVhostUserOptions *vhost_user_opts;
  357. Chardev *chr;
  358. assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
  359. vhost_user_opts = &netdev->u.vhost_user;
  360. chr = net_vhost_claim_chardev(vhost_user_opts, errp);
  361. if (!chr) {
  362. return -1;
  363. }
  364. queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
  365. if (queues < 1 || queues > MAX_QUEUE_NUM) {
  366. error_setg(errp,
  367. "vhost-user number of queues must be in range [1, %d]",
  368. MAX_QUEUE_NUM);
  369. return -1;
  370. }
  371. return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
  372. }