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 } 849