static void vhost_user_cleanup(NetClientState *nc) { VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); vhost_user_stop(s); qemu_purge_queued_packets(nc); }
static void chr_closed_bh(void *opaque) { const char *name = opaque; NetClientState *ncs[MAX_QUEUE_NUM]; VhostUserState *s; Error *err = NULL; int queues; queues = qemu_find_net_clients_except(name, ncs, NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); assert(queues < MAX_QUEUE_NUM); s = DO_UPCAST(VhostUserState, nc, ncs[0]); qmp_set_link(name, false, &err); vhost_user_stop(queues, ncs); qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, NULL, opaque, NULL, true); if (err) { error_report_err(err); } }
static int vhost_user_start(int queues, NetClientState *ncs[], CharBackend *be) { VhostNetOptions options; struct vhost_net *net = NULL; NetVhostUserState *s; int max_queues; int i; options.backend_type = VHOST_BACKEND_TYPE_USER; for (i = 0; i < queues; i++) { assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); s = DO_UPCAST(NetVhostUserState, nc, ncs[i]); options.net_backend = ncs[i]; options.opaque = be; options.busyloop_timeout = 0; net = vhost_net_init(&options); if (!net) { error_report("failed to init vhost_net for queue %d", i); goto err; } if (i == 0) { max_queues = vhost_net_get_max_queues(net); if (queues > max_queues) { error_report("you are asking more queues than supported: %d", max_queues); goto err; } } if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); g_free(s->vhost_net); } s->vhost_net = net; } return 0; err: if (net) { vhost_net_cleanup(net); g_free(net); } vhost_user_stop(i, ncs); return -1; }
static void net_vhost_user_event(void *opaque, int event) { VhostUserState *s = opaque; switch (event) { case CHR_EVENT_OPENED: vhost_user_start(s); net_vhost_link_down(s, false); error_report("chardev \"%s\" went up", s->chr->label); break; case CHR_EVENT_CLOSED: net_vhost_link_down(s, true); vhost_user_stop(s); error_report("chardev \"%s\" went down", s->chr->label); break; } }
static int vhost_user_start(int queues, NetClientState *ncs[]) { VhostNetOptions options; VhostUserState *s; int max_queues; int i; options.backend_type = VHOST_BACKEND_TYPE_USER; for (i = 0; i < queues; i++) { assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); s = DO_UPCAST(VhostUserState, nc, ncs[i]); if (vhost_user_running(s)) { continue; } options.net_backend = ncs[i]; options.opaque = s->chr; s->vhost_net = vhost_net_init(&options); if (!s->vhost_net) { error_report("failed to init vhost_net for queue %d\n", i); goto err; } if (i == 0) { max_queues = vhost_net_get_max_queues(s->vhost_net); if (queues > max_queues) { error_report("you are asking more queues than " "supported: %d\n", max_queues); goto err; } } } return 0; err: vhost_user_stop(i + 1, ncs); return -1; }
static void net_vhost_user_event(void *opaque, int event) { const char *name = opaque; NetClientState *ncs[MAX_QUEUE_NUM]; VhostUserState *s; CharDriverState *chr; Error *err = NULL; int queues; queues = qemu_find_net_clients_except(name, ncs, NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); assert(queues < MAX_QUEUE_NUM); s = DO_UPCAST(VhostUserState, nc, ncs[0]); chr = qemu_chr_fe_get_driver(&s->chr); trace_vhost_user_event(chr->label, event); switch (event) { case CHR_EVENT_OPENED: s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP, net_vhost_user_watch, s); if (vhost_user_start(queues, ncs, &s->chr) < 0) { qemu_chr_fe_disconnect(&s->chr); return; } qmp_set_link(name, true, &err); s->started = true; break; case CHR_EVENT_CLOSED: qmp_set_link(name, false, &err); vhost_user_stop(queues, ncs); g_source_remove(s->watch); s->watch = 0; break; } if (err) { error_report_err(err); } }