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