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