LCOV - code coverage report
Current view: top level - lib/vhost - vhost.h (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 136 0.0 %
Date: 2025-03-01 20:23:48 Functions: 0 3 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 1706 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2018 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #ifndef _VHOST_NET_CDEV_H_
       6                 :            : #define _VHOST_NET_CDEV_H_
       7                 :            : #include <stdint.h>
       8                 :            : #include <stdio.h>
       9                 :            : #include <stdbool.h>
      10                 :            : #include <stdlib.h>
      11                 :            : #include <sys/queue.h>
      12                 :            : #include <unistd.h>
      13                 :            : #include <linux/virtio_net.h>
      14                 :            : #include <sys/socket.h>
      15                 :            : #include <linux/if.h>
      16                 :            : #include <sys/mman.h>
      17                 :            : 
      18                 :            : #include <rte_log.h>
      19                 :            : #include <rte_ether.h>
      20                 :            : #include <rte_malloc.h>
      21                 :            : #include <rte_dmadev.h>
      22                 :            : 
      23                 :            : #include "rte_vhost.h"
      24                 :            : #include "vdpa_driver.h"
      25                 :            : 
      26                 :            : #include "rte_vhost_async.h"
      27                 :            : 
      28                 :            : /* Used to indicate that the device is running on a data core */
      29                 :            : #define VIRTIO_DEV_RUNNING ((uint32_t)1 << 0)
      30                 :            : /* Used to indicate that the device is ready to operate */
      31                 :            : #define VIRTIO_DEV_READY ((uint32_t)1 << 1)
      32                 :            : /* Used to indicate that the built-in vhost net device backend is enabled */
      33                 :            : #define VIRTIO_DEV_BUILTIN_VIRTIO_NET ((uint32_t)1 << 2)
      34                 :            : /* Used to indicate that the device has its own data path and configured */
      35                 :            : #define VIRTIO_DEV_VDPA_CONFIGURED ((uint32_t)1 << 3)
      36                 :            : /* Used to indicate that the feature negotiation failed */
      37                 :            : #define VIRTIO_DEV_FEATURES_FAILED ((uint32_t)1 << 4)
      38                 :            : /* Used to indicate that the virtio_net tx code should fill TX ol_flags */
      39                 :            : #define VIRTIO_DEV_LEGACY_OL_FLAGS ((uint32_t)1 << 5)
      40                 :            : /*  Used to indicate the application has requested statistics collection */
      41                 :            : #define VIRTIO_DEV_STATS_ENABLED ((uint32_t)1 << 6)
      42                 :            : /*  Used to indicate the application has requested iommu support */
      43                 :            : #define VIRTIO_DEV_SUPPORT_IOMMU ((uint32_t)1 << 7)
      44                 :            : 
      45                 :            : /* Backend value set by guest. */
      46                 :            : #define VIRTIO_DEV_STOPPED -1
      47                 :            : 
      48                 :            : #define BUF_VECTOR_MAX 256
      49                 :            : 
      50                 :            : #define VHOST_LOG_CACHE_NR 32
      51                 :            : 
      52                 :            : #define MAX_PKT_BURST 32
      53                 :            : 
      54                 :            : #define VHOST_MAX_ASYNC_IT (MAX_PKT_BURST)
      55                 :            : #define VHOST_MAX_ASYNC_VEC 2048
      56                 :            : #define VIRTIO_MAX_RX_PKTLEN 9728U
      57                 :            : #define VHOST_DMA_MAX_COPY_COMPLETE ((VIRTIO_MAX_RX_PKTLEN / RTE_MBUF_DEFAULT_DATAROOM) \
      58                 :            :                 * MAX_PKT_BURST)
      59                 :            : 
      60                 :            : #define PACKED_DESC_ENQUEUE_USED_FLAG(w)        \
      61                 :            :         ((w) ? (VRING_DESC_F_AVAIL | VRING_DESC_F_USED | VRING_DESC_F_WRITE) : \
      62                 :            :                 VRING_DESC_F_WRITE)
      63                 :            : #define PACKED_DESC_DEQUEUE_USED_FLAG(w)        \
      64                 :            :         ((w) ? (VRING_DESC_F_AVAIL | VRING_DESC_F_USED) : 0x0)
      65                 :            : #define PACKED_DESC_SINGLE_DEQUEUE_FLAG (VRING_DESC_F_NEXT | \
      66                 :            :                                          VRING_DESC_F_INDIRECT)
      67                 :            : 
      68                 :            : #define PACKED_BATCH_SIZE (RTE_CACHE_LINE_SIZE / \
      69                 :            :                             sizeof(struct vring_packed_desc))
      70                 :            : #define PACKED_BATCH_MASK (PACKED_BATCH_SIZE - 1)
      71                 :            : 
      72                 :            : #ifdef VHOST_GCC_UNROLL_PRAGMA
      73                 :            : #define vhost_for_each_try_unroll(iter, val, size) _Pragma("GCC unroll 4") \
      74                 :            :         for (iter = val; iter < size; iter++)
      75                 :            : #endif
      76                 :            : 
      77                 :            : #ifdef VHOST_CLANG_UNROLL_PRAGMA
      78                 :            : #define vhost_for_each_try_unroll(iter, val, size) _Pragma("unroll 4") \
      79                 :            :         for (iter = val; iter < size; iter++)
      80                 :            : #endif
      81                 :            : 
      82                 :            : #ifndef vhost_for_each_try_unroll
      83                 :            : #define vhost_for_each_try_unroll(iter, val, num) \
      84                 :            :         for (iter = val; iter < num; iter++)
      85                 :            : #endif
      86                 :            : 
      87                 :            : struct virtio_net;
      88                 :            : struct vhost_virtqueue;
      89                 :            : 
      90                 :            : typedef void (*vhost_iotlb_remove_notify)(uint64_t addr, uint64_t off, uint64_t size);
      91                 :            : 
      92                 :            : typedef int (*vhost_iotlb_miss_cb)(struct virtio_net *dev, uint64_t iova, uint8_t perm);
      93                 :            : 
      94                 :            : typedef int (*vhost_vring_inject_irq_cb)(struct virtio_net *dev, struct vhost_virtqueue *vq);
      95                 :            : /**
      96                 :            :  * Structure that contains backend-specific ops.
      97                 :            :  */
      98                 :            : struct vhost_backend_ops {
      99                 :            :         vhost_iotlb_remove_notify iotlb_remove_notify;
     100                 :            :         vhost_iotlb_miss_cb iotlb_miss;
     101                 :            :         vhost_vring_inject_irq_cb inject_irq;
     102                 :            : };
     103                 :            : 
     104                 :            : /**
     105                 :            :  * Structure contains buffer address, length and descriptor index
     106                 :            :  * from vring to do scatter RX.
     107                 :            :  */
     108                 :            : struct buf_vector {
     109                 :            :         uint64_t buf_iova;
     110                 :            :         uint64_t buf_addr;
     111                 :            :         uint32_t buf_len;
     112                 :            :         uint32_t desc_idx;
     113                 :            : };
     114                 :            : 
     115                 :            : /*
     116                 :            :  * Structure contains the info for each batched memory copy.
     117                 :            :  */
     118                 :            : struct batch_copy_elem {
     119                 :            :         void *dst;
     120                 :            :         void *src;
     121                 :            :         uint32_t len;
     122                 :            :         uint64_t log_addr;
     123                 :            : };
     124                 :            : 
     125                 :            : /*
     126                 :            :  * Structure that contains the info for batched dirty logging.
     127                 :            :  */
     128                 :            : struct log_cache_entry {
     129                 :            :         uint32_t offset;
     130                 :            :         unsigned long val;
     131                 :            : };
     132                 :            : 
     133                 :            : struct vring_used_elem_packed {
     134                 :            :         uint16_t id;
     135                 :            :         uint16_t flags;
     136                 :            :         uint32_t len;
     137                 :            :         uint32_t count;
     138                 :            : };
     139                 :            : 
     140                 :            : /**
     141                 :            :  * Virtqueue statistics
     142                 :            :  */
     143                 :            : struct virtqueue_stats {
     144                 :            :         uint64_t packets;
     145                 :            :         uint64_t bytes;
     146                 :            :         uint64_t multicast;
     147                 :            :         uint64_t broadcast;
     148                 :            :         /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
     149                 :            :         uint64_t size_bins[8];
     150                 :            :         uint64_t iotlb_hits;
     151                 :            :         uint64_t iotlb_misses;
     152                 :            :         uint64_t inflight_submitted;
     153                 :            :         uint64_t inflight_completed;
     154                 :            :         uint64_t mbuf_alloc_failed;
     155                 :            :         uint64_t guest_notifications_suppressed;
     156                 :            :         /* Counters below are atomic, and should be incremented as such. */
     157                 :            :         RTE_ATOMIC(uint64_t) guest_notifications;
     158                 :            :         RTE_ATOMIC(uint64_t) guest_notifications_offloaded;
     159                 :            :         RTE_ATOMIC(uint64_t) guest_notifications_error;
     160                 :            : };
     161                 :            : 
     162                 :            : /**
     163                 :            :  * iovec
     164                 :            :  */
     165                 :            : struct vhost_iovec {
     166                 :            :         void *src_addr;
     167                 :            :         void *dst_addr;
     168                 :            :         size_t len;
     169                 :            : };
     170                 :            : 
     171                 :            : /**
     172                 :            :  * iovec iterator
     173                 :            :  */
     174                 :            : struct vhost_iov_iter {
     175                 :            :         /** pointer to the iovec array */
     176                 :            :         struct vhost_iovec *iov;
     177                 :            :         /** number of iovec in this iterator */
     178                 :            :         unsigned long nr_segs;
     179                 :            : };
     180                 :            : 
     181                 :            : struct async_dma_vchan_info {
     182                 :            :         /* circular array to track if packet copy completes */
     183                 :            :         bool **pkts_cmpl_flag_addr;
     184                 :            : 
     185                 :            :         /* max elements in 'pkts_cmpl_flag_addr' */
     186                 :            :         uint16_t ring_size;
     187                 :            :         /* ring index mask for 'pkts_cmpl_flag_addr' */
     188                 :            :         uint16_t ring_mask;
     189                 :            : 
     190                 :            :         /**
     191                 :            :          * DMA virtual channel lock. Although it is able to bind DMA
     192                 :            :          * virtual channels to data plane threads, vhost control plane
     193                 :            :          * thread could call data plane functions too, thus causing
     194                 :            :          * DMA device contention.
     195                 :            :          *
     196                 :            :          * For example, in VM exit case, vhost control plane thread needs
     197                 :            :          * to clear in-flight packets before disable vring, but there could
     198                 :            :          * be anotther data plane thread is enqueuing packets to the same
     199                 :            :          * vring with the same DMA virtual channel. As dmadev PMD functions
     200                 :            :          * are lock-free, the control plane and data plane threads could
     201                 :            :          * operate the same DMA virtual channel at the same time.
     202                 :            :          */
     203                 :            :         rte_spinlock_t dma_lock;
     204                 :            : };
     205                 :            : 
     206                 :            : struct async_dma_info {
     207                 :            :         struct async_dma_vchan_info *vchans;
     208                 :            :         /* number of registered virtual channels */
     209                 :            :         uint16_t nr_vchans;
     210                 :            : };
     211                 :            : 
     212                 :            : extern struct async_dma_info dma_copy_track[RTE_DMADEV_DEFAULT_MAX];
     213                 :            : 
     214                 :            : /**
     215                 :            :  * inflight async packet information
     216                 :            :  */
     217                 :            : struct async_inflight_info {
     218                 :            :         struct rte_mbuf *mbuf;
     219                 :            :         uint16_t descs; /* num of descs inflight */
     220                 :            :         uint16_t nr_buffers; /* num of buffers inflight for packed ring */
     221                 :            :         struct virtio_net_hdr nethdr;
     222                 :            : };
     223                 :            : 
     224                 :            : struct vhost_async {
     225                 :            :         struct vhost_iov_iter iov_iter[VHOST_MAX_ASYNC_IT];
     226                 :            :         struct vhost_iovec iovec[VHOST_MAX_ASYNC_VEC];
     227                 :            :         uint16_t iter_idx;
     228                 :            :         uint16_t iovec_idx;
     229                 :            : 
     230                 :            :         /* data transfer status */
     231                 :            :         struct async_inflight_info *pkts_info;
     232                 :            :         /**
     233                 :            :          * Packet reorder array. "true" indicates that DMA device
     234                 :            :          * completes all copies for the packet.
     235                 :            :          *
     236                 :            :          * Note that this array could be written by multiple threads
     237                 :            :          * simultaneously. For example, in the case of thread0 and
     238                 :            :          * thread1 RX packets from NIC and then enqueue packets to
     239                 :            :          * vring0 and vring1 with own DMA device DMA0 and DMA1, it's
     240                 :            :          * possible for thread0 to get completed copies belonging to
     241                 :            :          * vring1 from DMA0, while thread0 is calling rte_vhost_poll
     242                 :            :          * _enqueue_completed() for vring0 and thread1 is calling
     243                 :            :          * rte_vhost_submit_enqueue_burst() for vring1. In this case,
     244                 :            :          * vq->access_lock cannot protect pkts_cmpl_flag of vring1.
     245                 :            :          *
     246                 :            :          * However, since offloading is per-packet basis, each packet
     247                 :            :          * flag will only be written by one thread. And single byte
     248                 :            :          * write is atomic, so no lock for pkts_cmpl_flag is needed.
     249                 :            :          */
     250                 :            :         bool *pkts_cmpl_flag;
     251                 :            :         uint16_t pkts_idx;
     252                 :            :         uint16_t pkts_inflight_n;
     253                 :            :         union {
     254                 :            :                 struct vring_used_elem  *descs_split;
     255                 :            :                 struct vring_used_elem_packed *buffers_packed;
     256                 :            :         };
     257                 :            :         union {
     258                 :            :                 uint16_t desc_idx_split;
     259                 :            :                 uint16_t buffer_idx_packed;
     260                 :            :         };
     261                 :            :         union {
     262                 :            :                 uint16_t last_desc_idx_split;
     263                 :            :                 uint16_t last_buffer_idx_packed;
     264                 :            :         };
     265                 :            : };
     266                 :            : 
     267                 :            : #define VHOST_RECONNECT_VERSION         0x0
     268                 :            : #define VHOST_MAX_VRING                 0x100
     269                 :            : #define VHOST_MAX_QUEUE_PAIRS           0x80
     270                 :            : 
     271                 :            : struct __rte_cache_aligned vhost_reconnect_vring {
     272                 :            :         uint16_t last_avail_idx;
     273                 :            :         bool avail_wrap_counter;
     274                 :            : };
     275                 :            : 
     276                 :            : struct vhost_reconnect_data {
     277                 :            :         uint32_t version;
     278                 :            :         uint64_t features;
     279                 :            :         uint8_t status;
     280                 :            :         struct virtio_net_config config;
     281                 :            :         uint32_t nr_vrings;
     282                 :            :         struct vhost_reconnect_vring vring[VHOST_MAX_VRING];
     283                 :            : };
     284                 :            : 
     285                 :            : /**
     286                 :            :  * Structure contains variables relevant to RX/TX virtqueues.
     287                 :            :  */
     288                 :            : struct __rte_cache_aligned vhost_virtqueue {
     289                 :            :         union {
     290                 :            :                 struct vring_desc       *desc;
     291                 :            :                 struct vring_packed_desc   *desc_packed;
     292                 :            :         };
     293                 :            :         union {
     294                 :            :                 struct vring_avail      *avail;
     295                 :            :                 struct vring_packed_desc_event *driver_event;
     296                 :            :         };
     297                 :            :         union {
     298                 :            :                 struct vring_used       *used;
     299                 :            :                 struct vring_packed_desc_event *device_event;
     300                 :            :         };
     301                 :            :         uint16_t                size;
     302                 :            : 
     303                 :            :         uint16_t                last_avail_idx;
     304                 :            :         uint16_t                last_used_idx;
     305                 :            :         /* Last used index we notify to front end. */
     306                 :            :         uint16_t                signalled_used;
     307                 :            :         bool                    signalled_used_valid;
     308                 :            : #define VIRTIO_INVALID_EVENTFD          (-1)
     309                 :            : #define VIRTIO_UNINITIALIZED_EVENTFD    (-2)
     310                 :            : 
     311                 :            :         bool                    enabled;
     312                 :            :         /* Protected by vq->access_lock */
     313                 :            :         bool                    access_ok __rte_guarded_var;
     314                 :            :         bool                    ready;
     315                 :            : 
     316                 :            :         rte_rwlock_t            access_lock;
     317                 :            : 
     318                 :            : 
     319                 :            :         union {
     320                 :            :                 struct vring_used_elem  *shadow_used_split;
     321                 :            :                 struct vring_used_elem_packed *shadow_used_packed;
     322                 :            :         };
     323                 :            :         uint16_t                shadow_used_idx;
     324                 :            :         /* Record packed ring enqueue latest desc cache aligned index */
     325                 :            :         uint16_t                shadow_aligned_idx;
     326                 :            :         /* Record packed ring first dequeue desc index */
     327                 :            :         uint16_t                shadow_last_used_idx;
     328                 :            : 
     329                 :            :         uint16_t                batch_copy_nb_elems;
     330                 :            :         struct batch_copy_elem  *batch_copy_elems;
     331                 :            :         int                     numa_node;
     332                 :            :         bool                    used_wrap_counter;
     333                 :            :         bool                    avail_wrap_counter;
     334                 :            : 
     335                 :            :         /* Physical address of used ring, for logging */
     336                 :            :         uint16_t                log_cache_nb_elem;
     337                 :            :         uint64_t                log_guest_addr;
     338                 :            :         struct log_cache_entry  *log_cache;
     339                 :            : 
     340                 :            :         rte_rwlock_t    iotlb_lock;
     341                 :            : 
     342                 :            :         /* Used to notify the guest (trigger interrupt) */
     343                 :            :         int                     callfd;
     344                 :            :         /* Currently unused as polling mode is enabled */
     345                 :            :         int                     kickfd;
     346                 :            : 
     347                 :            :         /* Index of this vq in dev->virtqueue[] */
     348                 :            :         uint32_t                index;
     349                 :            : 
     350                 :            :         /* inflight share memory info */
     351                 :            :         union {
     352                 :            :                 struct rte_vhost_inflight_info_split *inflight_split;
     353                 :            :                 struct rte_vhost_inflight_info_packed *inflight_packed;
     354                 :            :         };
     355                 :            :         struct rte_vhost_resubmit_info *resubmit_inflight;
     356                 :            :         uint64_t                global_counter;
     357                 :            : 
     358                 :            :         struct vhost_async      *async __rte_guarded_var;
     359                 :            : 
     360                 :            :         int                     notif_enable;
     361                 :            : #define VIRTIO_UNINITIALIZED_NOTIF      (-1)
     362                 :            : 
     363                 :            :         struct vhost_vring_addr ring_addrs;
     364                 :            :         struct virtqueue_stats  stats;
     365                 :            : 
     366                 :            :         RTE_ATOMIC(bool) irq_pending;
     367                 :            :         struct vhost_reconnect_vring *reconnect_log;
     368                 :            : };
     369                 :            : 
     370                 :            : /* Virtio device status as per Virtio specification */
     371                 :            : #define VIRTIO_DEVICE_STATUS_RESET              0x00
     372                 :            : #define VIRTIO_DEVICE_STATUS_ACK                0x01
     373                 :            : #define VIRTIO_DEVICE_STATUS_DRIVER             0x02
     374                 :            : #define VIRTIO_DEVICE_STATUS_DRIVER_OK          0x04
     375                 :            : #define VIRTIO_DEVICE_STATUS_FEATURES_OK        0x08
     376                 :            : #define VIRTIO_DEVICE_STATUS_DEV_NEED_RESET     0x40
     377                 :            : #define VIRTIO_DEVICE_STATUS_FAILED             0x80
     378                 :            : 
     379                 :            : /* Declare IOMMU related bits for older kernels */
     380                 :            : #ifndef VIRTIO_F_IOMMU_PLATFORM
     381                 :            : 
     382                 :            : #define VIRTIO_F_IOMMU_PLATFORM 33
     383                 :            : 
     384                 :            : struct vhost_iotlb_msg {
     385                 :            :         __u64 iova;
     386                 :            :         __u64 size;
     387                 :            :         __u64 uaddr;
     388                 :            : #define VHOST_ACCESS_RO      0x1
     389                 :            : #define VHOST_ACCESS_WO      0x2
     390                 :            : #define VHOST_ACCESS_RW      0x3
     391                 :            :         __u8 perm;
     392                 :            : #define VHOST_IOTLB_MISS           1
     393                 :            : #define VHOST_IOTLB_UPDATE         2
     394                 :            : #define VHOST_IOTLB_INVALIDATE     3
     395                 :            : #define VHOST_IOTLB_ACCESS_FAIL    4
     396                 :            :         __u8 type;
     397                 :            : };
     398                 :            : 
     399                 :            : #define VHOST_IOTLB_MSG 0x1
     400                 :            : 
     401                 :            : struct vhost_msg {
     402                 :            :         int type;
     403                 :            :         union {
     404                 :            :                 struct vhost_iotlb_msg iotlb;
     405                 :            :                 __u8 padding[64];
     406                 :            :         };
     407                 :            : };
     408                 :            : #endif
     409                 :            : 
     410                 :            : /*
     411                 :            :  * Define virtio 1.0 for older kernels
     412                 :            :  */
     413                 :            : #ifndef VIRTIO_F_VERSION_1
     414                 :            :  #define VIRTIO_F_VERSION_1 32
     415                 :            : #endif
     416                 :            : 
     417                 :            : /* Declare packed ring related bits for older kernels */
     418                 :            : #ifndef VIRTIO_F_RING_PACKED
     419                 :            : 
     420                 :            : #define VIRTIO_F_RING_PACKED 34
     421                 :            : 
     422                 :            : struct vring_packed_desc {
     423                 :            :         uint64_t addr;
     424                 :            :         uint32_t len;
     425                 :            :         uint16_t id;
     426                 :            :         uint16_t flags;
     427                 :            : };
     428                 :            : 
     429                 :            : struct vring_packed_desc_event {
     430                 :            :         uint16_t off_wrap;
     431                 :            :         uint16_t flags;
     432                 :            : };
     433                 :            : #endif
     434                 :            : 
     435                 :            : /*
     436                 :            :  * Declare below packed ring defines unconditionally
     437                 :            :  * as Kernel header might use different names.
     438                 :            :  */
     439                 :            : #define VRING_DESC_F_AVAIL      (1ULL << 7)
     440                 :            : #define VRING_DESC_F_USED       (1ULL << 15)
     441                 :            : 
     442                 :            : #define VRING_EVENT_F_ENABLE 0x0
     443                 :            : #define VRING_EVENT_F_DISABLE 0x1
     444                 :            : #define VRING_EVENT_F_DESC 0x2
     445                 :            : 
     446                 :            : /*
     447                 :            :  * Available and used descs are in same order
     448                 :            :  */
     449                 :            : #ifndef VIRTIO_F_IN_ORDER
     450                 :            : #define VIRTIO_F_IN_ORDER      35
     451                 :            : #endif
     452                 :            : 
     453                 :            : /* Features supported by this builtin vhost-user net driver. */
     454                 :            : #define VIRTIO_NET_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
     455                 :            :                                 (1ULL << VIRTIO_F_ANY_LAYOUT) | \
     456                 :            :                                 (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
     457                 :            :                                 (1ULL << VIRTIO_NET_F_MQ)      | \
     458                 :            :                                 (1ULL << VIRTIO_F_VERSION_1)   | \
     459                 :            :                                 (1ULL << VIRTIO_NET_F_GSO) | \
     460                 :            :                                 (1ULL << VIRTIO_NET_F_HOST_TSO4) | \
     461                 :            :                                 (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
     462                 :            :                                 (1ULL << VIRTIO_NET_F_HOST_UFO) | \
     463                 :            :                                 (1ULL << VIRTIO_NET_F_HOST_ECN) | \
     464                 :            :                                 (1ULL << VIRTIO_NET_F_CSUM)    | \
     465                 :            :                                 (1ULL << VIRTIO_NET_F_GUEST_CSUM) | \
     466                 :            :                                 (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
     467                 :            :                                 (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
     468                 :            :                                 (1ULL << VIRTIO_NET_F_GUEST_UFO) | \
     469                 :            :                                 (1ULL << VIRTIO_NET_F_GUEST_ECN) | \
     470                 :            :                                 (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | \
     471                 :            :                                 (1ULL << VIRTIO_RING_F_EVENT_IDX) | \
     472                 :            :                                 (1ULL << VIRTIO_F_IN_ORDER) | \
     473                 :            :                                 (1ULL << VIRTIO_F_IOMMU_PLATFORM))
     474                 :            : 
     475                 :            : 
     476                 :            : struct guest_page {
     477                 :            :         uint64_t guest_phys_addr;
     478                 :            :         uint64_t host_iova;
     479                 :            :         uint64_t host_user_addr;
     480                 :            :         uint64_t size;
     481                 :            : };
     482                 :            : 
     483                 :            : struct inflight_mem_info {
     484                 :            :         int             fd;
     485                 :            :         void            *addr;
     486                 :            :         uint64_t        size;
     487                 :            : };
     488                 :            : 
     489                 :            : /**
     490                 :            :  * Device structure contains all configuration information relating
     491                 :            :  * to the device.
     492                 :            :  */
     493                 :            : struct __rte_cache_aligned virtio_net {
     494                 :            :         /* Frontend (QEMU) memory and memory region information */
     495                 :            :         struct rte_vhost_memory *mem;
     496                 :            :         uint64_t                features;
     497                 :            :         uint64_t                protocol_features;
     498                 :            :         int                     vid;
     499                 :            :         uint32_t                flags;
     500                 :            :         uint16_t                vhost_hlen;
     501                 :            :         /* to tell if we need broadcast rarp packet */
     502                 :            :         RTE_ATOMIC(int16_t)     broadcast_rarp;
     503                 :            :         uint32_t                nr_vring;
     504                 :            :         int                     async_copy;
     505                 :            : 
     506                 :            :         int                     extbuf;
     507                 :            :         int                     linearbuf;
     508                 :            :         struct vhost_virtqueue  *virtqueue[VHOST_MAX_QUEUE_PAIRS * 2];
     509                 :            : 
     510                 :            :         rte_rwlock_t    iotlb_pending_lock;
     511                 :            :         struct vhost_iotlb_entry *iotlb_pool;
     512                 :            :         TAILQ_HEAD(, vhost_iotlb_entry) iotlb_list;
     513                 :            :         TAILQ_HEAD(, vhost_iotlb_entry) iotlb_pending_list;
     514                 :            :         int                             iotlb_cache_nr;
     515                 :            :         rte_spinlock_t  iotlb_free_lock;
     516                 :            :         SLIST_HEAD(, vhost_iotlb_entry) iotlb_free_list;
     517                 :            : 
     518                 :            :         struct inflight_mem_info *inflight_info;
     519                 :            : #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
     520                 :            :         char                    ifname[IF_NAME_SZ];
     521                 :            :         uint64_t                log_size;
     522                 :            :         uint64_t                log_base;
     523                 :            :         uint64_t                log_addr;
     524                 :            :         struct rte_ether_addr   mac;
     525                 :            :         uint16_t                mtu;
     526                 :            :         uint8_t                 status;
     527                 :            : 
     528                 :            :         struct rte_vhost_device_ops const *notify_ops;
     529                 :            : 
     530                 :            :         uint32_t                nr_guest_pages;
     531                 :            :         uint32_t                max_guest_pages;
     532                 :            :         struct guest_page       *guest_pages;
     533                 :            : 
     534                 :            :         int                     backend_req_fd;
     535                 :            :         rte_spinlock_t          backend_req_lock;
     536                 :            : 
     537                 :            :         int                     postcopy_ufd;
     538                 :            :         int                     postcopy_listening;
     539                 :            :         int                     vduse_ctrl_fd;
     540                 :            :         int                     vduse_dev_fd;
     541                 :            : 
     542                 :            :         struct vhost_virtqueue  *cvq;
     543                 :            : 
     544                 :            :         struct rte_vdpa_device *vdpa_dev;
     545                 :            : 
     546                 :            :         /* context data for the external message handlers */
     547                 :            :         void                    *extern_data;
     548                 :            :         /* pre and post vhost user message handlers for the device */
     549                 :            :         struct rte_vhost_user_extern_ops extern_ops;
     550                 :            : 
     551                 :            :         struct vhost_backend_ops *backend_ops;
     552                 :            : 
     553                 :            :         struct vhost_reconnect_data *reconnect_log;
     554                 :            : };
     555                 :            : 
     556                 :            : static __rte_always_inline void
     557                 :            : vhost_virtqueue_reconnect_log_split(struct vhost_virtqueue *vq)
     558                 :            : {
     559   [ #  #  #  #  :          0 :         if (vq->reconnect_log != NULL)
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     560                 :          0 :                 vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
     561                 :            : }
     562                 :            : 
     563                 :            : static __rte_always_inline void
     564                 :            : vhost_virtqueue_reconnect_log_packed(struct vhost_virtqueue *vq)
     565                 :            : {
     566   [ #  #  #  #  :          0 :         if (vq->reconnect_log != NULL) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     567                 :          0 :                 vq->reconnect_log->last_avail_idx = vq->last_avail_idx;
     568                 :          0 :                 vq->reconnect_log->avail_wrap_counter = vq->avail_wrap_counter;
     569                 :            :         }
     570                 :            : }
     571                 :            : 
     572                 :            : static inline void
     573         [ #  # ]:          0 : vq_assert_lock__(struct virtio_net *dev, struct vhost_virtqueue *vq, const char *func)
     574                 :            :         __rte_assert_capability(&vq->access_lock)
     575                 :            : {
     576         [ #  # ]:          0 :         if (unlikely(!rte_rwlock_write_is_locked(&vq->access_lock)))
     577                 :          0 :                 rte_panic("VHOST_CONFIG: (%s) %s() called without access lock taken.\n",
     578                 :            :                         dev->ifname, func);
     579                 :          0 : }
     580                 :            : #define vq_assert_lock(dev, vq) vq_assert_lock__(dev, vq, __func__)
     581                 :            : 
     582                 :            : static __rte_always_inline bool
     583                 :            : vq_is_packed(struct virtio_net *dev)
     584                 :            : {
     585   [ #  #  #  #  :          0 :         return dev->features & (1ull << VIRTIO_F_RING_PACKED);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     586                 :            : }
     587                 :            : 
     588                 :            : static inline bool
     589                 :          0 : desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
     590                 :            : {
     591                 :          0 :         uint16_t flags = rte_atomic_load_explicit((unsigned short __rte_atomic *)&desc->flags,
     592                 :            :                 rte_memory_order_acquire);
     593                 :            : 
     594         [ #  # ]:          0 :         return wrap_counter == !!(flags & VRING_DESC_F_AVAIL) &&
     595         [ #  # ]:          0 :                 wrap_counter != !!(flags & VRING_DESC_F_USED);
     596                 :            : }
     597                 :            : 
     598                 :            : static inline void
     599                 :            : vq_inc_last_used_packed(struct vhost_virtqueue *vq, uint16_t num)
     600                 :            : {
     601                 :          0 :         vq->last_used_idx += num;
     602   [ #  #  #  #  :          0 :         if (vq->last_used_idx >= vq->size) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     603                 :          0 :                 vq->used_wrap_counter ^= 1;
     604                 :          0 :                 vq->last_used_idx -= vq->size;
     605                 :            :         }
     606                 :            : }
     607                 :            : 
     608                 :            : static inline void
     609                 :            : vq_inc_last_avail_packed(struct vhost_virtqueue *vq, uint16_t num)
     610                 :            : {
     611                 :          0 :         vq->last_avail_idx += num;
     612   [ #  #  #  #  :          0 :         if (vq->last_avail_idx >= vq->size) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     613                 :          0 :                 vq->avail_wrap_counter ^= 1;
     614                 :          0 :                 vq->last_avail_idx -= vq->size;
     615                 :            :         }
     616                 :            :         vhost_virtqueue_reconnect_log_packed(vq);
     617                 :            : }
     618                 :            : 
     619                 :            : void __vhost_log_cache_write(struct virtio_net *dev,
     620                 :            :                 struct vhost_virtqueue *vq,
     621                 :            :                 uint64_t addr, uint64_t len);
     622                 :            : void __vhost_log_cache_write_iova(struct virtio_net *dev,
     623                 :            :                 struct vhost_virtqueue *vq,
     624                 :            :                 uint64_t iova, uint64_t len)
     625                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     626                 :            : void __vhost_log_cache_sync(struct virtio_net *dev,
     627                 :            :                 struct vhost_virtqueue *vq);
     628                 :            : 
     629                 :            : void __vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len);
     630                 :            : void __vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
     631                 :            :                             uint64_t iova, uint64_t len)
     632                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     633                 :            : 
     634                 :            : static __rte_always_inline void
     635                 :            : vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
     636                 :            : {
     637         [ #  # ]:          0 :         if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
     638                 :          0 :                 __vhost_log_write(dev, addr, len);
     639                 :            : }
     640                 :            : 
     641                 :            : static __rte_always_inline void
     642                 :            : vhost_log_cache_sync(struct virtio_net *dev, struct vhost_virtqueue *vq)
     643                 :            : {
     644   [ #  #  #  #  :          0 :         if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     645                 :          0 :                 __vhost_log_cache_sync(dev, vq);
     646                 :            : }
     647                 :            : 
     648                 :            : static __rte_always_inline void
     649                 :            : vhost_log_cache_write(struct virtio_net *dev, struct vhost_virtqueue *vq,
     650                 :            :                         uint64_t addr, uint64_t len)
     651                 :            : {
     652                 :            :         if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL)))
     653                 :            :                 __vhost_log_cache_write(dev, vq, addr, len);
     654                 :            : }
     655                 :            : 
     656                 :            : static __rte_always_inline void
     657                 :            : vhost_log_cache_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
     658                 :            :                         uint64_t offset, uint64_t len)
     659                 :            : {
     660   [ #  #  #  #  :          0 :         if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     661   [ #  #  #  #  :          0 :                 if (unlikely(vq->log_guest_addr == 0))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     662                 :            :                         return;
     663                 :          0 :                 __vhost_log_cache_write(dev, vq, vq->log_guest_addr + offset,
     664                 :            :                                         len);
     665                 :            :         }
     666                 :            : }
     667                 :            : 
     668                 :            : static __rte_always_inline void
     669                 :            : vhost_log_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
     670                 :            :                      uint64_t offset, uint64_t len)
     671                 :            : {
     672   [ #  #  #  #  :          0 :         if (unlikely(dev->features & (1ULL << VHOST_F_LOG_ALL))) {
                   #  # ]
     673   [ #  #  #  #  :          0 :                 if (unlikely(vq->log_guest_addr == 0))
                   #  # ]
     674                 :            :                         return;
     675                 :          0 :                 __vhost_log_write(dev, vq->log_guest_addr + offset, len);
     676                 :            :         }
     677                 :            : }
     678                 :            : 
     679                 :            : static __rte_always_inline void
     680                 :            : vhost_log_cache_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
     681                 :            :                            uint64_t iova, uint64_t len)
     682                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock)
     683                 :            : {
     684   [ #  #  #  #  :          0 :         if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     685                 :            :                 return;
     686                 :            : 
     687   [ #  #  #  #  :          0 :         if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     688                 :          0 :                 __vhost_log_cache_write_iova(dev, vq, iova, len);
     689                 :            :         else
     690                 :          0 :                 __vhost_log_cache_write(dev, vq, iova, len);
     691                 :            : }
     692                 :            : 
     693                 :            : static __rte_always_inline void
     694                 :            : vhost_log_write_iova(struct virtio_net *dev, struct vhost_virtqueue *vq,
     695                 :            :                            uint64_t iova, uint64_t len)
     696                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock)
     697                 :            : {
     698         [ #  # ]:          0 :         if (likely(!(dev->features & (1ULL << VHOST_F_LOG_ALL))))
     699                 :            :                 return;
     700                 :            : 
     701         [ #  # ]:          0 :         if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
     702                 :          0 :                 __vhost_log_write_iova(dev, vq, iova, len);
     703                 :            :         else
     704                 :          0 :                 __vhost_log_write(dev, iova, len);
     705                 :            : }
     706                 :            : 
     707                 :            : extern int vhost_config_log_level;
     708                 :            : #define RTE_LOGTYPE_VHOST_CONFIG vhost_config_log_level
     709                 :            : extern int vhost_data_log_level;
     710                 :            : #define RTE_LOGTYPE_VHOST_DATA vhost_data_log_level
     711                 :            : 
     712                 :            : #define VHOST_CONFIG_LOG(prefix, level, ...) \
     713                 :            :         RTE_LOG_LINE_PREFIX(level, VHOST_CONFIG, "(%s) ", prefix, __VA_ARGS__)
     714                 :            : 
     715                 :            : #define VHOST_DATA_LOG(prefix, level, ...) \
     716                 :            :         RTE_LOG_DP_LINE_PREFIX(level, VHOST_DATA, "(%s) ", prefix, __VA_ARGS__)
     717                 :            : 
     718                 :            : #ifdef RTE_LIBRTE_VHOST_DEBUG
     719                 :            : #define VHOST_MAX_PRINT_BUFF 6072
     720                 :            : #define PRINT_PACKET(device, addr, size, header) do { \
     721                 :            :         char *pkt_addr = (char *)(addr); \
     722                 :            :         unsigned int index; \
     723                 :            :         char packet[VHOST_MAX_PRINT_BUFF]; \
     724                 :            :         \
     725                 :            :         if ((header)) \
     726                 :            :                 snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Header size %d: ", (device->vid), (size)); \
     727                 :            :         else \
     728                 :            :                 snprintf(packet, VHOST_MAX_PRINT_BUFF, "(%d) Packet size %d: ", (device->vid), (size)); \
     729                 :            :         for (index = 0; index < (size); index++) { \
     730                 :            :                 snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), \
     731                 :            :                         "%02hhx ", pkt_addr[index]); \
     732                 :            :         } \
     733                 :            :         snprintf(packet + strnlen(packet, VHOST_MAX_PRINT_BUFF), VHOST_MAX_PRINT_BUFF - strnlen(packet, VHOST_MAX_PRINT_BUFF), "\n"); \
     734                 :            :         \
     735                 :            :         RTE_LOG_DP(DEBUG, VHOST_DATA, "(%s) %s", dev->ifname, packet); \
     736                 :            : } while (0)
     737                 :            : #else
     738                 :            : #define PRINT_PACKET(device, addr, size, header) do {} while (0)
     739                 :            : #endif
     740                 :            : 
     741                 :            : extern struct virtio_net *vhost_devices[RTE_MAX_VHOST_DEVICE];
     742                 :            : 
     743                 :            : #define VHOST_BINARY_SEARCH_THRESH 256
     744                 :            : 
     745                 :          0 : static __rte_always_inline int guest_page_addrcmp(const void *p1,
     746                 :            :                                                 const void *p2)
     747                 :            : {
     748                 :            :         const struct guest_page *page1 = (const struct guest_page *)p1;
     749                 :            :         const struct guest_page *page2 = (const struct guest_page *)p2;
     750                 :            : 
     751         [ #  # ]:          0 :         if (page1->guest_phys_addr > page2->guest_phys_addr)
     752                 :            :                 return 1;
     753         [ #  # ]:          0 :         if (page1->guest_phys_addr < page2->guest_phys_addr)
     754                 :          0 :                 return -1;
     755                 :            : 
     756                 :            :         return 0;
     757                 :            : }
     758                 :            : 
     759                 :            : static __rte_always_inline int guest_page_rangecmp(const void *p1, const void *p2)
     760                 :            : {
     761                 :            :         const struct guest_page *page1 = (const struct guest_page *)p1;
     762                 :            :         const struct guest_page *page2 = (const struct guest_page *)p2;
     763                 :            : 
     764   [ #  #  #  #  :          0 :         if (page1->guest_phys_addr >= page2->guest_phys_addr) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     765   [ #  #  #  #  :          0 :                 if (page1->guest_phys_addr < page2->guest_phys_addr + page2->size)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     766                 :            :                         return 0;
     767                 :            :                 else
     768                 :            :                         return 1;
     769                 :            :         } else
     770                 :            :                 return -1;
     771                 :            : }
     772                 :            : 
     773                 :            : static __rte_always_inline rte_iova_t
     774                 :            : gpa_to_first_hpa(struct virtio_net *dev, uint64_t gpa,
     775                 :            :         uint64_t gpa_size, uint64_t *hpa_size)
     776                 :            : {
     777                 :            :         uint32_t i;
     778                 :            :         struct guest_page *page;
     779                 :            :         struct guest_page key;
     780                 :            : 
     781                 :          0 :         *hpa_size = gpa_size;
     782   [ #  #  #  #  :          0 :         if (dev->nr_guest_pages >= VHOST_BINARY_SEARCH_THRESH) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     783                 :            :                 key.guest_phys_addr = gpa;
     784                 :          0 :                 page = bsearch(&key, dev->guest_pages, dev->nr_guest_pages,
     785                 :            :                                sizeof(struct guest_page), guest_page_rangecmp);
     786   [ #  #  #  #  :          0 :                 if (page) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     787                 :          0 :                         if (gpa + gpa_size <=
     788   [ #  #  #  #  :          0 :                                         page->guest_phys_addr + page->size) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     789                 :          0 :                                 return gpa - page->guest_phys_addr +
     790                 :          0 :                                         page->host_iova;
     791   [ #  #  #  #  :          0 :                         } else if (gpa < page->guest_phys_addr +
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     792                 :            :                                                 page->size) {
     793                 :          0 :                                 *hpa_size = page->guest_phys_addr +
     794                 :          0 :                                         page->size - gpa;
     795                 :          0 :                                 return gpa - page->guest_phys_addr +
     796                 :          0 :                                         page->host_iova;
     797                 :            :                         }
     798                 :            :                 }
     799                 :            :         } else {
     800   [ #  #  #  #  :          0 :                 for (i = 0; i < dev->nr_guest_pages; i++) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     801                 :          0 :                         page = &dev->guest_pages[i];
     802                 :            : 
     803   [ #  #  #  #  :          0 :                         if (gpa >= page->guest_phys_addr) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     804                 :          0 :                                 if (gpa + gpa_size <=
     805   [ #  #  #  #  :          0 :                                         page->guest_phys_addr + page->size) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     806                 :          0 :                                         return gpa - page->guest_phys_addr +
     807                 :          0 :                                                 page->host_iova;
     808   [ #  #  #  #  :          0 :                                 } else if (gpa < page->guest_phys_addr +
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     809                 :            :                                                         page->size) {
     810                 :          0 :                                         *hpa_size = page->guest_phys_addr +
     811                 :          0 :                                                 page->size - gpa;
     812                 :          0 :                                         return gpa - page->guest_phys_addr +
     813                 :          0 :                                                 page->host_iova;
     814                 :            :                                 }
     815                 :            :                         }
     816                 :            :                 }
     817                 :            :         }
     818                 :            : 
     819                 :          0 :         *hpa_size = 0;
     820                 :          0 :         return 0;
     821                 :            : }
     822                 :            : 
     823                 :            : /* Convert guest physical address to host physical address */
     824                 :            : static __rte_always_inline rte_iova_t
     825                 :            : gpa_to_hpa(struct virtio_net *dev, uint64_t gpa, uint64_t size)
     826                 :            : {
     827                 :            :         rte_iova_t hpa;
     828                 :            :         uint64_t hpa_size;
     829                 :            : 
     830                 :            :         hpa = gpa_to_first_hpa(dev, gpa, size, &hpa_size);
     831   [ #  #  #  #  :          0 :         return hpa_size == size ? hpa : 0;
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     832                 :            : }
     833                 :            : 
     834                 :            : static __rte_always_inline uint64_t
     835                 :            : hva_to_gpa(struct virtio_net *dev, uint64_t vva, uint64_t len)
     836                 :            : {
     837                 :            :         struct rte_vhost_mem_region *r;
     838                 :            :         uint32_t i;
     839                 :            : 
     840   [ #  #  #  #  :          0 :         if (unlikely(!dev || !dev->mem))
          #  #  #  #  #  
                      # ]
     841                 :            :                 return 0;
     842                 :            : 
     843   [ #  #  #  #  :          0 :         for (i = 0; i < dev->mem->nregions; i++) {
                   #  # ]
     844                 :            :                 r = &dev->mem->regions[i];
     845                 :            : 
     846   [ #  #  #  #  :          0 :                 if (vva >= r->host_user_addr &&
                   #  # ]
     847   [ #  #  #  #  :          0 :                     vva + len <  r->host_user_addr + r->size) {
                   #  # ]
     848                 :          0 :                         return r->guest_phys_addr + vva - r->host_user_addr;
     849                 :            :                 }
     850                 :            :         }
     851                 :            :         return 0;
     852                 :            : }
     853                 :            : 
     854                 :            : static __rte_always_inline struct virtio_net *
     855                 :            : get_device(int vid)
     856                 :            : {
     857                 :            :         struct virtio_net *dev = NULL;
     858                 :            : 
     859   [ #  #  #  #  :          0 :         if (likely(vid >= 0 && vid < RTE_MAX_VHOST_DEVICE))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     860                 :          0 :                 dev = vhost_devices[vid];
     861                 :            : 
     862   [ #  #  #  #  :          0 :         if (unlikely(!dev)) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     863                 :          0 :                 VHOST_CONFIG_LOG("device", ERR, "(%d) device not found.", vid);
     864                 :            :         }
     865                 :            : 
     866                 :            :         return dev;
     867                 :            : }
     868                 :            : 
     869                 :            : int vhost_new_device(struct vhost_backend_ops *ops);
     870                 :            : void cleanup_device(struct virtio_net *dev, int destroy);
     871                 :            : void reset_device(struct virtio_net *dev);
     872                 :            : void vhost_destroy_device(int);
     873                 :            : void vhost_destroy_device_notify(struct virtio_net *dev);
     874                 :            : 
     875                 :            : void cleanup_vq(struct vhost_virtqueue *vq, int destroy);
     876                 :            : void cleanup_vq_inflight(struct virtio_net *dev, struct vhost_virtqueue *vq);
     877                 :            : void free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq);
     878                 :            : 
     879                 :            : int alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx);
     880                 :            : 
     881                 :            : void vhost_attach_vdpa_device(int vid, struct rte_vdpa_device *dev);
     882                 :            : 
     883                 :            : void vhost_set_ifname(int, const char *if_name, unsigned int if_len);
     884                 :            : void vhost_setup_virtio_net(int vid, bool enable, bool legacy_ol_flags, bool stats_enabled,
     885                 :            :         bool support_iommu);
     886                 :            : void vhost_enable_extbuf(int vid);
     887                 :            : void vhost_enable_linearbuf(int vid);
     888                 :            : int vhost_enable_guest_notification(struct virtio_net *dev,
     889                 :            :                 struct vhost_virtqueue *vq, int enable);
     890                 :            : 
     891                 :            : struct rte_vhost_device_ops const *vhost_driver_callback_get(const char *path);
     892                 :            : 
     893                 :            : /*
     894                 :            :  * Backend-specific cleanup.
     895                 :            :  *
     896                 :            :  * TODO: fix it; we have one backend now
     897                 :            :  */
     898                 :            : void vhost_backend_cleanup(struct virtio_net *dev);
     899                 :            : 
     900                 :            : uint64_t __vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
     901                 :            :                         uint64_t iova, uint64_t *len, uint8_t perm)
     902                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     903                 :            : void *vhost_alloc_copy_ind_table(struct virtio_net *dev,
     904                 :            :                         struct vhost_virtqueue *vq,
     905                 :            :                         uint64_t desc_addr, uint64_t desc_len)
     906                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     907                 :            : int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq)
     908                 :            :         __rte_requires_capability(&vq->access_lock)
     909                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     910                 :            : uint64_t translate_log_addr(struct virtio_net *dev, struct vhost_virtqueue *vq,
     911                 :            :                 uint64_t log_addr)
     912                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock);
     913                 :            : void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq)
     914                 :            :         __rte_requires_capability(&vq->access_lock);
     915                 :            : 
     916                 :            : static __rte_always_inline uint64_t
     917                 :            : vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq,
     918                 :            :                         uint64_t iova, uint64_t *len, uint8_t perm)
     919                 :            :         __rte_requires_shared_capability(&vq->iotlb_lock)
     920                 :            : {
     921   [ #  #  #  #  :          0 :         if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM)))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     922                 :          0 :                 return rte_vhost_va_from_guest_pa(dev->mem, iova, len);
     923                 :            : 
     924                 :          0 :         return __vhost_iova_to_vva(dev, vq, iova, len, perm);
     925                 :            : }
     926                 :            : 
     927                 :            : #define vhost_avail_event(vr) \
     928                 :            :         (*(volatile uint16_t*)&(vr)->used->ring[(vr)->size])
     929                 :            : #define vhost_used_event(vr) \
     930                 :            :         (*(volatile uint16_t*)&(vr)->avail->ring[(vr)->size])
     931                 :            : 
     932                 :            : /*
     933                 :            :  * The following is used with VIRTIO_RING_F_EVENT_IDX.
     934                 :            :  * Assuming a given event_idx value from the other size, if we have
     935                 :            :  * just incremented index from old to new_idx, should we trigger an
     936                 :            :  * event?
     937                 :            :  */
     938                 :            : static __rte_always_inline int
     939                 :            : vhost_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
     940                 :            : {
     941                 :          0 :         return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old);
     942                 :            : }
     943                 :            : 
     944                 :            : static __rte_always_inline void
     945                 :            : vhost_vring_inject_irq(struct virtio_net *dev, struct vhost_virtqueue *vq)
     946                 :            : {
     947                 :          0 :         bool expected = false;
     948                 :            : 
     949   [ #  #  #  #  :          0 :         if (dev->notify_ops->guest_notify) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     950   [ #  #  #  #  :          0 :                 if (rte_atomic_compare_exchange_strong_explicit(&vq->irq_pending, &expected, true,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     951                 :            :                                   rte_memory_order_release, rte_memory_order_relaxed)) {
     952   [ #  #  #  #  :          0 :                         if (dev->notify_ops->guest_notify(dev->vid, vq->index)) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     953   [ #  #  #  #  :          0 :                                 if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     954                 :          0 :                                         rte_atomic_fetch_add_explicit(
     955                 :            :                                                 &vq->stats.guest_notifications_offloaded,
     956                 :            :                                                 1, rte_memory_order_relaxed);
     957                 :          0 :                                 return;
     958                 :            :                         }
     959                 :            : 
     960                 :            :                         /* Offloading failed, fallback to direct IRQ injection */
     961                 :          0 :                         rte_atomic_store_explicit(&vq->irq_pending, false,
     962                 :            :                                 rte_memory_order_release);
     963                 :            :                 } else {
     964                 :          0 :                         vq->stats.guest_notifications_suppressed++;
     965                 :          0 :                         return;
     966                 :            :                 }
     967                 :            :         }
     968                 :            : 
     969   [ #  #  #  #  :          0 :         if (dev->backend_ops->inject_irq(dev, vq)) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     970   [ #  #  #  #  :          0 :                 if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     971                 :          0 :                         rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications_error,
     972                 :            :                                 1, rte_memory_order_relaxed);
     973                 :            :                 return;
     974                 :            :         }
     975                 :            : 
     976   [ #  #  #  #  :          0 :         if (dev->flags & VIRTIO_DEV_STATS_ENABLED)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     977                 :          0 :                 rte_atomic_fetch_add_explicit(&vq->stats.guest_notifications,
     978                 :            :                         1, rte_memory_order_relaxed);
     979   [ #  #  #  #  :          0 :         if (dev->notify_ops->guest_notified)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     980                 :          0 :                 dev->notify_ops->guest_notified(dev->vid);
     981                 :            : }
     982                 :            : 
     983                 :            : static __rte_always_inline void
     984                 :            : vhost_vring_call_split(struct virtio_net *dev, struct vhost_virtqueue *vq)
     985                 :            : {
     986                 :            :         /* Flush used->idx update before we read avail->flags. */
     987                 :            :         rte_atomic_thread_fence(rte_memory_order_seq_cst);
     988                 :            : 
     989                 :            :         /* Don't kick guest if we don't reach index specified by guest. */
     990   [ #  #  #  #  :          0 :         if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     991                 :          0 :                 uint16_t old = vq->signalled_used;
     992                 :          0 :                 uint16_t new = vq->last_used_idx;
     993                 :          0 :                 bool signalled_used_valid = vq->signalled_used_valid;
     994                 :            : 
     995                 :          0 :                 vq->signalled_used = new;
     996                 :          0 :                 vq->signalled_used_valid = true;
     997                 :            : 
     998                 :            :                 VHOST_DATA_LOG(dev->ifname, DEBUG,
     999                 :            :                         "%s: used_event_idx=%d, old=%d, new=%d",
    1000                 :            :                         __func__, vhost_used_event(vq), old, new);
    1001                 :            : 
    1002   [ #  #  #  #  :          0 :                 if (vhost_need_event(vhost_used_event(vq), new, old) ||
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1003   [ #  #  #  #  :          0 :                                 unlikely(!signalled_used_valid))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1004                 :            :                         vhost_vring_inject_irq(dev, vq);
    1005                 :            :         } else {
    1006                 :            :                 /* Kick the guest if necessary. */
    1007   [ #  #  #  #  :          0 :                 if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1008                 :            :                         vhost_vring_inject_irq(dev, vq);
    1009                 :            :         }
    1010                 :            : }
    1011                 :            : 
    1012                 :            : static __rte_always_inline void
    1013                 :            : vhost_vring_call_packed(struct virtio_net *dev, struct vhost_virtqueue *vq)
    1014                 :            : {
    1015                 :            :         uint16_t old, new, off, off_wrap;
    1016                 :            :         bool signalled_used_valid, kick = false;
    1017                 :            : 
    1018                 :            :         /* Flush used desc update. */
    1019                 :            :         rte_atomic_thread_fence(rte_memory_order_seq_cst);
    1020                 :            : 
    1021   [ #  #  #  #  :          0 :         if (!(dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1022   [ #  #  #  #  :          0 :                 if (vq->driver_event->flags !=
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1023                 :            :                                 VRING_EVENT_F_DISABLE)
    1024                 :            :                         kick = true;
    1025                 :          0 :                 goto kick;
    1026                 :            :         }
    1027                 :            : 
    1028                 :          0 :         old = vq->signalled_used;
    1029                 :          0 :         new = vq->last_used_idx;
    1030                 :          0 :         vq->signalled_used = new;
    1031                 :          0 :         signalled_used_valid = vq->signalled_used_valid;
    1032                 :          0 :         vq->signalled_used_valid = true;
    1033                 :            : 
    1034   [ #  #  #  #  :          0 :         if (vq->driver_event->flags != VRING_EVENT_F_DESC) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1035   [ #  #  #  #  :          0 :                 if (vq->driver_event->flags != VRING_EVENT_F_DISABLE)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1036                 :            :                         kick = true;
    1037                 :          0 :                 goto kick;
    1038                 :            :         }
    1039                 :            : 
    1040   [ #  #  #  #  :          0 :         if (unlikely(!signalled_used_valid)) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1041                 :            :                 kick = true;
    1042                 :          0 :                 goto kick;
    1043                 :            :         }
    1044                 :            : 
    1045                 :            :         rte_atomic_thread_fence(rte_memory_order_acquire);
    1046                 :            : 
    1047                 :          0 :         off_wrap = vq->driver_event->off_wrap;
    1048                 :          0 :         off = off_wrap & ~(1 << 15);
    1049                 :            : 
    1050   [ #  #  #  #  :          0 :         if (new <= old)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1051                 :          0 :                 old -= vq->size;
    1052                 :            : 
    1053   [ #  #  #  #  :          0 :         if (vq->used_wrap_counter != off_wrap >> 15)
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1054                 :          0 :                 off -= vq->size;
    1055                 :            : 
    1056   [ #  #  #  #  :          0 :         if (vhost_need_event(off, new, old))
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1057                 :            :                 kick = true;
    1058                 :          0 : kick:
    1059                 :            :         if (kick)
    1060                 :            :                 vhost_vring_inject_irq(dev, vq);
    1061                 :            : }
    1062                 :            : 
    1063                 :            : static __rte_always_inline void
    1064                 :            : free_ind_table(void *idesc)
    1065                 :            : {
    1066                 :          0 :         rte_free(idesc);
    1067                 :          0 : }
    1068                 :            : 
    1069                 :            : static __rte_always_inline void
    1070                 :            : restore_mbuf(struct rte_mbuf *m)
    1071                 :            : {
    1072                 :            :         uint32_t mbuf_size, priv_size;
    1073                 :            : 
    1074                 :            :         while (m) {
    1075                 :            :                 priv_size = rte_pktmbuf_priv_size(m->pool);
    1076                 :            :                 mbuf_size = sizeof(struct rte_mbuf) + priv_size;
    1077                 :            :                 /* start of buffer is after mbuf structure and priv data */
    1078                 :            : 
    1079                 :            :                 m->buf_addr = (char *)m + mbuf_size;
    1080                 :            :                 rte_mbuf_iova_set(m, rte_mempool_virt2iova(m) + mbuf_size);
    1081                 :            :                 m = m->next;
    1082                 :            :         }
    1083                 :            : }
    1084                 :            : 
    1085                 :            : static __rte_always_inline bool
    1086                 :            : mbuf_is_consumed(struct rte_mbuf *m)
    1087                 :            : {
    1088                 :            :         while (m) {
    1089                 :            :                 if (rte_mbuf_refcnt_read(m) > 1)
    1090                 :            :                         return false;
    1091                 :            :                 m = m->next;
    1092                 :            :         }
    1093                 :            : 
    1094                 :            :         return true;
    1095                 :            : }
    1096                 :            : 
    1097                 :            : void mem_set_dump(struct virtio_net *dev, void *ptr, size_t size, bool enable, uint64_t alignment);
    1098                 :            : 
    1099                 :            : #endif /* _VHOST_NET_CDEV_H_ */

Generated by: LCOV version 1.14