vhost: move stdbool include
[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         return;
246
247 err:
248         free(conn);
249         close(fd);
250 }
251
252 /* call back when there is new vhost-user connection from client  */
253 static void
254 vhost_user_server_new_connection(int fd, void *dat, int *remove __rte_unused)
255 {
256         struct vhost_user_socket *vsocket = dat;
257
258         fd = accept(fd, NULL, NULL);
259         if (fd < 0)
260                 return;
261
262         RTE_LOG(INFO, VHOST_CONFIG, "new vhost user connection is %d\n", fd);
263         vhost_user_add_connection(fd, vsocket);
264 }
265
266 static void
267 vhost_user_read_cb(int connfd, void *dat, int *remove)
268 {
269         struct vhost_user_connection *conn = dat;
270         struct vhost_user_socket *vsocket = conn->vsocket;
271         int ret;
272
273         ret = vhost_user_msg_handler(conn->vid, connfd);
274         if (ret < 0) {
275                 close(connfd);
276                 *remove = 1;
277                 vhost_destroy_device(conn->vid);
278
279                 if (vsocket->notify_ops->destroy_connection)
280                         vsocket->notify_ops->destroy_connection(conn->vid);
281
282                 pthread_mutex_lock(&vsocket->conn_mutex);
283                 TAILQ_REMOVE(&vsocket->conn_list, conn, next);
284                 pthread_mutex_unlock(&vsocket->conn_mutex);
285
286                 free(conn);
287
288                 if (vsocket->reconnect) {
289                         create_unix_socket(vsocket);
290                         vhost_user_start_client(vsocket);
291                 }
292         }
293 }
294
295 static int
296 create_unix_socket(struct vhost_user_socket *vsocket)
297 {
298         int fd;
299         struct sockaddr_un *un = &vsocket->un;
300
301         fd = socket(AF_UNIX, SOCK_STREAM, 0);
302         if (fd < 0)
303                 return -1;
304         RTE_LOG(INFO, VHOST_CONFIG, "vhost-user %s: socket created, fd: %d\n",
305                 vsocket->is_server ? "server" : "client", fd);
306
307         if (!vsocket->is_server && fcntl(fd, F_SETFL, O_NONBLOCK)) {
308                 RTE_LOG(ERR, VHOST_CONFIG,
309                         "vhost-user: can't set nonblocking mode for socket, fd: "
310                         "%d (%s)\n", fd, strerror(errno));
311                 close(fd);
312                 return -1;
313         }
314
315         memset(un, 0, sizeof(*un));
316         un->sun_family = AF_UNIX;
317         strncpy(un->sun_path, vsocket->path, sizeof(un->sun_path));
318         un->sun_path[sizeof(un->sun_path) - 1] = '\0';
319
320         vsocket->socket_fd = fd;
321         return 0;
322 }
323
324 static int
325 vhost_user_start_server(struct vhost_user_socket *vsocket)
326 {
327         int ret;
328         int fd = vsocket->socket_fd;
329         const char *path = vsocket->path;
330
331         /*
332          * bind () may fail if the socket file with the same name already
333          * exists. But the library obviously should not delete the file
334          * provided by the user, since we can not be sure that it is not
335          * being used by other applications. Moreover, many applications form
336          * socket names based on user input, which is prone to errors.
337          *
338          * The user must ensure that the socket does not exist before
339          * registering the vhost driver in server mode.
340          */
341         ret = bind(fd, (struct sockaddr *)&vsocket->un, sizeof(vsocket->un));
342         if (ret < 0) {
343                 RTE_LOG(ERR, VHOST_CONFIG,
344                         "failed to bind to %s: %s; remove it and try again\n",
345                         path, strerror(errno));
346                 goto err;
347         }
348         RTE_LOG(INFO, VHOST_CONFIG, "bind to %s\n", path);
349
350         ret = listen(fd, MAX_VIRTIO_BACKLOG);
351         if (ret < 0)
352                 goto err;
353
354         ret = fdset_add(&vhost_user.fdset, fd, vhost_user_server_new_connection,
355                   NULL, vsocket);
356         if (ret < 0) {
357                 RTE_LOG(ERR, VHOST_CONFIG,
358                         "failed to add listen fd %d to vhost server fdset\n",
359                         fd);
360                 goto err;
361         }
362
363         return 0;
364
365 err:
366         close(fd);
367         return -1;
368 }
369
370 struct vhost_user_reconnect {
371         struct sockaddr_un un;
372         int fd;
373         struct vhost_user_socket *vsocket;
374
375         TAILQ_ENTRY(vhost_user_reconnect) next;
376 };
377
378 TAILQ_HEAD(vhost_user_reconnect_tailq_list, vhost_user_reconnect);
379 struct vhost_user_reconnect_list {
380         struct vhost_user_reconnect_tailq_list head;
381         pthread_mutex_t mutex;
382 };
383
384 static struct vhost_user_reconnect_list reconn_list;
385 static pthread_t reconn_tid;
386
387 static int
388 vhost_user_connect_nonblock(int fd, struct sockaddr *un, size_t sz)
389 {
390         int ret, flags;
391
392         ret = connect(fd, un, sz);
393         if (ret < 0 && errno != EISCONN)
394                 return -1;
395
396         flags = fcntl(fd, F_GETFL, 0);
397         if (flags < 0) {
398                 RTE_LOG(ERR, VHOST_CONFIG,
399                         "can't get flags for connfd %d\n", fd);
400                 return -2;
401         }
402         if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags & ~O_NONBLOCK)) {
403                 RTE_LOG(ERR, VHOST_CONFIG,
404                                 "can't disable nonblocking on fd %d\n", fd);
405                 return -2;
406         }
407         return 0;
408 }
409
410 static void *
411 vhost_user_client_reconnect(void *arg __rte_unused)
412 {
413         int ret;
414         struct vhost_user_reconnect *reconn, *next;
415
416         while (1) {
417                 pthread_mutex_lock(&reconn_list.mutex);
418
419                 /*
420                  * An equal implementation of TAILQ_FOREACH_SAFE,
421                  * which does not exist on all platforms.
422                  */
423                 for (reconn = TAILQ_FIRST(&reconn_list.head);
424                      reconn != NULL; reconn = next) {
425                         next = TAILQ_NEXT(reconn, next);
426
427                         ret = vhost_user_connect_nonblock(reconn->fd,
428                                                 (struct sockaddr *)&reconn->un,
429                                                 sizeof(reconn->un));
430                         if (ret == -2) {
431                                 close(reconn->fd);
432                                 RTE_LOG(ERR, VHOST_CONFIG,
433                                         "reconnection for fd %d failed\n",
434                                         reconn->fd);
435                                 goto remove_fd;
436                         }
437                         if (ret == -1)
438                                 continue;
439
440                         RTE_LOG(INFO, VHOST_CONFIG,
441                                 "%s: connected\n", reconn->vsocket->path);
442                         vhost_user_add_connection(reconn->fd, reconn->vsocket);
443 remove_fd:
444                         TAILQ_REMOVE(&reconn_list.head, reconn, next);
445                         free(reconn);
446                 }
447
448                 pthread_mutex_unlock(&reconn_list.mutex);
449                 sleep(1);
450         }
451
452         return NULL;
453 }
454
455 static int
456 vhost_user_reconnect_init(void)
457 {
458         int ret;
459         char thread_name[RTE_MAX_THREAD_NAME_LEN];
460
461         ret = pthread_mutex_init(&reconn_list.mutex, NULL);
462         if (ret < 0) {
463                 RTE_LOG(ERR, VHOST_CONFIG, "failed to initialize mutex");
464                 return ret;
465         }
466         TAILQ_INIT(&reconn_list.head);
467
468         ret = pthread_create(&reconn_tid, NULL,
469                              vhost_user_client_reconnect, NULL);
470         if (ret != 0) {
471                 RTE_LOG(ERR, VHOST_CONFIG, "failed to create reconnect thread");
472                 if (pthread_mutex_destroy(&reconn_list.mutex)) {
473                         RTE_LOG(ERR, VHOST_CONFIG,
474                                 "failed to destroy reconnect mutex");
475                 }
476         } else {
477                 snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,
478                          "vhost-reconn");
479
480                 if (rte_thread_setname(reconn_tid, thread_name)) {
481                         RTE_LOG(DEBUG, VHOST_CONFIG,
482                                 "failed to set reconnect thread name");
483                 }
484         }
485
486         return ret;
487 }
488
489 static int
490 vhost_user_start_client(struct vhost_user_socket *vsocket)
491 {
492         int ret;
493         int fd = vsocket->socket_fd;
494         const char *path = vsocket->path;
495         struct vhost_user_reconnect *reconn;
496
497         ret = vhost_user_connect_nonblock(fd, (struct sockaddr *)&vsocket->un,
498                                           sizeof(vsocket->un));
499         if (ret == 0) {
500                 vhost_user_add_connection(fd, vsocket);
501                 return 0;
502         }
503
504         RTE_LOG(WARNING, VHOST_CONFIG,
505                 "failed to connect to %s: %s\n",
506                 path, strerror(errno));
507
508         if (ret == -2 || !vsocket->reconnect) {
509                 close(fd);
510                 return -1;
511         }
512
513         RTE_LOG(INFO, VHOST_CONFIG, "%s: reconnecting...\n", path);
514         reconn = malloc(sizeof(*reconn));
515         if (reconn == NULL) {
516                 RTE_LOG(ERR, VHOST_CONFIG,
517                         "failed to allocate memory for reconnect\n");
518                 close(fd);
519                 return -1;
520         }
521         reconn->un = vsocket->un;
522         reconn->fd = fd;
523         reconn->vsocket = vsocket;
524         pthread_mutex_lock(&reconn_list.mutex);
525         TAILQ_INSERT_TAIL(&reconn_list.head, reconn, next);
526         pthread_mutex_unlock(&reconn_list.mutex);
527
528         return 0;
529 }
530
531 static struct vhost_user_socket *
532 find_vhost_user_socket(const char *path)
533 {
534         int i;
535
536         for (i = 0; i < vhost_user.vsocket_cnt; i++) {
537                 struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
538
539                 if (!strcmp(vsocket->path, path))
540                         return vsocket;
541         }
542
543         return NULL;
544 }
545
546 int
547 rte_vhost_driver_disable_features(const char *path, uint64_t features)
548 {
549         struct vhost_user_socket *vsocket;
550
551         pthread_mutex_lock(&vhost_user.mutex);
552         vsocket = find_vhost_user_socket(path);
553
554         /* Note that use_builtin_virtio_net is not affected by this function
555          * since callers may want to selectively disable features of the
556          * built-in vhost net device backend.
557          */
558
559         if (vsocket)
560                 vsocket->features &= ~features;
561         pthread_mutex_unlock(&vhost_user.mutex);
562
563         return vsocket ? 0 : -1;
564 }
565
566 int
567 rte_vhost_driver_enable_features(const char *path, uint64_t features)
568 {
569         struct vhost_user_socket *vsocket;
570
571         pthread_mutex_lock(&vhost_user.mutex);
572         vsocket = find_vhost_user_socket(path);
573         if (vsocket) {
574                 if ((vsocket->supported_features & features) != features) {
575                         /*
576                          * trying to enable features the driver doesn't
577                          * support.
578                          */
579                         pthread_mutex_unlock(&vhost_user.mutex);
580                         return -1;
581                 }
582                 vsocket->features |= features;
583         }
584         pthread_mutex_unlock(&vhost_user.mutex);
585
586         return vsocket ? 0 : -1;
587 }
588
589 int
590 rte_vhost_driver_set_features(const char *path, uint64_t features)
591 {
592         struct vhost_user_socket *vsocket;
593
594         pthread_mutex_lock(&vhost_user.mutex);
595         vsocket = find_vhost_user_socket(path);
596         if (vsocket) {
597                 vsocket->supported_features = features;
598                 vsocket->features = features;
599
600                 /* Anyone setting feature bits is implementing their own vhost
601                  * device backend.
602                  */
603                 vsocket->use_builtin_virtio_net = false;
604         }
605         pthread_mutex_unlock(&vhost_user.mutex);
606
607         return vsocket ? 0 : -1;
608 }
609
610 int
611 rte_vhost_driver_get_features(const char *path, uint64_t *features)
612 {
613         struct vhost_user_socket *vsocket;
614
615         pthread_mutex_lock(&vhost_user.mutex);
616         vsocket = find_vhost_user_socket(path);
617         if (vsocket)
618                 *features = vsocket->features;
619         pthread_mutex_unlock(&vhost_user.mutex);
620
621         if (!vsocket) {
622                 RTE_LOG(ERR, VHOST_CONFIG,
623                         "socket file %s is not registered yet.\n", path);
624                 return -1;
625         } else {
626                 return 0;
627         }
628 }
629
630 /*
631  * Register a new vhost-user socket; here we could act as server
632  * (the default case), or client (when RTE_VHOST_USER_CLIENT) flag
633  * is set.
634  */
635 int
636 rte_vhost_driver_register(const char *path, uint64_t flags)
637 {
638         int ret = -1;
639         struct vhost_user_socket *vsocket;
640
641         if (!path)
642                 return -1;
643
644         pthread_mutex_lock(&vhost_user.mutex);
645
646         if (vhost_user.vsocket_cnt == MAX_VHOST_SOCKET) {
647                 RTE_LOG(ERR, VHOST_CONFIG,
648                         "error: the number of vhost sockets reaches maximum\n");
649                 goto out;
650         }
651
652         vsocket = malloc(sizeof(struct vhost_user_socket));
653         if (!vsocket)
654                 goto out;
655         memset(vsocket, 0, sizeof(struct vhost_user_socket));
656         vsocket->path = strdup(path);
657         if (vsocket->path == NULL) {
658                 RTE_LOG(ERR, VHOST_CONFIG,
659                         "error: failed to copy socket path string\n");
660                 free(vsocket);
661                 goto out;
662         }
663         TAILQ_INIT(&vsocket->conn_list);
664         ret = pthread_mutex_init(&vsocket->conn_mutex, NULL);
665         if (ret) {
666                 RTE_LOG(ERR, VHOST_CONFIG,
667                         "error: failed to init connection mutex\n");
668                 goto out_free;
669         }
670         vsocket->dequeue_zero_copy = flags & RTE_VHOST_USER_DEQUEUE_ZERO_COPY;
671
672         /*
673          * Set the supported features correctly for the builtin vhost-user
674          * net driver.
675          *
676          * Applications know nothing about features the builtin virtio net
677          * driver (virtio_net.c) supports, thus it's not possible for them
678          * to invoke rte_vhost_driver_set_features(). To workaround it, here
679          * we set it unconditionally. If the application want to implement
680          * another vhost-user driver (say SCSI), it should call the
681          * rte_vhost_driver_set_features(), which will overwrite following
682          * two values.
683          */
684         vsocket->use_builtin_virtio_net = true;
685         vsocket->supported_features = VIRTIO_NET_SUPPORTED_FEATURES;
686         vsocket->features           = VIRTIO_NET_SUPPORTED_FEATURES;
687
688         if (!(flags & RTE_VHOST_USER_IOMMU_SUPPORT)) {
689                 vsocket->supported_features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
690                 vsocket->features &= ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
691         }
692
693         if ((flags & RTE_VHOST_USER_CLIENT) != 0) {
694                 vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT);
695                 if (vsocket->reconnect && reconn_tid == 0) {
696                         if (vhost_user_reconnect_init() != 0)
697                                 goto out_mutex;
698                 }
699         } else {
700                 vsocket->is_server = true;
701         }
702         ret = create_unix_socket(vsocket);
703         if (ret < 0) {
704                 goto out_mutex;
705         }
706
707         vhost_user.vsockets[vhost_user.vsocket_cnt++] = vsocket;
708
709         pthread_mutex_unlock(&vhost_user.mutex);
710         return ret;
711
712 out_mutex:
713         if (pthread_mutex_destroy(&vsocket->conn_mutex)) {
714                 RTE_LOG(ERR, VHOST_CONFIG,
715                         "error: failed to destroy connection mutex\n");
716         }
717 out_free:
718         free(vsocket->path);
719         free(vsocket);
720 out:
721         pthread_mutex_unlock(&vhost_user.mutex);
722
723         return ret;
724 }
725
726 static bool
727 vhost_user_remove_reconnect(struct vhost_user_socket *vsocket)
728 {
729         int found = false;
730         struct vhost_user_reconnect *reconn, *next;
731
732         pthread_mutex_lock(&reconn_list.mutex);
733
734         for (reconn = TAILQ_FIRST(&reconn_list.head);
735              reconn != NULL; reconn = next) {
736                 next = TAILQ_NEXT(reconn, next);
737
738                 if (reconn->vsocket == vsocket) {
739                         TAILQ_REMOVE(&reconn_list.head, reconn, next);
740                         close(reconn->fd);
741                         free(reconn);
742                         found = true;
743                         break;
744                 }
745         }
746         pthread_mutex_unlock(&reconn_list.mutex);
747         return found;
748 }
749
750 /**
751  * Unregister the specified vhost socket
752  */
753 int
754 rte_vhost_driver_unregister(const char *path)
755 {
756         int i;
757         int count;
758         struct vhost_user_connection *conn, *next;
759
760         pthread_mutex_lock(&vhost_user.mutex);
761
762         for (i = 0; i < vhost_user.vsocket_cnt; i++) {
763                 struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
764
765                 if (!strcmp(vsocket->path, path)) {
766                         if (vsocket->is_server) {
767                                 fdset_del(&vhost_user.fdset, vsocket->socket_fd);
768                                 close(vsocket->socket_fd);
769                                 unlink(path);
770                         } else if (vsocket->reconnect) {
771                                 vhost_user_remove_reconnect(vsocket);
772                         }
773
774                         pthread_mutex_lock(&vsocket->conn_mutex);
775                         for (conn = TAILQ_FIRST(&vsocket->conn_list);
776                              conn != NULL;
777                              conn = next) {
778                                 next = TAILQ_NEXT(conn, next);
779
780                                 fdset_del(&vhost_user.fdset, conn->connfd);
781                                 RTE_LOG(INFO, VHOST_CONFIG,
782                                         "free connfd = %d for device '%s'\n",
783                                         conn->connfd, path);
784                                 close(conn->connfd);
785                                 vhost_destroy_device(conn->vid);
786                                 TAILQ_REMOVE(&vsocket->conn_list, conn, next);
787                                 free(conn);
788                         }
789                         pthread_mutex_unlock(&vsocket->conn_mutex);
790
791                         pthread_mutex_destroy(&vsocket->conn_mutex);
792                         free(vsocket->path);
793                         free(vsocket);
794
795                         count = --vhost_user.vsocket_cnt;
796                         vhost_user.vsockets[i] = vhost_user.vsockets[count];
797                         vhost_user.vsockets[count] = NULL;
798                         pthread_mutex_unlock(&vhost_user.mutex);
799
800                         return 0;
801                 }
802         }
803         pthread_mutex_unlock(&vhost_user.mutex);
804
805         return -1;
806 }
807
808 /*
809  * Register ops so that we can add/remove device to data core.
810  */
811 int
812 rte_vhost_driver_callback_register(const char *path,
813         struct vhost_device_ops const * const ops)
814 {
815         struct vhost_user_socket *vsocket;
816
817         pthread_mutex_lock(&vhost_user.mutex);
818         vsocket = find_vhost_user_socket(path);
819         if (vsocket)
820                 vsocket->notify_ops = ops;
821         pthread_mutex_unlock(&vhost_user.mutex);
822
823         return vsocket ? 0 : -1;
824 }
825
826 struct vhost_device_ops const *
827 vhost_driver_callback_get(const char *path)
828 {
829         struct vhost_user_socket *vsocket;
830
831         pthread_mutex_lock(&vhost_user.mutex);
832         vsocket = find_vhost_user_socket(path);
833         pthread_mutex_unlock(&vhost_user.mutex);
834
835         return vsocket ? vsocket->notify_ops : NULL;
836 }
837
838 int
839 rte_vhost_driver_start(const char *path)
840 {
841         struct vhost_user_socket *vsocket;
842         static pthread_t fdset_tid;
843         char thread_name[RTE_MAX_THREAD_NAME_LEN];
844
845         pthread_mutex_lock(&vhost_user.mutex);
846         vsocket = find_vhost_user_socket(path);
847         pthread_mutex_unlock(&vhost_user.mutex);
848
849         if (!vsocket)
850                 return -1;
851
852         if (fdset_tid == 0) {
853                 int ret = pthread_create(&fdset_tid, NULL, fdset_event_dispatch,
854                                      &vhost_user.fdset);
855                 if (ret != 0) {
856                         RTE_LOG(ERR, VHOST_CONFIG,
857                                 "failed to create fdset handling thread");
858                         return -1;
859                 } else {
860                         snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,
861                                  "vhost-events");
862
863                         if (rte_thread_setname(fdset_tid, thread_name)) {
864                                 RTE_LOG(DEBUG, VHOST_CONFIG,
865                                         "failed to set vhost-event thread name");
866                         }
867                 }
868         }
869
870         if (vsocket->is_server)
871                 return vhost_user_start_server(vsocket);
872         else
873                 return vhost_user_start_client(vsocket);
874 }