1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2017 Intel Corporation 3 */ 4 5 #include <linux/vhost.h> 6 #include <linux/virtio_net.h> 7 #include <stddef.h> 8 #include <stdint.h> 9 #include <stdlib.h> 10 #ifdef RTE_LIBRTE_VHOST_NUMA 11 #include <numa.h> 12 #include <numaif.h> 13 #endif 14 15 #include <rte_errno.h> 16 #include <rte_ethdev.h> 17 #include <rte_log.h> 18 #include <rte_string_fns.h> 19 #include <rte_memory.h> 20 #include <rte_malloc.h> 21 #include <rte_vhost.h> 22 #include <rte_rwlock.h> 23 24 #include "iotlb.h" 25 #include "vhost.h" 26 #include "vhost_user.h" 27 28 struct virtio_net *vhost_devices[MAX_VHOST_DEVICE]; 29 30 /* Called with iotlb_lock read-locked */ 31 uint64_t 32 __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, 33 uint64_t iova, uint64_t *size, uint8_t perm) 34 { 35 uint64_t vva, tmp_size; 36 37 if (unlikely(!*size)) 38 return 0; 39 40 tmp_size = *size; 41 42 vva = vhost_user_iotlb_cache_find(vq, iova, &tmp_size, perm); 43 if (tmp_size == *size) 44 return vva; 45 46 iova += tmp_size; 47 48 if (!vhost_user_iotlb_pending_miss(vq, iova, perm)) { 49 /* 50 * iotlb_lock is read-locked for a full burst, 51 * but it only protects the iotlb cache. 52 * In case of IOTLB miss, we might block on the socket, 53 * which could cause a deadlock with QEMU if an IOTLB update 54 * is being handled. We can safely unlock here to avoid it. 55 */ 56 vhost_user_iotlb_rd_unlock(vq); 57 58 vhost_user_iotlb_pending_insert(vq, iova, perm); 59 if (vhost_user_iotlb_miss(dev, iova, perm)) { 60 RTE_LOG(ERR, VHOST_CONFIG, 61 "IOTLB miss req failed for IOVA 0x%" PRIx64 "\n", 62 iova); 63 vhost_user_iotlb_pending_remove(vq, iova, 1, perm); 64 } 65 66 vhost_user_iotlb_rd_lock(vq); 67 } 68 69 return 0; 70 } 71 72 void 73 cleanup_vq(struct vhost_virtqueue *vq, int destroy) 74 { 75 if ((vq->callfd >= 0) && (destroy != 0)) 76 close(vq->callfd); 77 if (vq->kickfd >= 0) 78 close(vq->kickfd); 79 } 80 81 /* 82 * Unmap any memory, close any file descriptors and 83 * free any memory owned by a device. 84 */ 85 void 86 cleanup_device(struct virtio_net *dev, int destroy) 87 { 88 uint32_t i; 89 90 vhost_backend_cleanup(dev); 91 92 for (i = 0; i < dev->nr_vring; i++) 93 cleanup_vq(dev->virtqueue[i], destroy); 94 } 95 96 void 97 free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) 98 { 99 if (vq_is_packed(dev)) 100 rte_free(vq->shadow_used_packed); 101 else 102 rte_free(vq->shadow_used_split); 103 rte_free(vq->batch_copy_elems); 104 rte_mempool_free(vq->iotlb_pool); 105 rte_free(vq); 106 } 107 108 /* 109 * Release virtqueues and device memory. 110 */ 111 static void 112 free_device(struct virtio_net *dev) 113 { 114 uint32_t i; 115 116 for (i = 0; i < dev->nr_vring; i++) 117 free_vq(dev, dev->virtqueue[i]); 118 119 rte_free(dev); 120 } 121 122 static int 123 vring_translate_split(struct virtio_net *dev, struct vhost_virtqueue *vq) 124 { 125 uint64_t req_size, size; 126 127 req_size = sizeof(struct vring_desc) * vq->size; 128 size = req_size; 129 vq->desc = (struct vring_desc *)(uintptr_t)vhost_iova_to_vva(dev, vq, 130 vq->ring_addrs.desc_user_addr, 131 &size, VHOST_ACCESS_RW); 132 if (!vq->desc || size != req_size) 133 return -1; 134 135 req_size = sizeof(struct vring_avail); 136 req_size += sizeof(uint16_t) * vq->size; 137 if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) 138 req_size += sizeof(uint16_t); 139 size = req_size; 140 vq->avail = (struct vring_avail *)(uintptr_t)vhost_iova_to_vva(dev, vq, 141 vq->ring_addrs.avail_user_addr, 142 &size, VHOST_ACCESS_RW); 143 if (!vq->avail || size != req_size) 144 return -1; 145 146 req_size = sizeof(struct vring_used); 147 req_size += sizeof(struct vring_used_elem) * vq->size; 148 if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) 149 req_size += sizeof(uint16_t); 150 size = req_size; 151 vq->used = (struct vring_used *)(uintptr_t)vhost_iova_to_vva(dev, vq, 152 vq->ring_addrs.used_user_addr, 153 &size, VHOST_ACCESS_RW); 154 if (!vq->used || size != req_size) 155 return -1; 156 157 return 0; 158 } 159 160 static int 161 vring_translate_packed(struct virtio_net *dev, struct vhost_virtqueue *vq) 162 { 163 uint64_t req_size, size; 164 165 req_size = sizeof(struct vring_packed_desc) * vq->size; 166 size = req_size; 167 vq->desc_packed = (struct vring_packed_desc *)(uintptr_t) 168 vhost_iova_to_vva(dev, vq, vq->ring_addrs.desc_user_addr, 169 &size, VHOST_ACCESS_RW); 170 if (!vq->desc_packed || size != req_size) 171 return -1; 172 173 req_size = sizeof(struct vring_packed_desc_event); 174 size = req_size; 175 vq->driver_event = (struct vring_packed_desc_event *)(uintptr_t) 176 vhost_iova_to_vva(dev, vq, vq->ring_addrs.avail_user_addr, 177 &size, VHOST_ACCESS_RW); 178 if (!vq->driver_event || size != req_size) 179 return -1; 180 181 req_size = sizeof(struct vring_packed_desc_event); 182 size = req_size; 183 vq->device_event = (struct vring_packed_desc_event *)(uintptr_t) 184 vhost_iova_to_vva(dev, vq, vq->ring_addrs.used_user_addr, 185 &size, VHOST_ACCESS_RW); 186 if (!vq->device_event || size != req_size) 187 return -1; 188 189 return 0; 190 } 191 192 int 193 vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq) 194 { 195 196 if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) 197 goto out; 198 199 if (vq_is_packed(dev)) { 200 if (vring_translate_packed(dev, vq) < 0) 201 return -1; 202 } else { 203 if (vring_translate_split(dev, vq) < 0) 204 return -1; 205 } 206 out: 207 vq->access_ok = 1; 208 209 return 0; 210 } 211 212 void 213 vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq) 214 { 215 if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)) 216 vhost_user_iotlb_wr_lock(vq); 217 218 vq->access_ok = 0; 219 vq->desc = NULL; 220 vq->avail = NULL; 221 vq->used = NULL; 222 223 if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)) 224 vhost_user_iotlb_wr_unlock(vq); 225 } 226 227 static void 228 init_vring_queue(struct virtio_net *dev, uint32_t vring_idx) 229 { 230 struct vhost_virtqueue *vq; 231 232 if (vring_idx >= VHOST_MAX_VRING) { 233 RTE_LOG(ERR, VHOST_CONFIG, 234 "Failed not init vring, out of bound (%d)\n", 235 vring_idx); 236 return; 237 } 238 239 vq = dev->virtqueue[vring_idx]; 240 241 memset(vq, 0, sizeof(struct vhost_virtqueue)); 242 243 vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD; 244 vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD; 245 246 vhost_user_iotlb_init(dev, vring_idx); 247 /* Backends are set to -1 indicating an inactive device. */ 248 vq->backend = -1; 249 250 TAILQ_INIT(&vq->zmbuf_list); 251 } 252 253 static void 254 reset_vring_queue(struct virtio_net *dev, uint32_t vring_idx) 255 { 256 struct vhost_virtqueue *vq; 257 int callfd; 258 259 if (vring_idx >= VHOST_MAX_VRING) { 260 RTE_LOG(ERR, VHOST_CONFIG, 261 "Failed not init vring, out of bound (%d)\n", 262 vring_idx); 263 return; 264 } 265 266 vq = dev->virtqueue[vring_idx]; 267 callfd = vq->callfd; 268 init_vring_queue(dev, vring_idx); 269 vq->callfd = callfd; 270 } 271 272 int 273 alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx) 274 { 275 struct vhost_virtqueue *vq; 276 277 vq = rte_malloc(NULL, sizeof(struct vhost_virtqueue), 0); 278 if (vq == NULL) { 279 RTE_LOG(ERR, VHOST_CONFIG, 280 "Failed to allocate memory for vring:%u.\n", vring_idx); 281 return -1; 282 } 283 284 dev->virtqueue[vring_idx] = vq; 285 init_vring_queue(dev, vring_idx); 286 rte_spinlock_init(&vq->access_lock); 287 vq->avail_wrap_counter = 1; 288 vq->used_wrap_counter = 1; 289 vq->signalled_used_valid = false; 290 291 dev->nr_vring += 1; 292 293 return 0; 294 } 295 296 /* 297 * Reset some variables in device structure, while keeping few 298 * others untouched, such as vid, ifname, nr_vring: they 299 * should be same unless the device is removed. 300 */ 301 void 302 reset_device(struct virtio_net *dev) 303 { 304 uint32_t i; 305 306 dev->features = 0; 307 dev->protocol_features = 0; 308 dev->flags &= VIRTIO_DEV_BUILTIN_VIRTIO_NET; 309 310 for (i = 0; i < dev->nr_vring; i++) 311 reset_vring_queue(dev, i); 312 } 313 314 /* 315 * Invoked when there is a new vhost-user connection established (when 316 * there is a new virtio device being attached). 317 */ 318 int 319 vhost_new_device(void) 320 { 321 struct virtio_net *dev; 322 int i; 323 324 for (i = 0; i < MAX_VHOST_DEVICE; i++) { 325 if (vhost_devices[i] == NULL) 326 break; 327 } 328 329 if (i == MAX_VHOST_DEVICE) { 330 RTE_LOG(ERR, VHOST_CONFIG, 331 "Failed to find a free slot for new device.\n"); 332 return -1; 333 } 334 335 dev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0); 336 if (dev == NULL) { 337 RTE_LOG(ERR, VHOST_CONFIG, 338 "Failed to allocate memory for new dev.\n"); 339 return -1; 340 } 341 342 vhost_devices[i] = dev; 343 dev->vid = i; 344 dev->flags = VIRTIO_DEV_BUILTIN_VIRTIO_NET; 345 dev->slave_req_fd = -1; 346 dev->vdpa_dev_id = -1; 347 dev->postcopy_ufd = -1; 348 rte_spinlock_init(&dev->slave_req_lock); 349 350 return i; 351 } 352 353 void 354 vhost_destroy_device_notify(struct virtio_net *dev) 355 { 356 struct rte_vdpa_device *vdpa_dev; 357 int did; 358 359 if (dev->flags & VIRTIO_DEV_RUNNING) { 360 did = dev->vdpa_dev_id; 361 vdpa_dev = rte_vdpa_get_device(did); 362 if (vdpa_dev && vdpa_dev->ops->dev_close) 363 vdpa_dev->ops->dev_close(dev->vid); 364 dev->flags &= ~VIRTIO_DEV_RUNNING; 365 dev->notify_ops->destroy_device(dev->vid); 366 } 367 } 368 369 /* 370 * Invoked when there is the vhost-user connection is broken (when 371 * the virtio device is being detached). 372 */ 373 void 374 vhost_destroy_device(int vid) 375 { 376 struct virtio_net *dev = get_device(vid); 377 378 if (dev == NULL) 379 return; 380 381 vhost_destroy_device_notify(dev); 382 383 cleanup_device(dev, 1); 384 free_device(dev); 385 386 vhost_devices[vid] = NULL; 387 } 388 389 void 390 vhost_attach_vdpa_device(int vid, int did) 391 { 392 struct virtio_net *dev = get_device(vid); 393 394 if (dev == NULL) 395 return; 396 397 if (rte_vdpa_get_device(did) == NULL) 398 return; 399 400 dev->vdpa_dev_id = did; 401 } 402 403 void 404 vhost_detach_vdpa_device(int vid) 405 { 406 struct virtio_net *dev = get_device(vid); 407 408 if (dev == NULL) 409 return; 410 411 vhost_user_host_notifier_ctrl(vid, false); 412 413 dev->vdpa_dev_id = -1; 414 } 415 416 void 417 vhost_set_ifname(int vid, const char *if_name, unsigned int if_len) 418 { 419 struct virtio_net *dev; 420 unsigned int len; 421 422 dev = get_device(vid); 423 if (dev == NULL) 424 return; 425 426 len = if_len > sizeof(dev->ifname) ? 427 sizeof(dev->ifname) : if_len; 428 429 strncpy(dev->ifname, if_name, len); 430 dev->ifname[sizeof(dev->ifname) - 1] = '\0'; 431 } 432 433 void 434 vhost_enable_dequeue_zero_copy(int vid) 435 { 436 struct virtio_net *dev = get_device(vid); 437 438 if (dev == NULL) 439 return; 440 441 dev->dequeue_zero_copy = 1; 442 } 443 444 void 445 vhost_set_builtin_virtio_net(int vid, bool enable) 446 { 447 struct virtio_net *dev = get_device(vid); 448 449 if (dev == NULL) 450 return; 451 452 if (enable) 453 dev->flags |= VIRTIO_DEV_BUILTIN_VIRTIO_NET; 454 else 455 dev->flags &= ~VIRTIO_DEV_BUILTIN_VIRTIO_NET; 456 } 457 458 int 459 rte_vhost_get_mtu(int vid, uint16_t *mtu) 460 { 461 struct virtio_net *dev = get_device(vid); 462 463 if (dev == NULL || mtu == NULL) 464 return -ENODEV; 465 466 if (!(dev->flags & VIRTIO_DEV_READY)) 467 return -EAGAIN; 468 469 if (!(dev->features & (1ULL << VIRTIO_NET_F_MTU))) 470 return -ENOTSUP; 471 472 *mtu = dev->mtu; 473 474 return 0; 475 } 476 477 int 478 rte_vhost_get_numa_node(int vid) 479 { 480 #ifdef RTE_LIBRTE_VHOST_NUMA 481 struct virtio_net *dev = get_device(vid); 482 int numa_node; 483 int ret; 484 485 if (dev == NULL || numa_available() != 0) 486 return -1; 487 488 ret = get_mempolicy(&numa_node, NULL, 0, dev, 489 MPOL_F_NODE | MPOL_F_ADDR); 490 if (ret < 0) { 491 RTE_LOG(ERR, VHOST_CONFIG, 492 "(%d) failed to query numa node: %s\n", 493 vid, rte_strerror(errno)); 494 return -1; 495 } 496 497 return numa_node; 498 #else 499 RTE_SET_USED(vid); 500 return -1; 501 #endif 502 } 503 504 uint32_t 505 rte_vhost_get_queue_num(int vid) 506 { 507 struct virtio_net *dev = get_device(vid); 508 509 if (dev == NULL) 510 return 0; 511 512 return dev->nr_vring / 2; 513 } 514 515 uint16_t 516 rte_vhost_get_vring_num(int vid) 517 { 518 struct virtio_net *dev = get_device(vid); 519 520 if (dev == NULL) 521 return 0; 522 523 return dev->nr_vring; 524 } 525 526 int 527 rte_vhost_get_ifname(int vid, char *buf, size_t len) 528 { 529 struct virtio_net *dev = get_device(vid); 530 531 if (dev == NULL || buf == NULL) 532 return -1; 533 534 len = RTE_MIN(len, sizeof(dev->ifname)); 535 536 strncpy(buf, dev->ifname, len); 537 buf[len - 1] = '\0'; 538 539 return 0; 540 } 541 542 int 543 rte_vhost_get_negotiated_features(int vid, uint64_t *features) 544 { 545 struct virtio_net *dev; 546 547 dev = get_device(vid); 548 if (dev == NULL || features == NULL) 549 return -1; 550 551 *features = dev->features; 552 return 0; 553 } 554 555 int 556 rte_vhost_get_mem_table(int vid, struct rte_vhost_memory **mem) 557 { 558 struct virtio_net *dev; 559 struct rte_vhost_memory *m; 560 size_t size; 561 562 dev = get_device(vid); 563 if (dev == NULL || mem == NULL) 564 return -1; 565 566 size = dev->mem->nregions * sizeof(struct rte_vhost_mem_region); 567 m = malloc(sizeof(struct rte_vhost_memory) + size); 568 if (!m) 569 return -1; 570 571 m->nregions = dev->mem->nregions; 572 memcpy(m->regions, dev->mem->regions, size); 573 *mem = m; 574 575 return 0; 576 } 577 578 int 579 rte_vhost_get_vhost_vring(int vid, uint16_t vring_idx, 580 struct rte_vhost_vring *vring) 581 { 582 struct virtio_net *dev; 583 struct vhost_virtqueue *vq; 584 585 dev = get_device(vid); 586 if (dev == NULL || vring == NULL) 587 return -1; 588 589 if (vring_idx >= VHOST_MAX_VRING) 590 return -1; 591 592 vq = dev->virtqueue[vring_idx]; 593 if (!vq) 594 return -1; 595 596 vring->desc = vq->desc; 597 vring->avail = vq->avail; 598 vring->used = vq->used; 599 vring->log_guest_addr = vq->log_guest_addr; 600 601 vring->callfd = vq->callfd; 602 vring->kickfd = vq->kickfd; 603 vring->size = vq->size; 604 605 return 0; 606 } 607 608 int 609 rte_vhost_vring_call(int vid, uint16_t vring_idx) 610 { 611 struct virtio_net *dev; 612 struct vhost_virtqueue *vq; 613 614 dev = get_device(vid); 615 if (!dev) 616 return -1; 617 618 if (vring_idx >= VHOST_MAX_VRING) 619 return -1; 620 621 vq = dev->virtqueue[vring_idx]; 622 if (!vq) 623 return -1; 624 625 if (vq_is_packed(dev)) 626 vhost_vring_call_packed(dev, vq); 627 else 628 vhost_vring_call_split(dev, vq); 629 630 return 0; 631 } 632 633 uint16_t 634 rte_vhost_avail_entries(int vid, uint16_t queue_id) 635 { 636 struct virtio_net *dev; 637 struct vhost_virtqueue *vq; 638 639 dev = get_device(vid); 640 if (!dev) 641 return 0; 642 643 vq = dev->virtqueue[queue_id]; 644 if (!vq->enabled) 645 return 0; 646 647 return *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx; 648 } 649 650 static inline void 651 vhost_enable_notify_split(struct virtio_net *dev, 652 struct vhost_virtqueue *vq, int enable) 653 { 654 if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) { 655 if (enable) 656 vq->used->flags &= ~VRING_USED_F_NO_NOTIFY; 657 else 658 vq->used->flags |= VRING_USED_F_NO_NOTIFY; 659 } else { 660 if (enable) 661 vhost_avail_event(vq) = vq->last_avail_idx; 662 } 663 } 664 665 static inline void 666 vhost_enable_notify_packed(struct virtio_net *dev, 667 struct vhost_virtqueue *vq, int enable) 668 { 669 uint16_t flags; 670 671 if (!enable) { 672 vq->device_event->flags = VRING_EVENT_F_DISABLE; 673 return; 674 } 675 676 flags = VRING_EVENT_F_ENABLE; 677 if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) { 678 flags = VRING_EVENT_F_DESC; 679 vq->device_event->off_wrap = vq->last_avail_idx | 680 vq->avail_wrap_counter << 15; 681 } 682 683 rte_smp_wmb(); 684 685 vq->device_event->flags = flags; 686 } 687 688 int 689 rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable) 690 { 691 struct virtio_net *dev = get_device(vid); 692 struct vhost_virtqueue *vq; 693 694 if (!dev) 695 return -1; 696 697 vq = dev->virtqueue[queue_id]; 698 699 if (vq_is_packed(dev)) 700 vhost_enable_notify_packed(dev, vq, enable); 701 else 702 vhost_enable_notify_split(dev, vq, enable); 703 704 return 0; 705 } 706 707 void 708 rte_vhost_log_write(int vid, uint64_t addr, uint64_t len) 709 { 710 struct virtio_net *dev = get_device(vid); 711 712 if (dev == NULL) 713 return; 714 715 vhost_log_write(dev, addr, len); 716 } 717 718 void 719 rte_vhost_log_used_vring(int vid, uint16_t vring_idx, 720 uint64_t offset, uint64_t len) 721 { 722 struct virtio_net *dev; 723 struct vhost_virtqueue *vq; 724 725 dev = get_device(vid); 726 if (dev == NULL) 727 return; 728 729 if (vring_idx >= VHOST_MAX_VRING) 730 return; 731 vq = dev->virtqueue[vring_idx]; 732 if (!vq) 733 return; 734 735 vhost_log_used_vring(dev, vq, offset, len); 736 } 737 738 uint32_t 739 rte_vhost_rx_queue_count(int vid, uint16_t qid) 740 { 741 struct virtio_net *dev; 742 struct vhost_virtqueue *vq; 743 744 dev = get_device(vid); 745 if (dev == NULL) 746 return 0; 747 748 if (unlikely(qid >= dev->nr_vring || (qid & 1) == 0)) { 749 RTE_LOG(ERR, VHOST_DATA, "(%d) %s: invalid virtqueue idx %d.\n", 750 dev->vid, __func__, qid); 751 return 0; 752 } 753 754 vq = dev->virtqueue[qid]; 755 if (vq == NULL) 756 return 0; 757 758 if (unlikely(vq->enabled == 0 || vq->avail == NULL)) 759 return 0; 760 761 return *((volatile uint16_t *)&vq->avail->idx) - vq->last_avail_idx; 762 } 763 764 int rte_vhost_get_vdpa_device_id(int vid) 765 { 766 struct virtio_net *dev = get_device(vid); 767 768 if (dev == NULL) 769 return -1; 770 771 return dev->vdpa_dev_id; 772 } 773 774 int rte_vhost_get_log_base(int vid, uint64_t *log_base, 775 uint64_t *log_size) 776 { 777 struct virtio_net *dev = get_device(vid); 778 779 if (dev == NULL || log_base == NULL || log_size == NULL) 780 return -1; 781 782 if (unlikely(!(dev->flags & VIRTIO_DEV_BUILTIN_VIRTIO_NET))) { 783 RTE_LOG(ERR, VHOST_DATA, 784 "(%d) %s: built-in vhost net backend is disabled.\n", 785 dev->vid, __func__); 786 return -1; 787 } 788 789 *log_base = dev->log_base; 790 *log_size = dev->log_size; 791 792 return 0; 793 } 794 795 int rte_vhost_get_vring_base(int vid, uint16_t queue_id, 796 uint16_t *last_avail_idx, uint16_t *last_used_idx) 797 { 798 struct virtio_net *dev = get_device(vid); 799 800 if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL) 801 return -1; 802 803 if (unlikely(!(dev->flags & VIRTIO_DEV_BUILTIN_VIRTIO_NET))) { 804 RTE_LOG(ERR, VHOST_DATA, 805 "(%d) %s: built-in vhost net backend is disabled.\n", 806 dev->vid, __func__); 807 return -1; 808 } 809 810 *last_avail_idx = dev->virtqueue[queue_id]->last_avail_idx; 811 *last_used_idx = dev->virtqueue[queue_id]->last_used_idx; 812 813 return 0; 814 } 815 816 int rte_vhost_set_vring_base(int vid, uint16_t queue_id, 817 uint16_t last_avail_idx, uint16_t last_used_idx) 818 { 819 struct virtio_net *dev = get_device(vid); 820 821 if (dev == NULL) 822 return -1; 823 824 if (unlikely(!(dev->flags & VIRTIO_DEV_BUILTIN_VIRTIO_NET))) { 825 RTE_LOG(ERR, VHOST_DATA, 826 "(%d) %s: built-in vhost net backend is disabled.\n", 827 dev->vid, __func__); 828 return -1; 829 } 830 831 dev->virtqueue[queue_id]->last_avail_idx = last_avail_idx; 832 dev->virtqueue[queue_id]->last_used_idx = last_used_idx; 833 834 return 0; 835 } 836