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