vhost: add pipe event for optimizing negotiation
[dpdk.git] / lib / librte_vhost / socket.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <limits.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/un.h>
14 #include <sys/queue.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <pthread.h>
18
19 #include <rte_log.h>
20
21 #include "fd_man.h"
22 #include "vhost.h"
23 #include "vhost_user.h"
24
25
26 TAILQ_HEAD(vhost_user_connection_list, vhost_user_connection);
27
28 /*
29  * Every time rte_vhost_driver_register() is invoked, an associated
30  * vhost_user_socket struct will be created.
31  */
32 struct vhost_user_socket {
33         struct vhost_user_connection_list conn_list;
34         pthread_mutex_t conn_mutex;
35         char *path;
36         int socket_fd;
37         struct sockaddr_un un;
38         bool is_server;
39         bool reconnect;
40         bool dequeue_zero_copy;
41         bool iommu_support;
42         bool use_builtin_virtio_net;
43
44         /*
45          * The "supported_features" indicates the feature bits the
46          * vhost driver supports. The "features" indicates the feature
47          * bits after the rte_vhost_driver_features_disable/enable().
48          * It is also the final feature bits used for vhost-user
49          * features negotiation.
50          */
51         uint64_t supported_features;
52         uint64_t features;
53
54         struct vhost_device_ops const *notify_ops;
55 };
56
57 struct vhost_user_connection {
58         struct vhost_user_socket *vsocket;
59         int connfd;
60         int vid;
61
62         TAILQ_ENTRY(vhost_user_connection) next;
63 };
64
65 #define MAX_VHOST_SOCKET 1024
66 struct vhost_user {
67         struct vhost_user_socket *vsockets[MAX_VHOST_SOCKET];
68         struct fdset fdset;
69         int vsocket_cnt;
70         pthread_mutex_t mutex;
71 };
72
73 #define MAX_VIRTIO_BACKLOG 128
74
75 static void vhost_user_server_new_connection(int fd, void *data, int *remove);
76 static void vhost_user_read_cb(int fd, void *dat, int *remove);
77 static int create_unix_socket(struct vhost_user_socket *vsocket);
78 static int vhost_user_start_client(struct vhost_user_socket *vsocket);
79
80 static struct vhost_user vhost_user = {
81         .fdset = {
82                 .fd = { [0 ... MAX_FDS - 1] = {-1, NULL, NULL, NULL, 0} },
83                 .fd_mutex = PTHREAD_MUTEX_INITIALIZER,
84                 .num = 0
85         },
86         .vsocket_cnt = 0,
87         .mutex = PTHREAD_MUTEX_INITIALIZER,
88 };
89
90 /* return bytes# of read on success or negative val on failure. */
91 int
92 read_fd_message(int sockfd, char *buf, int buflen, int *fds, int fd_num)
93 {
94         struct iovec iov;
95         struct msghdr msgh;
96         size_t fdsize = fd_num * sizeof(int);
97         char control[CMSG_SPACE(fdsize)];
98         struct cmsghdr *cmsg;
99         int got_fds = 0;
100         int ret;
101
102         memset(&msgh, 0, sizeof(msgh));
103         iov.iov_base = buf;
104         iov.iov_len  = buflen;
105
106         msgh.msg_iov = &iov;
107         msgh.msg_iovlen = 1;
108         msgh.msg_control = control;
109         msgh.msg_controllen = sizeof(control);
110
111         ret = recvmsg(sockfd, &msgh, 0);
112         if (ret <= 0) {
113                 RTE_LOG(ERR, VHOST_CONFIG, "recvmsg failed\n");
114                 return ret;
115         }
116
117         if (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
118                 RTE_LOG(ERR, VHOST_CONFIG, "truncted msg\n");
119                 return -1;
120         }
121
122         for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
123                 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
124                 if ((cmsg->cmsg_level == SOL_SOCKET) &&
125                         (cmsg->cmsg_type == SCM_RIGHTS)) {
126                         got_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
127                         memcpy(fds, CMSG_DATA(cmsg), got_fds * sizeof(int));
128                         break;
129                 }
130         }
131
132         /* Clear out unused file descriptors */
133         while (got_fds < fd_num)
134                 fds[got_fds++] = -1;
135
136         return ret;
137 }
138
139 int
140 send_fd_message(int sockfd, char *buf, int buflen, int *fds, int fd_num)
141 {
142
143         struct iovec iov;
144         struct msghdr msgh;
145         size_t fdsize = fd_num * sizeof(int);
146         char control[CMSG_SPACE(fdsize)];
147         struct cmsghdr *cmsg;
148         int ret;
149
150         memset(&msgh, 0, sizeof(msgh));
151         iov.iov_base = buf;
152         iov.iov_len = buflen;
153
154         msgh.msg_iov = &iov;
155         msgh.msg_iovlen = 1;
156
157         if (fds && fd_num > 0) {
158                 msgh.msg_control = control;
159                 msgh.msg_controllen = sizeof(control);
160                 cmsg = CMSG_FIRSTHDR(&msgh);
161                 if (cmsg == NULL) {
162                         RTE_LOG(ERR, VHOST_CONFIG, "cmsg == NULL\n");
163                         errno = EINVAL;
164                         return -1;
165                 }
166                 cmsg->cmsg_len = CMSG_LEN(fdsize);
167                 cmsg->cmsg_level = SOL_SOCKET;
168                 cmsg->cmsg_type = SCM_RIGHTS;
169                 memcpy(CMSG_DATA(cmsg), fds, fdsize);
170         } else {
171                 msgh.msg_control = NULL;
172                 msgh.msg_controllen = 0;
173         }
174
175         do {
176                 ret = sendmsg(sockfd, &msgh, MSG_NOSIGNAL);
177         } while (ret < 0 && errno == EINTR);
178
179         if (ret < 0) {
180                 RTE_LOG(ERR, VHOST_CONFIG,  "sendmsg error\n");
181                 return ret;
182         }
183
184         return ret;
185 }
186
187 static void
188 vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
189 {
190         int vid;
191         size_t size;
192         struct vhost_user_connection *conn;
193         int ret;
194
195         conn = malloc(sizeof(*conn));
196         if (conn == NULL) {
197                 close(fd);
198                 return;
199         }
200
201         vid = vhost_new_device();
202         if (vid == -1) {
203                 goto err;
204         }
205
206         size = strnlen(vsocket->path, PATH_MAX);
207         vhost_set_ifname(vid, vsocket->path, size);
208
209         vhost_set_builtin_virtio_net(vid, vsocket->use_builtin_virtio_net);
210
211         if (vsocket->dequeue_zero_copy)
212                 vhost_enable_dequeue_zero_copy(vid);
213
214         RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
215
216         if (vsocket->notify_ops->new_connection) {
217                 ret = vsocket->notify_ops->new_connection(vid);
218                 if (ret < 0) {
219                         RTE_LOG(ERR, VHOST_CONFIG,
220                                 "failed to add vhost user connection with fd %d\n",
221                                 fd);
222                         goto err;
223                 }
224         }
225
226         conn->connfd = fd;
227         conn->vsocket = vsocket;
228         conn->vid = vid;
229         ret = fdset_add(&vhost_user.fdset, fd, vhost_user_read_cb,
230                         NULL, conn);
231         if (ret < 0) {
232                 RTE_LOG(ERR, VHOST_CONFIG,
233                         "failed to add fd %d into vhost server fdset\n",
234                         fd);
235
236                 if (vsocket->notify_ops->destroy_connection)
237                         vsocket->notify_ops->destroy_connection(conn->vid);
238
239                 goto err;
240         }
241
242         pthread_mutex_lock(&vsocket->conn_mutex);
243         TAILQ_INSERT_TAIL(&vsocket->conn_list, conn, next);
244         pthread_mutex_unlock(&vsocket->conn_mutex);
245
246         fdset_pipe_notify(&vhost_user.fdset);
247         return;
248
249 err:
250         free(conn);
251         close(fd);
252 }
253
254 /* call back when there is new vhost-user connection from client  */
255 static void
256 vhost_user_server_new_connection(int fd, void *dat, int *remove __rte_unused)
257 {
258         struct vhost_user_socket *vsocket = dat;
259
260         fd = accept(fd, NULL, NULL);
261         if (fd < 0)
262                 return;
263
264         RTE_LOG(INFO, VHOST_CONFIG, "new vhost user connection is %d\n", fd);
265         vhost_user_add_connection(fd, vsocket);
266 }
267
268 static void
269 vhost_user_read_cb(int connfd, void *dat, int *remove)
270 {
271         struct vhost_user_connection *conn = dat;
272         struct vhost_user_socket *vsocket = conn->vsocket;
273         int ret;
274
275         ret = vhost_user_msg_handler(conn->vid, connfd);
276         if (ret < 0) {
277                 close(connfd);
278                 *remove = 1;
279                 vhost_destroy_device(conn->vid);
280
281                 if (vsocket->notify_ops->destroy_connection)
282                         vsocket->notify_ops->destroy_connection(conn->vid);
283
284                 pthread_mutex_lock(&vsocket->conn_mutex);
285                 TAILQ_REMOVE(&vsocket->conn_list, conn, next);
286                 pthread_mutex_unlock(&vsocket->conn_mutex);
287
288                 free(conn);
289
290                 if (vsocket->reconnect) {
291                         create_unix_socket(vsocket);
292                         vhost_user_start_client(vsocket);
293                 }
294         }
295 }
296
297 static int
298 create_unix_socket(struct vhost_user_socket *vsocket)
299 {
300         int fd;
301         struct sockaddr_un *un = &vsocket->un;
302
303         fd = socket(AF_UNIX, SOCK_STREAM, 0);
304         if (fd < 0)
305                 return -1;
306         RTE_LOG(INFO, VHOST_CONFIG, "vhost-user %s: socket created, fd: %d\n",
307                 vsocket->is_server ? "server" : "client", fd);
308
309         if (!vsocket->is_server && fcntl(fd, F_SETFL, O_NONBLOCK)) {
310                 RTE_LOG(ERR, VHOST_CONFIG,
311                         "vhost-user: can't set nonblocking mode for socket, fd: "
312                         "%d (%s)\n", fd, strerror(errno));
313                 close(fd);
314                 return -1;
315         }
316
317         memset(un, 0, sizeof(*un));
318         un->sun_family = AF_UNIX;
319         strncpy(un->sun_path, vsocket->path, sizeof(un->sun_path));
320         un->sun_path[sizeof(un->sun_path) - 1] = '\0';
321
322         vsocket->socket_fd = fd;
323         return 0;
324 }
325
326 static int
327 vhost_user_start_server(struct vhost_user_socket *vsocket)
328 {
329         int ret;
330         int fd = vsocket->socket_fd;
331         const char *path = vsocket->path;
332
333         /*
334          * bind () may fail if the socket file with the same name already
335          * exists. But the library obviously should not delete the file
336          * provided by the user, since we can not be sure that it is not
337          * being used by other applications. Moreover, many applications form
338          * socket names based on user input, which is prone to errors.
339          *
340          * The user must ensure that the socket does not exist before
341          * registering the vhost driver in server mode.
342          */
343         ret = bind(fd, (struct sockaddr *)&vsocket->un, sizeof(vsocket->un));
344         if (ret < 0) {
345                 RTE_LOG(ERR, VHOST_CONFIG,
346                         "failed to bind to %s: %s; remove it and try again\n",
347                         path, strerror(errno));
348                 goto err;
349         }
350         RTE_LOG(INFO, VHOST_CONFIG, "bind to %s\n", path);
351
352         ret = listen(fd, MAX_VIRTIO_BACKLOG);
353         if (ret < 0)
354                 goto err;
355
356         ret = fdset_add(&vhost_user.fdset, fd, vhost_user_server_new_connection,
357                   NULL, vsocket);
358         if (ret < 0) {
359                 RTE_LOG(ERR, VHOST_CONFIG,
360                         "failed to add listen fd %d to vhost server fdset\n",
361                         fd);
362                 goto err;
363         }
364
365         return 0;
366
367 err:
368         close(fd);
369         return -1;
370 }
371
372 struct vhost_user_reconnect {
373         struct sockaddr_un un;
374         int fd;
375         struct vhost_user_socket *vsocket;
376
377         TAILQ_ENTRY(vhost_user_reconnect) next;
378 };
379
380 TAILQ_HEAD(vhost_user_reconnect_tailq_list, vhost_user_reconnect);
381 struct vhost_user_reconnect_list {
382         struct vhost_user_reconnect_tailq_list head;
383         pthread_mutex_t mutex;
384 };
385
386 static struct vhost_user_reconnect_list reconn_list;
387 static pthread_t reconn_tid;
388
389 static int
390 vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
391 {
392         int ret, flags;
393
394         ret = connect(fd, un, sz);
395         if (ret < 0 && errno != EISCONN)
396                 return -1;
397
398         flags = fcntl(fd, F_GETFL, 0);
399         if (flags < 0) {
400                 RTE_LOG(ERR, VHOST_CONFIG,
401                         "can't get flags for connfd %d\n", fd);
402                 return -2;
403         }
404         if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags & ~O_NONBLOCK)) {
405                 RTE_LOG(ERR, VHOST_CONFIG,
406                                 "can't disable nonblocking on fd %d\n", fd);
407                 return -2;
408         }
409         return 0;
410 }
411
412 static void *
413 vhost_user_client_reconnect(void *arg __rte_unused)
414 {
415         int ret;
416         struct vhost_user_reconnect *reconn, *next;
417
418         while (1) {
419                 pthread_mutex_lock(&reconn_list.mutex);
420
421                 /*
422                  * An equal implementation of TAILQ_FOREACH_SAFE,
423                  * which does not exist on all platforms.
424                  */
425                 for (reconn = TAILQ_FIRST(&reconn_list.head);
426                      reconn != NULL; reconn = next) {
427                         next = TAILQ_NEXT(reconn, next);
428
429                         ret = vhost_user_connect_nonblock(reconn->fd,
430                                                 (struct sockaddr *)&reconn->un,
431                                                 sizeof(reconn->un));
432                         if (ret == -2) {
433                                 close(reconn->fd);
434                                 RTE_LOG(ERR, VHOST_CONFIG,
435                                         "reconnection for fd %d failed\n",
436                                         reconn->fd);
437                                 goto remove_fd;
438                         }
439                         if (ret == -1)
440                                 continue;
441
442                         RTE_LOG(INFO, VHOST_CONFIG,
443                                 "%s: connected\n", reconn->vsocket->path);
444                         vhost_user_add_connection(reconn->fd, reconn->vsocket);
445 remove_fd:
446                         TAILQ_REMOVE(&reconn_list.head, reconn, next);
447                         free(reconn);
448                 }
449
450                 pthread_mutex_unlock(&reconn_list.mutex);
451                 sleep(1);
452         }
453
454         return NULL;
455 }
456
457 static int
458 vhost_user_reconnect_init(void)
459 {
460         int ret;
461         char thread_name[RTE_MAX_THREAD_NAME_LEN];
462
463         ret = pthread_mutex_init(&reconn_list.mutex, NULL);
464         if (ret < 0) {
465                 RTE_LOG(ERR, VHOST_CONFIG, "failed to initialize mutex");
466                 return ret;
467         }
468         TAILQ_INIT(&reconn_list.head);
469
470         ret = pthread_create(&reconn_tid, NULL,
471                              vhost_user_client_reconnect, NULL);
472         if (ret != 0) {
473                 RTE_LOG(ERR, VHOST_CONFIG, "failed to create reconnect thread");
474                 if (pthread_mutex_destroy(&reconn_list.mutex)) {
475                         RTE_LOG(ERR, VHOST_CONFIG,
476                                 "failed to destroy reconnect mutex");
477                 }
478         } else {
479                 snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,
480                          "vhost-reconn");
481
482                 if (rte_thread_setname(reconn_tid, thread_name)) {
483                         RTE_LOG(DEBUG, VHOST_CONFIG,
484                                 "failed to set reconnect thread name");
485                 }
486         }
487
488         return ret;
489 }
490
491 static int
492 vhost_user_start_client(struct vhost_user_socket *vsocket)
493 {
494         int ret;
495         int fd = vsocket->socket_fd;
496         const char *path = vsocket->path;
497         struct vhost_user_reconnect *reconn;
498
499         ret = vhost_user_connect_nonblock(fd, (struct sockaddr *)&vsocket->un,
500                                           sizeof(vsocket->un));
501         if (ret == 0) {
502                 vhost_user_add_connection(fd, vsocket);
503                 return 0;
504         }
505
506         RTE_LOG(WARNING, VHOST_CONFIG,
507                 "failed to connect to %s: %s\n",
508                 path, strerror(errno));
509
510         if (ret == -2 || !vsocket->reconnect) {
511                 close(fd);
512                 return -1;
513         }
514
515         RTE_LOG(INFO, VHOST_CONFIG, "%s: reconnecting...\n", path);
516         reconn = malloc(sizeof(*reconn));
517         if (reconn == NULL) {
518                 RTE_LOG(ERR, VHOST_CONFIG,
519                         "failed to allocate memory for reconnect\n");
520                 close(fd);
521                 return -1;
522         }
523         reconn->un = vsocket->un;
524         reconn->fd = fd;
525         reconn->vsocket = vsocket;
526         pthread_mutex_lock(&reconn_list.mutex);
527         TAILQ_INSERT_TAIL(&reconn_list.head, reconn, next);
528         pthread_mutex_unlock(&reconn_list.mutex);
529
530         return 0;
531 }
532
533 static struct vhost_user_socket *
534 find_vhost_user_socket(const char *path)
535 {
536         int i;
537
538         for (i = 0; i < vhost_user.vsocket_cnt; i++) {
539                 struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
540
541                 if (!strcmp(vsocket->path, path))
542                         return vsocket;
543         }
544
545         return NULL;
546 }
547
548 int
549 rte_vhost_driver_disable_features(const char *path, uint64_t features)
550 {
551         struct vhost_user_socket *vsocket;
552
553         pthread_mutex_lock(&vhost_user.mutex);
554         vsocket = find_vhost_user_socket(path);
555
556         /* Note that use_builtin_virtio_net is not affected by this function
557          * since callers may want to selectively disable features of the
558          * built-in vhost net device backend.
559          */
560
561         if (vsocket)
562                 vsocket->features &= ~features;
563         pthread_mutex_unlock(&vhost_user.mutex);
564
565         return vsocket ? 0 : -1;
566 }
567
568 int
569 rte_vhost_driver_enable_features(const char *path, uint64_t features)
570 {
571         struct vhost_user_socket *vsocket;
572
573         pthread_mutex_lock(&vhost_user.mutex);
574         vsocket = find_vhost_user_socket(path);
575         if (vsocket) {
576                 if ((vsocket->supported_features & features) != features) {
577                         /*
578                          * trying to enable features the driver doesn't
579                          * support.
580                          */
581                         pthread_mutex_unlock(&vhost_user.mutex);
582                         return -1;
583                 }
584                 vsocket->features |= features;
585         }
586         pthread_mutex_unlock(&vhost_user.mutex);
587
588         return vsocket ? 0 : -1;
589 }
590
591 int
592 rte_vhost_driver_set_features(const char *path, uint64_t features)
593 {
594         struct vhost_user_socket *vsocket;
595
596         pthread_mutex_lock(&vhost_user.mutex);
597         vsocket = find_vhost_user_socket(path);
598         if (vsocket) {
599                 vsocket->supported_features = features;
600                 vsocket->features = features;
601
602                 /* Anyone setting feature bits is implementing their own vhost
603                  * device backend.
604                  */
605                 vsocket->use_builtin_virtio_net = false;
606         }
607         pthread_mutex_unlock(&vhost_user.mutex);
608
609         return vsocket ? 0 : -1;
610 }
611
612 int
613 rte_vhost_driver_get_features(const char *path, uint64_t *features)
614 {
615         struct vhost_user_socket *vsocket;
616
617         pthread_mutex_lock(&vhost_user.mutex);
618         vsocket = find_vhost_user_socket(path);
619         if (vsocket)
620                 *features = vsocket->features;
621         pthread_mutex_unlock(&vhost_user.mutex);
622
623         if (!vsocket) {
624                 RTE_LOG(ERR, VHOST_CONFIG,
625                         "socket file %s is not registered yet.\n", path);
626                 return -1;
627         } else {
628                 return 0;
629         }
630 }
631
632 /*
633  * Register a new vhost-user socket; here we could act as server
634  * (the default case), or client (when RTE_VHOST_USER_CLIENT) flag
635  * is set.
636  */
637 int
638 rte_vhost_driver_register(const char *path, uint64_t flags)
639 {
640         int ret = -1;
641         struct vhost_user_socket *vsocket;
642
643         if (!path)
644                 return -1;
645
646         pthread_mutex_lock(&vhost_user.mutex);
647
648         if (vhost_user.vsocket_cnt == MAX_VHOST_SOCKET) {
649                 RTE_LOG(ERR, VHOST_CONFIG,
650                         "error: the number of vhost sockets reaches maximum\n");
651                 goto out;
652         }
653
654         vsocket = malloc(sizeof(struct vhost_user_socket));
655         if (!vsocket)
656                 goto out;
657         memset(vsocket, 0, sizeof(struct vhost_user_socket));
658         vsocket->path = strdup(path);
659         if (vsocket->path == NULL) {
660                 RTE_LOG(ERR, VHOST_CONFIG,
661                         "error: failed to copy socket path string\n");
662                 free(vsocket);
663                 goto out;
664         }
665         TAILQ_INIT(&vsocket->conn_list);
666         ret = pthread_mutex_init(&vsocket->conn_mutex, NULL);
667         if (ret) {
668                 RTE_LOG(ERR, VHOST_CONFIG,
669                         "error: failed to init connection mutex\n");
670                 goto out_free;
671         }
672         vsocket->dequeue_zero_copy = flags & RTE_VHOST_USER_DEQUEUE_ZERO_COPY;
673
674         /*
675          * Set the supported features correctly for the builtin vhost-user
676          * net driver.
677          *
678          * Applications know nothing about features the builtin virtio net
679          * driver (virtio_net.c) supports, thus it's not possible for them
680          * to invoke rte_vhost_driver_set_features(). To workaround it, here
681          * we set it unconditionally. If the application want to implement
682          * another vhost-user driver (say SCSI), it should call the
683          * rte_vhost_driver_set_features(), which will overwrite following
684          * two values.
685          */
686         vsocket->use_builtin_virtio_net = true;
687         vsocket->supported_features = VIRTIO_NET_SUPPORTED_FEATURES;
688         vsocket->features           = VIRTIO_NET_SUPPORTED_FEATURES;
689
690         if (!(flags & RTE_VHOST_USER_IOMMU_SUPPORT)) {
691                 vsocket->supported_features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
692                 vsocket->features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
693         }
694
695         if ((flags & RTE_VHOST_USER_CLIENT) != 0) {
696                 vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT);
697                 if (vsocket->reconnect && reconn_tid == 0) {
698                         if (vhost_user_reconnect_init() != 0)
699                                 goto out_mutex;
700                 }
701         } else {
702                 vsocket->is_server = true;
703         }
704         ret = create_unix_socket(vsocket);
705         if (ret < 0) {
706                 goto out_mutex;
707         }
708
709         vhost_user.vsockets[vhost_user.vsocket_cnt++] = vsocket;
710
711         pthread_mutex_unlock(&vhost_user.mutex);
712         return ret;
713
714 out_mutex:
715         if (pthread_mutex_destroy(&vsocket->conn_mutex)) {
716                 RTE_LOG(ERR, VHOST_CONFIG,
717                         "error: failed to destroy connection mutex\n");
718         }
719 out_free:
720         free(vsocket->path);
721         free(vsocket);
722 out:
723         pthread_mutex_unlock(&vhost_user.mutex);
724
725         return ret;
726 }
727
728 static bool
729 vhost_user_remove_reconnect(struct vhost_user_socket *vsocket)
730 {
731         int found = false;
732         struct vhost_user_reconnect *reconn, *next;
733
734         pthread_mutex_lock(&reconn_list.mutex);
735
736         for (reconn = TAILQ_FIRST(&reconn_list.head);
737              reconn != NULL; reconn = next) {
738                 next = TAILQ_NEXT(reconn, next);
739
740                 if (reconn->vsocket == vsocket) {
741                         TAILQ_REMOVE(&reconn_list.head, reconn, next);
742                         close(reconn->fd);
743                         free(reconn);
744                         found = true;
745                         break;
746                 }
747         }
748         pthread_mutex_unlock(&reconn_list.mutex);
749         return found;
750 }
751
752 /**
753  * Unregister the specified vhost socket
754  */
755 int
756 rte_vhost_driver_unregister(const char *path)
757 {
758         int i;
759         int count;
760         struct vhost_user_connection *conn, *next;
761
762         pthread_mutex_lock(&vhost_user.mutex);
763
764         for (i = 0; i < vhost_user.vsocket_cnt; i++) {
765                 struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
766
767                 if (!strcmp(vsocket->path, path)) {
768                         if (vsocket->is_server) {
769                                 fdset_del(&vhost_user.fdset, vsocket->socket_fd);
770                                 close(vsocket->socket_fd);
771                                 unlink(path);
772                         } else if (vsocket->reconnect) {
773                                 vhost_user_remove_reconnect(vsocket);
774                         }
775
776                         pthread_mutex_lock(&vsocket->conn_mutex);
777                         for (conn = TAILQ_FIRST(&vsocket->conn_list);
778                              conn != NULL;
779                              conn = next) {
780                                 next = TAILQ_NEXT(conn, next);
781
782                                 fdset_del(&vhost_user.fdset, conn->connfd);
783                                 RTE_LOG(INFO, VHOST_CONFIG,
784                                         "free connfd = %d for device '%s'\n",
785                                         conn->connfd, path);
786                                 close(conn->connfd);
787                                 vhost_destroy_device(conn->vid);
788                                 TAILQ_REMOVE(&vsocket->conn_list, conn, next);
789                                 free(conn);
790                         }
791                         pthread_mutex_unlock(&vsocket->conn_mutex);
792
793                         pthread_mutex_destroy(&vsocket->conn_mutex);
794                         free(vsocket->path);
795                         free(vsocket);
796
797                         count = --vhost_user.vsocket_cnt;
798                         vhost_user.vsockets[i] = vhost_user.vsockets[count];
799                         vhost_user.vsockets[count] = NULL;
800                         pthread_mutex_unlock(&vhost_user.mutex);
801
802                         return 0;
803                 }
804         }
805         pthread_mutex_unlock(&vhost_user.mutex);
806
807         return -1;
808 }
809
810 /*
811  * Register ops so that we can add/remove device to data core.
812  */
813 int
814 rte_vhost_driver_callback_register(const char *path,
815         struct vhost_device_ops const * const ops)
816 {
817         struct vhost_user_socket *vsocket;
818
819         pthread_mutex_lock(&vhost_user.mutex);
820         vsocket = find_vhost_user_socket(path);
821         if (vsocket)
822                 vsocket->notify_ops = ops;
823         pthread_mutex_unlock(&vhost_user.mutex);
824
825         return vsocket ? 0 : -1;
826 }
827
828 struct vhost_device_ops const *
829 vhost_driver_callback_get(const char *path)
830 {
831         struct vhost_user_socket *vsocket;
832
833         pthread_mutex_lock(&vhost_user.mutex);
834         vsocket = find_vhost_user_socket(path);
835         pthread_mutex_unlock(&vhost_user.mutex);
836
837         return vsocket ? vsocket->notify_ops : NULL;
838 }
839
840 int
841 rte_vhost_driver_start(const char *path)
842 {
843         struct vhost_user_socket *vsocket;
844         static pthread_t fdset_tid;
845         char thread_name[RTE_MAX_THREAD_NAME_LEN];
846
847         pthread_mutex_lock(&vhost_user.mutex);
848         vsocket = find_vhost_user_socket(path);
849         pthread_mutex_unlock(&vhost_user.mutex);
850
851         if (!vsocket)
852                 return -1;
853
854         if (fdset_tid == 0) {
855                 /**
856                  * create a pipe which will be waited by poll and notified to
857                  * rebuild the wait list of poll.
858                  */
859                 if (fdset_pipe_init(&vhost_user.fdset) < 0) {
860                         RTE_LOG(ERR, VHOST_CONFIG,
861                                 "failed to create pipe for vhost fdset\n");
862                         return -1;
863                 }
864
865                 int ret = pthread_create(&fdset_tid, NULL, fdset_event_dispatch,
866                                      &vhost_user.fdset);
867                 if (ret != 0) {
868                         RTE_LOG(ERR, VHOST_CONFIG,
869                                 "failed to create fdset handling thread");
870
871                         fdset_pipe_uninit(&vhost_user.fdset);
872                         return -1;
873                 } else {
874                         snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,
875                                  "vhost-events");
876
877                         if (rte_thread_setname(fdset_tid, thread_name)) {
878                                 RTE_LOG(DEBUG, VHOST_CONFIG,
879                                         "failed to set vhost-event thread name");
880                         }
881                 }
882         }
883
884         if (vsocket->is_server)
885                 return vhost_user_start_server(vsocket);
886         else
887                 return vhost_user_start_client(vsocket);
888 }