1d314f586SNikolay Nikolaev /*
2d314f586SNikolay Nikolaev * vhost-user.c
3d314f586SNikolay Nikolaev *
4d314f586SNikolay Nikolaev * Copyright (c) 2013 Virtual Open Systems Sarl.
5d314f586SNikolay Nikolaev *
6d314f586SNikolay Nikolaev * This work is licensed under the terms of the GNU GPL, version 2 or later.
7d314f586SNikolay Nikolaev * See the COPYING file in the top-level directory.
8d314f586SNikolay Nikolaev *
9d314f586SNikolay Nikolaev */
10d314f586SNikolay Nikolaev
112744d920SPeter Maydell #include "qemu/osdep.h"
12d314f586SNikolay Nikolaev #include "clients.h"
13d314f586SNikolay Nikolaev #include "net/vhost_net.h"
14d314f586SNikolay Nikolaev #include "net/vhost-user.h"
154d0cf552STiwei Bie #include "hw/virtio/vhost-user.h"
164d43a603SMarc-André Lureau #include "chardev/char-fe.h"
17e688df6bSMarkus Armbruster #include "qapi/error.h"
189af23989SMarkus Armbruster #include "qapi/qapi-commands-net.h"
1903ce5744SNikolay Nikolaev #include "qemu/config-file.h"
20d314f586SNikolay Nikolaev #include "qemu/error-report.h"
21922a01a0SMarkus Armbruster #include "qemu/option.h"
2269b32a6cSMarc-André Lureau #include "trace.h"
23d314f586SNikolay Nikolaev
24703878e2STiwei Bie typedef struct NetVhostUserState {
25d314f586SNikolay Nikolaev NetClientState nc;
265d300164SMarc-André Lureau CharBackend chr; /* only queue index 0 */
274d0cf552STiwei Bie VhostUserState *vhost_user;
28d314f586SNikolay Nikolaev VHostNetState *vhost_net;
296f1de6b7SPaolo Bonzini guint watch;
30a463215bSMarc-André Lureau uint64_t acked_features;
31c89804d6SMarc-André Lureau bool started;
32703878e2STiwei Bie } NetVhostUserState;
33d314f586SNikolay Nikolaev
vhost_user_get_vhost_net(NetClientState * nc)34d314f586SNikolay Nikolaev VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
35d314f586SNikolay Nikolaev {
36703878e2STiwei Bie NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
37f394b2e2SEric Blake assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
38d314f586SNikolay Nikolaev return s->vhost_net;
39d314f586SNikolay Nikolaev }
40d314f586SNikolay Nikolaev
vhost_user_get_acked_features(NetClientState * nc)41a463215bSMarc-André Lureau uint64_t vhost_user_get_acked_features(NetClientState *nc)
42a463215bSMarc-André Lureau {
43703878e2STiwei Bie NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
44f394b2e2SEric Blake assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
45a463215bSMarc-André Lureau return s->acked_features;
46a463215bSMarc-André Lureau }
47a463215bSMarc-André Lureau
vhost_user_save_acked_features(NetClientState * nc)48937b7d96SHyman Huang(黄勇) void vhost_user_save_acked_features(NetClientState *nc)
49b931bfbfSChangchun Ouyang {
50703878e2STiwei Bie NetVhostUserState *s;
51937b7d96SHyman Huang(黄勇)
52937b7d96SHyman Huang(黄勇) s = DO_UPCAST(NetVhostUserState, nc, nc);
53937b7d96SHyman Huang(黄勇) if (s->vhost_net) {
54937b7d96SHyman Huang(黄勇) uint64_t features = vhost_net_get_acked_features(s->vhost_net);
55937b7d96SHyman Huang(黄勇) if (features) {
56937b7d96SHyman Huang(黄勇) s->acked_features = features;
57937b7d96SHyman Huang(黄勇) }
58937b7d96SHyman Huang(黄勇) }
59937b7d96SHyman Huang(黄勇) }
60937b7d96SHyman Huang(黄勇)
vhost_user_stop(int queues,NetClientState * ncs[])61937b7d96SHyman Huang(黄勇) static void vhost_user_stop(int queues, NetClientState *ncs[])
62937b7d96SHyman Huang(黄勇) {
63b931bfbfSChangchun Ouyang int i;
64937b7d96SHyman Huang(黄勇) NetVhostUserState *s;
65b931bfbfSChangchun Ouyang
66b931bfbfSChangchun Ouyang for (i = 0; i < queues; i++) {
67f394b2e2SEric Blake assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
68b931bfbfSChangchun Ouyang
69703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
70b931bfbfSChangchun Ouyang
71b931bfbfSChangchun Ouyang if (s->vhost_net) {
72937b7d96SHyman Huang(黄勇) vhost_user_save_acked_features(ncs[i]);
73b931bfbfSChangchun Ouyang vhost_net_cleanup(s->vhost_net);
74b931bfbfSChangchun Ouyang }
75b931bfbfSChangchun Ouyang }
76b931bfbfSChangchun Ouyang }
77b931bfbfSChangchun Ouyang
vhost_user_start(int queues,NetClientState * ncs[],VhostUserState * be)784d0cf552STiwei Bie static int vhost_user_start(int queues, NetClientState *ncs[],
794d0cf552STiwei Bie VhostUserState *be)
80d314f586SNikolay Nikolaev {
81d314f586SNikolay Nikolaev VhostNetOptions options;
82e6bcb1b6SMarc-André Lureau struct vhost_net *net = NULL;
83703878e2STiwei Bie NetVhostUserState *s;
84b931bfbfSChangchun Ouyang int max_queues;
85b931bfbfSChangchun Ouyang int i;
86d314f586SNikolay Nikolaev
87d314f586SNikolay Nikolaev options.backend_type = VHOST_BACKEND_TYPE_USER;
88d314f586SNikolay Nikolaev
89b931bfbfSChangchun Ouyang for (i = 0; i < queues; i++) {
90f394b2e2SEric Blake assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
91d314f586SNikolay Nikolaev
92703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, ncs[i]);
93d314f586SNikolay Nikolaev
94b931bfbfSChangchun Ouyang options.net_backend = ncs[i];
955d300164SMarc-André Lureau options.opaque = be;
9669e87b32SJason Wang options.busyloop_timeout = 0;
976a756d14SJason Wang options.nvqs = 2;
98e6bcb1b6SMarc-André Lureau net = vhost_net_init(&options);
99e6bcb1b6SMarc-André Lureau if (!net) {
1009af9e0feSMarkus Armbruster error_report("failed to init vhost_net for queue %d", i);
101b931bfbfSChangchun Ouyang goto err;
102b931bfbfSChangchun Ouyang }
103b931bfbfSChangchun Ouyang
104b931bfbfSChangchun Ouyang if (i == 0) {
105e6bcb1b6SMarc-André Lureau max_queues = vhost_net_get_max_queues(net);
106b931bfbfSChangchun Ouyang if (queues > max_queues) {
1079af9e0feSMarkus Armbruster error_report("you are asking more queues than supported: %d",
1089af9e0feSMarkus Armbruster max_queues);
109b931bfbfSChangchun Ouyang goto err;
110b931bfbfSChangchun Ouyang }
111b931bfbfSChangchun Ouyang }
112e6bcb1b6SMarc-André Lureau
113e6bcb1b6SMarc-André Lureau if (s->vhost_net) {
114e6bcb1b6SMarc-André Lureau vhost_net_cleanup(s->vhost_net);
115e6bcb1b6SMarc-André Lureau g_free(s->vhost_net);
116e6bcb1b6SMarc-André Lureau }
117e6bcb1b6SMarc-André Lureau s->vhost_net = net;
118b931bfbfSChangchun Ouyang }
119b931bfbfSChangchun Ouyang
120b931bfbfSChangchun Ouyang return 0;
121b931bfbfSChangchun Ouyang
122b931bfbfSChangchun Ouyang err:
123e6bcb1b6SMarc-André Lureau if (net) {
124e6bcb1b6SMarc-André Lureau vhost_net_cleanup(net);
125a38a498dSlinzhecheng g_free(net);
126e6bcb1b6SMarc-André Lureau }
127e6bcb1b6SMarc-André Lureau vhost_user_stop(i, ncs);
128b931bfbfSChangchun Ouyang return -1;
129d314f586SNikolay Nikolaev }
130d314f586SNikolay Nikolaev
vhost_user_receive(NetClientState * nc,const uint8_t * buf,size_t size)131f6f56291SThibaut Collet static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf,
132f6f56291SThibaut Collet size_t size)
133f6f56291SThibaut Collet {
1343e866365SThibaut Collet /* In case of RARP (message size is 60) notify backup to send a fake RARP.
1353e866365SThibaut Collet This fake RARP will be sent by backend only for guest
1363e866365SThibaut Collet without GUEST_ANNOUNCE capability.
137f6f56291SThibaut Collet */
1383e866365SThibaut Collet if (size == 60) {
139703878e2STiwei Bie NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
1403e866365SThibaut Collet int r;
1413e866365SThibaut Collet static int display_rarp_failure = 1;
1423e866365SThibaut Collet char mac_addr[6];
1433e866365SThibaut Collet
1443e866365SThibaut Collet /* extract guest mac address from the RARP message */
1453e866365SThibaut Collet memcpy(mac_addr, &buf[6], 6);
1463e866365SThibaut Collet
1473e866365SThibaut Collet r = vhost_net_notify_migration_done(s->vhost_net, mac_addr);
1483e866365SThibaut Collet
1493e866365SThibaut Collet if ((r != 0) && (display_rarp_failure)) {
1503e866365SThibaut Collet fprintf(stderr,
1513e866365SThibaut Collet "Vhost user backend fails to broadcast fake RARP\n");
1523e866365SThibaut Collet fflush(stderr);
1533e866365SThibaut Collet display_rarp_failure = 0;
1543e866365SThibaut Collet }
1553e866365SThibaut Collet }
1563e866365SThibaut Collet
157f6f56291SThibaut Collet return size;
158f6f56291SThibaut Collet }
159f6f56291SThibaut Collet
net_vhost_user_cleanup(NetClientState * nc)1604d0cf552STiwei Bie static void net_vhost_user_cleanup(NetClientState *nc)
161d314f586SNikolay Nikolaev {
162703878e2STiwei Bie NetVhostUserState *s = DO_UPCAST(NetVhostUserState, nc, nc);
163d314f586SNikolay Nikolaev
164b931bfbfSChangchun Ouyang if (s->vhost_net) {
165b931bfbfSChangchun Ouyang vhost_net_cleanup(s->vhost_net);
166e6bcb1b6SMarc-André Lureau g_free(s->vhost_net);
167b931bfbfSChangchun Ouyang s->vhost_net = NULL;
168b931bfbfSChangchun Ouyang }
169c39860e6SMarc-André Lureau if (nc->queue_index == 0) {
17041d4e5ecSYunjian Wang if (s->watch) {
17141d4e5ecSYunjian Wang g_source_remove(s->watch);
17241d4e5ecSYunjian Wang s->watch = 0;
17341d4e5ecSYunjian Wang }
1741ce2610cSMarc-André Lureau qemu_chr_fe_deinit(&s->chr, true);
1754d0cf552STiwei Bie if (s->vhost_user) {
1764d0cf552STiwei Bie vhost_user_cleanup(s->vhost_user);
1774d0cf552STiwei Bie g_free(s->vhost_user);
1784d0cf552STiwei Bie s->vhost_user = NULL;
1794d0cf552STiwei Bie }
18025f0d2aaSPaolo Bonzini }
181b931bfbfSChangchun Ouyang
182d314f586SNikolay Nikolaev qemu_purge_queued_packets(nc);
183d314f586SNikolay Nikolaev }
184d314f586SNikolay Nikolaev
vhost_user_set_vnet_endianness(NetClientState * nc,bool enable)185ba288898SPaolo Bonzini static int vhost_user_set_vnet_endianness(NetClientState *nc,
186ba288898SPaolo Bonzini bool enable)
187ba288898SPaolo Bonzini {
188ba288898SPaolo Bonzini /* Nothing to do. If the server supports
189ba288898SPaolo Bonzini * VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, it will get the
190ba288898SPaolo Bonzini * vnet header endianness from there. If it doesn't, negotiation
191ba288898SPaolo Bonzini * fails.
192ba288898SPaolo Bonzini */
193ba288898SPaolo Bonzini return 0;
194ba288898SPaolo Bonzini }
195ba288898SPaolo Bonzini
vhost_user_has_vnet_hdr(NetClientState * nc)196d314f586SNikolay Nikolaev static bool vhost_user_has_vnet_hdr(NetClientState *nc)
197d314f586SNikolay Nikolaev {
198f394b2e2SEric Blake assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
199d314f586SNikolay Nikolaev
200d314f586SNikolay Nikolaev return true;
201d314f586SNikolay Nikolaev }
202d314f586SNikolay Nikolaev
vhost_user_has_ufo(NetClientState * nc)203d314f586SNikolay Nikolaev static bool vhost_user_has_ufo(NetClientState *nc)
204d314f586SNikolay Nikolaev {
205f394b2e2SEric Blake assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
206d314f586SNikolay Nikolaev
207d314f586SNikolay Nikolaev return true;
208d314f586SNikolay Nikolaev }
209d314f586SNikolay Nikolaev
vhost_user_check_peer_type(NetClientState * nc,ObjectClass * oc,Error ** errp)2105c485d51SKevin Wolf static bool vhost_user_check_peer_type(NetClientState *nc, ObjectClass *oc,
2115c485d51SKevin Wolf Error **errp)
2125c485d51SKevin Wolf {
2135c485d51SKevin Wolf const char *driver = object_class_get_name(oc);
2145c485d51SKevin Wolf
2155c485d51SKevin Wolf if (!g_str_has_prefix(driver, "virtio-net-")) {
2165c485d51SKevin Wolf error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
2175c485d51SKevin Wolf return false;
2185c485d51SKevin Wolf }
2195c485d51SKevin Wolf
2205c485d51SKevin Wolf return true;
2215c485d51SKevin Wolf }
2225c485d51SKevin Wolf
223d314f586SNikolay Nikolaev static NetClientInfo net_vhost_user_info = {
224f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_VHOST_USER,
225703878e2STiwei Bie .size = sizeof(NetVhostUserState),
226f6f56291SThibaut Collet .receive = vhost_user_receive,
2274d0cf552STiwei Bie .cleanup = net_vhost_user_cleanup,
228d314f586SNikolay Nikolaev .has_vnet_hdr = vhost_user_has_vnet_hdr,
229d314f586SNikolay Nikolaev .has_ufo = vhost_user_has_ufo,
230ba288898SPaolo Bonzini .set_vnet_be = vhost_user_set_vnet_endianness,
231ba288898SPaolo Bonzini .set_vnet_le = vhost_user_set_vnet_endianness,
2325c485d51SKevin Wolf .check_peer_type = vhost_user_check_peer_type,
233d314f586SNikolay Nikolaev };
234d314f586SNikolay Nikolaev
net_vhost_user_watch(void * do_not_use,GIOCondition cond,void * opaque)235bf7b1eabSMarc-André Lureau static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond,
236a6553598STetsuya Mukawa void *opaque)
237a6553598STetsuya Mukawa {
238703878e2STiwei Bie NetVhostUserState *s = opaque;
239a6553598STetsuya Mukawa
2405345fdb4SMarc-André Lureau qemu_chr_fe_disconnect(&s->chr);
241a6553598STetsuya Mukawa
242*53c7c924SPhilippe Mathieu-Daudé return G_SOURCE_CONTINUE;
243e7c83a88SMarc-André Lureau }
244e7c83a88SMarc-André Lureau
245083b266fSPhilippe Mathieu-Daudé static void net_vhost_user_event(void *opaque, QEMUChrEvent event);
246e7c83a88SMarc-André Lureau
chr_closed_bh(void * opaque)247e7c83a88SMarc-André Lureau static void chr_closed_bh(void *opaque)
248e7c83a88SMarc-André Lureau {
249e7c83a88SMarc-André Lureau const char *name = opaque;
250e7c83a88SMarc-André Lureau NetClientState *ncs[MAX_QUEUE_NUM];
251703878e2STiwei Bie NetVhostUserState *s;
252e7c83a88SMarc-André Lureau Error *err = NULL;
253f66337bdShaibinzhang(张海斌) int queues, i;
254e7c83a88SMarc-André Lureau
255e7c83a88SMarc-André Lureau queues = qemu_find_net_clients_except(name, ncs,
256e7c83a88SMarc-André Lureau NET_CLIENT_DRIVER_NIC,
257e7c83a88SMarc-André Lureau MAX_QUEUE_NUM);
258e7c83a88SMarc-André Lureau assert(queues < MAX_QUEUE_NUM);
259e7c83a88SMarc-André Lureau
260703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
261e7c83a88SMarc-André Lureau
262f66337bdShaibinzhang(张海斌) for (i = queues -1; i >= 0; i--) {
263bebcac05SHyman Huang(黄勇) vhost_user_save_acked_features(ncs[i]);
264f66337bdShaibinzhang(张海斌) }
265c6beefd6SAdrian Moreno
266e7c83a88SMarc-André Lureau qmp_set_link(name, false, &err);
267e7c83a88SMarc-André Lureau
268e7c83a88SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
26981517ba3SAnton Nefedov NULL, opaque, NULL, true);
270e7c83a88SMarc-André Lureau
271e7c83a88SMarc-André Lureau if (err) {
272e7c83a88SMarc-André Lureau error_report_err(err);
273e7c83a88SMarc-André Lureau }
274a6553598STetsuya Mukawa }
275a6553598STetsuya Mukawa
net_vhost_user_event(void * opaque,QEMUChrEvent event)276083b266fSPhilippe Mathieu-Daudé static void net_vhost_user_event(void *opaque, QEMUChrEvent event)
277d314f586SNikolay Nikolaev {
278b931bfbfSChangchun Ouyang const char *name = opaque;
279b931bfbfSChangchun Ouyang NetClientState *ncs[MAX_QUEUE_NUM];
280703878e2STiwei Bie NetVhostUserState *s;
2810ec7b3e7SMarc-André Lureau Chardev *chr;
282b931bfbfSChangchun Ouyang Error *err = NULL;
283b931bfbfSChangchun Ouyang int queues;
284d314f586SNikolay Nikolaev
285b931bfbfSChangchun Ouyang queues = qemu_find_net_clients_except(name, ncs,
286f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC,
287b931bfbfSChangchun Ouyang MAX_QUEUE_NUM);
288c1bf3531SMarc-André Lureau assert(queues < MAX_QUEUE_NUM);
289c1bf3531SMarc-André Lureau
290703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
2915345fdb4SMarc-André Lureau chr = qemu_chr_fe_get_driver(&s->chr);
2925345fdb4SMarc-André Lureau trace_vhost_user_event(chr->label, event);
293d314f586SNikolay Nikolaev switch (event) {
294d314f586SNikolay Nikolaev case CHR_EVENT_OPENED:
2954d0cf552STiwei Bie if (vhost_user_start(queues, ncs, s->vhost_user) < 0) {
2965345fdb4SMarc-André Lureau qemu_chr_fe_disconnect(&s->chr);
2970d572afdSMarc-André Lureau return;
298b931bfbfSChangchun Ouyang }
299e7c83a88SMarc-André Lureau s->watch = qemu_chr_fe_add_watch(&s->chr, G_IO_HUP,
300e7c83a88SMarc-André Lureau net_vhost_user_watch, s);
301b931bfbfSChangchun Ouyang qmp_set_link(name, true, &err);
302c89804d6SMarc-André Lureau s->started = true;
303d314f586SNikolay Nikolaev break;
304d314f586SNikolay Nikolaev case CHR_EVENT_CLOSED:
305e7c83a88SMarc-André Lureau /* a close event may happen during a read/write, but vhost
306e7c83a88SMarc-André Lureau * code assumes the vhost_dev remains setup, so delay the
307e7c83a88SMarc-André Lureau * stop & clear to idle.
308e7c83a88SMarc-André Lureau * FIXME: better handle failure in vhost code, remove bh
309e7c83a88SMarc-André Lureau */
310e7c83a88SMarc-André Lureau if (s->watch) {
311e7c83a88SMarc-André Lureau AioContext *ctx = qemu_get_current_aio_context();
312e7c83a88SMarc-André Lureau
313a6553598STetsuya Mukawa g_source_remove(s->watch);
314a6553598STetsuya Mukawa s->watch = 0;
31581517ba3SAnton Nefedov qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, NULL, NULL,
316e7c83a88SMarc-André Lureau NULL, NULL, false);
317e7c83a88SMarc-André Lureau
318e7c83a88SMarc-André Lureau aio_bh_schedule_oneshot(ctx, chr_closed_bh, opaque);
319e7c83a88SMarc-André Lureau }
320d314f586SNikolay Nikolaev break;
321d0ab6769SPhilippe Mathieu-Daudé case CHR_EVENT_BREAK:
322d0ab6769SPhilippe Mathieu-Daudé case CHR_EVENT_MUX_IN:
323d0ab6769SPhilippe Mathieu-Daudé case CHR_EVENT_MUX_OUT:
324d0ab6769SPhilippe Mathieu-Daudé /* Ignore */
325d0ab6769SPhilippe Mathieu-Daudé break;
326d314f586SNikolay Nikolaev }
327b931bfbfSChangchun Ouyang
328b931bfbfSChangchun Ouyang if (err) {
329b931bfbfSChangchun Ouyang error_report_err(err);
330b931bfbfSChangchun Ouyang }
331d314f586SNikolay Nikolaev }
332d314f586SNikolay Nikolaev
net_vhost_user_init(NetClientState * peer,const char * device,const char * name,Chardev * chr,int queues)333d314f586SNikolay Nikolaev static int net_vhost_user_init(NetClientState *peer, const char *device,
334f9bb0c1fSJason Wang const char *name, Chardev *chr,
335f9bb0c1fSJason Wang int queues)
336d314f586SNikolay Nikolaev {
33732a6ebecSMarc-André Lureau Error *err = NULL;
338c89804d6SMarc-André Lureau NetClientState *nc, *nc0 = NULL;
3394d0cf552STiwei Bie NetVhostUserState *s = NULL;
3400b99f224SMarc-André Lureau VhostUserState *user;
341b931bfbfSChangchun Ouyang int i;
342d314f586SNikolay Nikolaev
343c1bf3531SMarc-André Lureau assert(name);
344c1bf3531SMarc-André Lureau assert(queues > 0);
345c1bf3531SMarc-André Lureau
3460b99f224SMarc-André Lureau user = g_new0(struct VhostUserState, 1);
347b931bfbfSChangchun Ouyang for (i = 0; i < queues; i++) {
348d314f586SNikolay Nikolaev nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
34953b85d95SLaurent Vivier qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label);
350b931bfbfSChangchun Ouyang nc->queue_index = i;
3515d300164SMarc-André Lureau if (!nc0) {
3525d300164SMarc-André Lureau nc0 = nc;
353703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, nc);
3540b99f224SMarc-André Lureau if (!qemu_chr_fe_init(&s->chr, chr, &err) ||
3550b99f224SMarc-André Lureau !vhost_user_init(user, &s->chr, &err)) {
35632a6ebecSMarc-André Lureau error_report_err(err);
3574d0cf552STiwei Bie goto err;
35832a6ebecSMarc-André Lureau }
359b931bfbfSChangchun Ouyang }
3604d0cf552STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, nc);
3614d0cf552STiwei Bie s->vhost_user = user;
3625d300164SMarc-André Lureau }
3635d300164SMarc-André Lureau
364703878e2STiwei Bie s = DO_UPCAST(NetVhostUserState, nc, nc0);
365c89804d6SMarc-André Lureau do {
3665345fdb4SMarc-André Lureau if (qemu_chr_fe_wait_connected(&s->chr, &err) < 0) {
367c89804d6SMarc-André Lureau error_report_err(err);
3684d0cf552STiwei Bie goto err;
369c89804d6SMarc-André Lureau }
3705345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, NULL, NULL,
37181517ba3SAnton Nefedov net_vhost_user_event, NULL, nc0->name, NULL,
37281517ba3SAnton Nefedov true);
373c89804d6SMarc-André Lureau } while (!s->started);
374d345ed2dSMichael S. Tsirkin
3751a5b68ceSMarc-André Lureau assert(s->vhost_net);
3761a5b68ceSMarc-André Lureau
377d314f586SNikolay Nikolaev return 0;
3784d0cf552STiwei Bie
3794d0cf552STiwei Bie err:
3804d0cf552STiwei Bie if (user) {
3814d0cf552STiwei Bie vhost_user_cleanup(user);
3824d0cf552STiwei Bie g_free(user);
3834d0cf552STiwei Bie if (s) {
3844d0cf552STiwei Bie s->vhost_user = NULL;
3854d0cf552STiwei Bie }
3864d0cf552STiwei Bie }
387c67daf4aSlinzhecheng if (nc0) {
388c67daf4aSlinzhecheng qemu_del_net_client(nc0);
389c67daf4aSlinzhecheng }
3904d0cf552STiwei Bie
3914d0cf552STiwei Bie return -1;
392d314f586SNikolay Nikolaev }
393d314f586SNikolay Nikolaev
net_vhost_claim_chardev(const NetdevVhostUserOptions * opts,Error ** errp)3940ec7b3e7SMarc-André Lureau static Chardev *net_vhost_claim_chardev(
39581904831SMarkus Armbruster const NetdevVhostUserOptions *opts, Error **errp)
39603ce5744SNikolay Nikolaev {
3970ec7b3e7SMarc-André Lureau Chardev *chr = qemu_chr_find(opts->chardev);
39803ce5744SNikolay Nikolaev
39903ce5744SNikolay Nikolaev if (chr == NULL) {
40081904831SMarkus Armbruster error_setg(errp, "chardev \"%s\" not found", opts->chardev);
40103ce5744SNikolay Nikolaev return NULL;
40203ce5744SNikolay Nikolaev }
40303ce5744SNikolay Nikolaev
4040a73336dSDaniel P. Berrange if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE)) {
4050a73336dSDaniel P. Berrange error_setg(errp, "chardev \"%s\" is not reconnectable",
4060a73336dSDaniel P. Berrange opts->chardev);
40703ce5744SNikolay Nikolaev return NULL;
40803ce5744SNikolay Nikolaev }
4090a73336dSDaniel P. Berrange if (!qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_FD_PASS)) {
4100a73336dSDaniel P. Berrange error_setg(errp, "chardev \"%s\" does not support FD passing",
41103ce5744SNikolay Nikolaev opts->chardev);
41203ce5744SNikolay Nikolaev return NULL;
41303ce5744SNikolay Nikolaev }
41403ce5744SNikolay Nikolaev
41503ce5744SNikolay Nikolaev return chr;
41603ce5744SNikolay Nikolaev }
41703ce5744SNikolay Nikolaev
net_init_vhost_user(const Netdev * netdev,const char * name,NetClientState * peer,Error ** errp)418cebea510SKővágó, Zoltán int net_init_vhost_user(const Netdev *netdev, const char *name,
419a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp)
420d314f586SNikolay Nikolaev {
421b931bfbfSChangchun Ouyang int queues;
42203ce5744SNikolay Nikolaev const NetdevVhostUserOptions *vhost_user_opts;
4230ec7b3e7SMarc-André Lureau Chardev *chr;
42403ce5744SNikolay Nikolaev
425f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
426f394b2e2SEric Blake vhost_user_opts = &netdev->u.vhost_user;
42703ce5744SNikolay Nikolaev
4280a73336dSDaniel P. Berrange chr = net_vhost_claim_chardev(vhost_user_opts, errp);
42903ce5744SNikolay Nikolaev if (!chr) {
43003ce5744SNikolay Nikolaev return -1;
43103ce5744SNikolay Nikolaev }
43203ce5744SNikolay Nikolaev
433b931bfbfSChangchun Ouyang queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
434fff4e48eSIlya Maximets if (queues < 1 || queues > MAX_QUEUE_NUM) {
4356f6f9512SVictor Kaplansky error_setg(errp,
436fff4e48eSIlya Maximets "vhost-user number of queues must be in range [1, %d]",
437fff4e48eSIlya Maximets MAX_QUEUE_NUM);
4386f6f9512SVictor Kaplansky return -1;
4396f6f9512SVictor Kaplansky }
44003ce5744SNikolay Nikolaev
441f9bb0c1fSJason Wang return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
442d314f586SNikolay Nikolaev }
443