LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_dpdk_virtio.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 398 850 46.8 %
Date: 2026-08-03 02:19:58 Functions: 30 40 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_dpdk_virtio.c - implements DPDK forwarding infrastructure for
       3             :  * virtio interfaces. The virtio data structures are setup by the user
       4             :  * space vhost server.
       5             :  *
       6             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       7             :  */
       8             : 
       9             : #include "vr_dpdk.h"
      10             : #include "vr_dpdk_virtio.h"
      11             : #include "vr_uvhost_client.h"
      12             : 
      13             : #include <linux/virtio_net.h>
      14             : #include <sys/eventfd.h>
      15             : 
      16             : #include <sys/mman.h>
      17             : #include <sys/stat.h>
      18             : #include <sys/types.h>
      19             : #include <unistd.h>
      20             : 
      21             : #include <rte_malloc.h>
      22             : #include <rte_memcpy.h>
      23             : 
      24             : #define VIRTIO_HDR_MRG_RXBUF 1
      25             : 
      26             : void *vr_dpdk_vif_clients[VR_MAX_INTERFACES];
      27             : vr_dpdk_virtioq_t vr_dpdk_virtio_rxqs[VR_MAX_INTERFACES][VR_DPDK_VIRTIO_MAX_QUEUES];
      28             : vr_dpdk_virtioq_t vr_dpdk_virtio_txqs[VR_MAX_INTERFACES][VR_DPDK_VIRTIO_MAX_QUEUES];
      29             : 
      30             : static int dpdk_virtio_from_vm_rx(void *port, struct rte_mbuf **pkts,
      31             :                                   uint32_t max_pkts);
      32             : static int dpdk_virtio_to_vm_tx(void *port, struct rte_mbuf *pkt);
      33             : static int dpdk_virtio_to_vm_flush(void *port);
      34             : static int dpdk_virtio_writer_stats_read(void *port,
      35             :                                             struct rte_port_out_stats *stats,
      36             :                                             int clear);
      37             : static int dpdk_virtio_reader_stats_read(void *port,
      38             :                                             struct rte_port_in_stats *stats,
      39             :                                             int clear);
      40             : 
      41             : /*
      42             :  * Virtio writer
      43             :  */
      44             : struct dpdk_virtio_writer {
      45             :     struct rte_port_out_stats stats;
      46             :     /* extra statistics */
      47             :     uint64_t nb_syscalls;
      48             :     /* last packet TX */
      49             :     uint64_t last_pkt_tx;
      50             :     /* last TX flush */
      51             :     uint64_t last_pkt_tx_flush;
      52             : 
      53             :     vr_dpdk_virtioq_t *tx_virtioq;
      54             :     struct rte_mbuf *tx_buf[VR_DPDK_VIRTIO_TX_BURST_SZ];
      55             :     /* Total number of mbuf chains
      56             :      * Say if a mbuf chain contains 10 segments, it is counted as 1
      57             :      */
      58             :     uint32_t tx_buf_count;
      59             :     /* Total number of mbufs in all the chains */
      60             :     uint32_t tx_mbufs;
      61             : };
      62             : 
      63             : struct dpdk_virtio_writer_params {
      64             :     /* virtio TX queue pointer */
      65             :     vr_dpdk_virtioq_t *tx_virtioq;
      66             : };
      67             : 
      68             : /*
      69             :  * vr_dpdk_virtio_stop - stop the virtio interface.
      70             :  *
      71             :  * Returns 0 on success, -1 otherwise.
      72             :  */
      73             : int
      74         554 : vr_dpdk_virtio_stop(unsigned int vif_idx)
      75             : {
      76             :     int i;
      77             :     vr_dpdk_virtioq_t *vq;
      78             : 
      79         554 :     if (vif_idx >= VR_MAX_INTERFACES) {
      80           0 :         return -1;
      81             :     }
      82             : 
      83             :     /* Disable and reset all the virtio queues. */
      84       18282 :     for (i = 0; i < VR_DPDK_VIRTIO_MAX_QUEUES*2; i++) {
      85       17728 :         if (i & 1) {
      86        8864 :             vq = &vr_dpdk_virtio_rxqs[vif_idx][i/2];
      87             :         } else {
      88        8864 :             vq = &vr_dpdk_virtio_txqs[vif_idx][i/2];
      89             :         }
      90             : 
      91       17728 :         if (vq->vdv_ready_state != VQ_NOT_READY) {
      92         388 :             vr_dpdk_set_virtq_ready(vif_idx, i, VQ_NOT_READY);
      93             :             rte_wmb();
      94         388 :             synchronize_rcu();
      95             :             /*
      96             :              * TODO: code duplication to minimize the changes.
      97             :              * See vr_dpdk_virtio_get_vring_base().
      98             :              */
      99         388 :             vq->vdv_desc = NULL;
     100         388 :             if (vq->vdv_callfd) {
     101         388 :                 close(vq->vdv_callfd);
     102         388 :                 vq->vdv_callfd = 0;
     103             :             }
     104             :         }
     105             :     }
     106             : 
     107         554 :     return 0;
     108             : }
     109             : 
     110             : static void *
     111        1328 : dpdk_virtio_writer_create(void *params, int socket_id)
     112             : {
     113        1328 :     struct dpdk_virtio_writer_params *conf =
     114             :             (struct dpdk_virtio_writer_params *) params;
     115             :     struct dpdk_virtio_writer *port;
     116             : 
     117             :     /* Check input parameters */
     118        1328 :     if (conf == NULL) {
     119           0 :         RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
     120           0 :         return NULL;
     121             :     }
     122             : 
     123             :     /* Memory allocation */
     124        1328 :     port = rte_zmalloc_socket("PORT", sizeof(*port),
     125             :             RTE_CACHE_LINE_SIZE, socket_id);
     126        1328 :     if (port == NULL) {
     127           0 :         RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
     128           0 :         return NULL;
     129             :     }
     130             : 
     131             :     /* Initialization */
     132        1328 :     port->tx_virtioq = conf->tx_virtioq;
     133             : 
     134        1328 :     return port;
     135             : }
     136             : 
     137             : static int
     138         860 : dpdk_virtio_writer_free(void *port)
     139             : {
     140             :     vr_dpdk_virtioq_t *tx_virtioq;
     141             : 
     142         860 :     if (port == NULL) {
     143           0 :         RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
     144           0 :         return -EINVAL;
     145             :     }
     146             : 
     147         860 :     tx_virtioq = ((struct dpdk_virtio_writer *)port)->tx_virtioq;
     148             : 
     149             :     /* close FDs */
     150         860 :     if (tx_virtioq->vdv_callfd > 0) {
     151           0 :         close(tx_virtioq->vdv_callfd);
     152             :     }
     153         860 :     if (tx_virtioq->vdv_kickfd > 0) {
     154           0 :         close(tx_virtioq->vdv_kickfd);
     155             :     }
     156             : 
     157             :     /* reset the virtio */
     158         860 :     memset(tx_virtioq, 0, sizeof(vr_dpdk_virtioq_t));
     159             : 
     160         860 :     rte_free(port);
     161             : 
     162         860 :     return 0;
     163             : }
     164             : 
     165             : struct rte_port_out_ops vr_dpdk_virtio_writer_ops = {
     166             :     .f_create = dpdk_virtio_writer_create,
     167             :     .f_free = dpdk_virtio_writer_free,
     168             :     .f_tx = dpdk_virtio_to_vm_tx,
     169             :     .f_tx_bulk = NULL, /* TODO: not implemented */
     170             :     .f_flush = dpdk_virtio_to_vm_flush,
     171             :     .f_stats = dpdk_virtio_writer_stats_read
     172             : };
     173             : 
     174             : /*
     175             :  * Virtio reader
     176             :  */
     177             : struct dpdk_virtio_reader {
     178             :     struct rte_port_in_stats stats;
     179             :     /* extra statistics */
     180             :     uint64_t nb_syscalls;
     181             :     uint64_t nb_nombufs;
     182             : 
     183             :     vr_dpdk_virtioq_t *rx_virtioq;
     184             : };
     185             : 
     186             : struct dpdk_virtio_reader_params {
     187             :     /* virtio RX queue pointer */
     188             :     vr_dpdk_virtioq_t *rx_virtioq;
     189             : };
     190             : 
     191             : static void *
     192         664 : dpdk_virtio_reader_create(void *params, int socket_id)
     193             : {
     194         664 :     struct dpdk_virtio_reader_params *conf =
     195             :             (struct dpdk_virtio_reader_params *) params;
     196             :     struct dpdk_virtio_reader *port;
     197             : 
     198             :     /* Check input parameters */
     199         664 :     if (conf == NULL) {
     200           0 :         RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
     201           0 :         return NULL;
     202             :     }
     203             : 
     204             :     /* Memory allocation */
     205         664 :     port = rte_zmalloc_socket("PORT", sizeof(*port),
     206             :             RTE_CACHE_LINE_SIZE, socket_id);
     207         664 :     if (port == NULL) {
     208           0 :         RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
     209           0 :         return NULL;
     210             :     }
     211             : 
     212             :     /* Initialization */
     213         664 :     port->rx_virtioq = conf->rx_virtioq;
     214             : 
     215         664 :     return port;
     216             : }
     217             : 
     218             : static int
     219         430 : dpdk_virtio_reader_free(void *port)
     220             : {
     221             :     vr_dpdk_virtioq_t *rx_virtioq;
     222             : 
     223         430 :     if (port == NULL) {
     224           0 :         RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
     225           0 :         return -EINVAL;
     226             :     }
     227             : 
     228         430 :     rx_virtioq = ((struct dpdk_virtio_reader *)port)->rx_virtioq;
     229             : 
     230             :     /* close FDs */
     231         430 :     if (rx_virtioq->vdv_callfd > 0) {
     232           0 :         close(rx_virtioq->vdv_callfd);
     233             :     }
     234         430 :     if (rx_virtioq->vdv_kickfd > 0) {
     235           0 :         close(rx_virtioq->vdv_kickfd);
     236             :     }
     237             : 
     238             :     /* reset the virtio */
     239         430 :     memset(rx_virtioq, 0, sizeof(vr_dpdk_virtioq_t));
     240             : 
     241         430 :     rte_free(port);
     242             : 
     243         430 :     return 0;
     244             : }
     245             : 
     246             : 
     247             : struct rte_port_in_ops vr_dpdk_virtio_reader_ops = {
     248             :     .f_create = dpdk_virtio_reader_create,
     249             :     .f_free = dpdk_virtio_reader_free,
     250             :     .f_rx = dpdk_virtio_from_vm_rx,
     251             :     .f_stats = dpdk_virtio_reader_stats_read
     252             : };
     253             : 
     254             : /*
     255             :  * vr_dpdk_vrtio_uvh_get_blk_size - set the block size of fd.
     256             :  * On error -1 is returned, otherwise 0.
     257             :  */
     258             : int
     259         388 : vr_dpdk_virtio_uvh_get_blk_size(int fd, uint64_t *const blksize)
     260             : {
     261             :     struct stat fd_stat;
     262             :     int ret;
     263         388 :     memset(&fd_stat, 0, sizeof(stat));
     264             : 
     265         388 :     ret = fstat(fd, &fd_stat);
     266         388 :     if (!ret){
     267         388 :         *blksize = (uint64_t)fd_stat.st_blksize;
     268             :     } else {
     269             :         RTE_LOG_DP(DEBUG, UVHOST, "Error getting file status for FD %d: %s (%d)\n",
     270             :                 fd, strerror(errno), errno);
     271             :     }
     272             : 
     273         388 :     return ret;
     274             : }
     275             : 
     276             : /*
     277             :  * vr_dpdk_virtio_nrxqs - returns the number of receives queues for a virtio
     278             :  * interface.
     279             :  */
     280             : uint16_t
     281         996 : vr_dpdk_virtio_nrxqs(struct vr_interface *vif)
     282             : {
     283         996 :     return vr_dpdk.nb_fwd_lcores;
     284             : }
     285             : 
     286             : /*
     287             :  * vr_dpdk_virtio_ntxqs - returns the number of transmit queues for a virtio
     288             :  * interface.
     289             :  */
     290             : uint16_t
     291        1328 : vr_dpdk_virtio_ntxqs(struct vr_interface *vif)
     292             : {
     293        1328 :     return vr_dpdk.nb_fwd_lcores;
     294             : }
     295             : 
     296             : static unsigned int vif_rx_queue_lcore[VR_MAX_INTERFACES][VR_MAX_INTERFACES];
     297             : 
     298             : /*
     299             :  * dpdk_virtio_rx_queue_release - releases a virtio RX queue.
     300             :  *
     301             :  * Returns nothing.
     302             :  */
     303             : static void
     304         430 : dpdk_virtio_rx_queue_release(unsigned lcore_id,
     305             :         unsigned queue_index __attribute__((unused)),
     306             :         struct vr_interface *vif)
     307             : {
     308         430 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     309         430 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif->vif_idx];
     310         430 :     struct vr_dpdk_queue_params *rx_queue_params
     311         430 :                         = &lcore->lcore_rx_queue_params[vif->vif_idx];
     312             :     /* free the queue */
     313         430 :     if (rx_queue->rxq_ops.f_free(rx_queue->q_queue_h)) {
     314           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u virtio device RX queue\n",
     315             :                     lcore_id);
     316             :     }
     317             : 
     318             :     /* reset the queue */
     319         430 :     vrouter_put_interface(rx_queue->q_vif);
     320         430 :     memset(rx_queue, 0, sizeof(*rx_queue));
     321         430 :     memset(rx_queue_params, 0, sizeof(*rx_queue_params));
     322         430 : }
     323             : 
     324             : /*
     325             :  * vr_dpdk_virtio_rx_queue_init - initializes a virtio RX queue.
     326             :  *
     327             :  * Returns a pointer to the RX queue on success, NULL otherwise.
     328             :  */
     329             : struct vr_dpdk_queue *
     330         664 : vr_dpdk_virtio_rx_queue_init(unsigned int lcore_id, struct vr_interface *vif,
     331             :                              unsigned int queue_or_lcore_id)
     332             : {
     333         664 :     uint16_t queue_id = queue_or_lcore_id;
     334         664 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     335         664 :     const unsigned int socket_id = rte_lcore_to_socket_id(lcore_id);
     336         664 :     unsigned int vif_idx = vif->vif_idx;
     337         664 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif_idx];
     338         664 :     struct vr_dpdk_queue_params *rx_queue_params =
     339             :         &lcore->lcore_rx_queue_params[vif_idx];
     340             : 
     341             :     /* Check input parameters */
     342         664 :     if (queue_id >= vr_dpdk_virtio_nrxqs(vif)) {
     343           0 :         RTE_LOG(ERR, VROUTER, "    error creating virtio device %s RX queue %"
     344             :             PRIu16 "\n", vif->vif_name, queue_id);
     345           0 :         return NULL;
     346             :     }
     347             : 
     348             :     /* init queue */
     349         664 :     rx_queue->rxq_ops = vr_dpdk_virtio_reader_ops;
     350         664 :     rx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     351             : 
     352             :     /* init virtio queue */
     353         664 :     vr_dpdk_virtio_rxqs[vif_idx][queue_id].vdv_ready_state = VQ_NOT_READY;
     354         664 :     vr_dpdk_virtio_rxqs[vif_idx][queue_id].vdv_last_used_idx = 0;
     355         664 :     vr_dpdk_virtio_rxqs[vif_idx][queue_id].vdv_last_used_idx_res = 0;
     356         664 :     vr_dpdk_virtio_rxqs[vif_idx][queue_id].vdv_vif_idx = vif->vif_idx;
     357             : 
     358             :     /* create the queue */
     359         664 :     struct dpdk_virtio_reader_params reader_params = {
     360         664 :         .rx_virtioq = &vr_dpdk_virtio_rxqs[vif_idx][queue_id],
     361             :     };
     362         664 :     rx_queue->q_queue_h = rx_queue->rxq_ops.f_create(&reader_params, socket_id);
     363         664 :     if (rx_queue->q_queue_h == NULL) {
     364           0 :         RTE_LOG(ERR, VROUTER, "    error creating virtio device %s RX queue %"
     365             :             PRIu16 "\n", vif->vif_name, queue_id);
     366           0 :         return NULL;
     367             :     }
     368         664 :     rx_queue->vring_queue_id = queue_id;
     369             :     /* store queue params */
     370         664 :     rx_queue_params->qp_release_op = &dpdk_virtio_rx_queue_release;
     371             : 
     372             :     /* save the lcore serving the queue for later enabling/disabling */
     373         664 :     vif_rx_queue_lcore[vif_idx][queue_id] = lcore_id;
     374             : 
     375         664 :     return rx_queue;
     376             : }
     377             : 
     378             : /*
     379             :  * dpdk_virtio_tx_queue_release - releases a virtio TX queue.
     380             :  *
     381             :  * Returns nothing.
     382             :  */
     383             : static void
     384         860 : dpdk_virtio_tx_queue_release(unsigned lcore_id, unsigned queue_index,
     385             :         struct vr_interface *vif)
     386             : {
     387         860 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     388         860 :     struct vr_dpdk_queue *tx_queue =
     389         860 :         &lcore->lcore_tx_queues[vif->vif_idx][queue_index];
     390         860 :     struct vr_dpdk_queue_params *tx_queue_params
     391         860 :         = &lcore->lcore_tx_queue_params[vif->vif_idx][queue_index];
     392             : 
     393         860 :     tx_queue->txq_ops.f_tx = NULL;
     394             :     rte_wmb();
     395             : 
     396             :     /* flush and free the queue */
     397         860 :     if (tx_queue->txq_ops.f_free(tx_queue->q_queue_h)) {
     398           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u virtio device TX queue\n",
     399             :                     lcore_id);
     400             :     }
     401             : 
     402             :     /* reset the queue */
     403         860 :     vrouter_put_interface(tx_queue->q_vif);
     404         860 :     memset(tx_queue, 0, sizeof(*tx_queue));
     405         860 :     memset(tx_queue_params, 0, sizeof(*tx_queue_params));
     406         860 : }
     407             : 
     408             : /*
     409             :  * vr_dpdk_virtio_tx_queue_init - initializes a virtio TX queue.
     410             :  *
     411             :  * Returns a pointer to the TX queue on success, NULL otherwise.
     412             :  */
     413             : struct vr_dpdk_queue *
     414        1328 : vr_dpdk_virtio_tx_queue_init(unsigned int lcore_id, struct vr_interface *vif,
     415             :                              unsigned int queue_or_lcore_id)
     416             : {
     417        1328 :     uint16_t queue_id = queue_or_lcore_id;
     418        1328 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     419        1328 :     const unsigned int socket_id = rte_lcore_to_socket_id(lcore_id);
     420        1328 :     unsigned int vif_idx = vif->vif_idx;
     421        1328 :     struct vr_dpdk_queue *tx_queue = &lcore->lcore_tx_queues[vif_idx][0];
     422        1328 :     struct vr_dpdk_queue_params *tx_queue_params
     423             :                 = &lcore->lcore_tx_queue_params[vif_idx][0];
     424             : 
     425             :     /* Check input parameters */
     426             :     /* virtio TX is thread safe, so just use one of the rings */
     427        1328 :     queue_id = queue_id % vr_dpdk_virtio_ntxqs(vif);
     428             : 
     429             :     /* init queue */
     430        1328 :     tx_queue->txq_ops = vr_dpdk_virtio_writer_ops;
     431        1328 :     tx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     432             : 
     433             :     /* init virtio queue */
     434        1328 :     vr_dpdk_virtio_txqs[vif_idx][queue_id].vdv_ready_state = VQ_NOT_READY;
     435        1328 :     vr_dpdk_virtio_txqs[vif_idx][queue_id].vdv_last_used_idx = 0;
     436        1328 :     vr_dpdk_virtio_txqs[vif_idx][queue_id].vdv_last_used_idx_res = 0;
     437        1328 :     vr_dpdk_virtio_txqs[vif_idx][queue_id].vdv_vif_idx = vif->vif_idx;
     438             : 
     439             :     /* create the queue */
     440        1328 :     struct dpdk_virtio_writer_params writer_params = {
     441             :         /*
     442             :          * Always initialize each lcore's tx_queue with virtio queue number 0.
     443             :          * If there are more queues, they will be enabled later via
     444             :          * VHOST_USER_SET_VRING_ENABLE message.
     445             :          */
     446        1328 :         .tx_virtioq = &vr_dpdk_virtio_txqs[vif_idx][0],
     447             :     };
     448        1328 :     tx_queue->q_queue_h = tx_queue->txq_ops.f_create(&writer_params, socket_id);
     449        1328 :     if (tx_queue->q_queue_h == NULL) {
     450           0 :         RTE_LOG(ERR, VROUTER, "    error creating virtio device %s TX queue %"
     451             :             PRIu16 "\n", vif->vif_name, queue_id);
     452           0 :         return NULL;
     453             :     }
     454             : 
     455             :     /* store queue params */
     456        1328 :     tx_queue_params->qp_release_op = &dpdk_virtio_tx_queue_release;
     457             : 
     458        1328 :     return tx_queue;
     459             : }
     460             : 
     461             : struct dpdk_virtio_tx_queue_set_params {
     462             :     unsigned int vif_id;
     463             :     unsigned int vif_gen;
     464             :     unsigned int queue_id;
     465             : };
     466             : 
     467             : static unsigned int vif_lcore_tx_queue[VR_MAX_INTERFACES][VR_MAX_CPUS_DPDK];
     468             : static unsigned int vif_tx_queues_enabled[VR_MAX_INTERFACES];
     469             : 
     470             : /*
     471             :  * Enable or disable given queue for a vif.
     472             :  *
     473             :  * In current vRouter design, every lcore that can send packets has to have a
     474             :  * TX queue available for every existing vif. It is because we do not know
     475             :  * which lcore wil eventually send the packet, and thus each has to have a
     476             :  * queue to use.
     477             :  *
     478             :  * If VM requests more than one virtio queue, then we distribute them among the
     479             :  * forwarding lcores as evenly as possible.
     480             :  *
     481             :  * The entire process (this function, which sends commands to other lcores and
     482             :  * then vr_dpdk_virtio_tx_queue_set(), which is called from the destination
     483             :  * lcores' main loop) works fine as long as the QEMU enables/disables each
     484             :  * queues in ascending order. For example, if the maximal number of queues is
     485             :  * 4, and inside a VM ethtool -L eth0 combined 2 is issued, the QEMU will send
     486             :  * the following messages:
     487             :  * 1. Enable queue 0.
     488             :  * 2. Enable queue 1.
     489             :  * 3. Disable queue 2.
     490             :  * 4. Disable queue 3.
     491             :  *
     492             :  * TODO: Remove the above assumption as there is no guarantee that QEMU will
     493             :  * always work as described.
     494             :  */
     495             : void
     496           0 : vr_dpdk_virtio_tx_queue_enable_disable(unsigned int vif_id,
     497             :                                        unsigned int vif_gen,
     498             :                                        unsigned int queue_id,
     499             :                                        bool enable)
     500             : {
     501             :     unsigned int lcore_id;
     502             :     unsigned int starting_lcore;
     503             :     struct dpdk_virtio_tx_queue_set_params *arg;
     504             :     unsigned int qid;
     505             :     unsigned int queue_num;
     506             : 
     507             :     /* If command is 'disable', we enable all lower numbered queues */
     508           0 :     if (!enable)
     509           0 :         queue_num = queue_id - 1;
     510             :     else
     511           0 :         queue_num = queue_id;
     512             : 
     513             :     /*
     514             :      * Subsequent 'disable' commands are ignored. For example if we enabled
     515             :      * queues 0 and 1, then all higher queues (2, 3, ..) had already been
     516             :      * disabled. Thus we ignore the 'disable' request for them
     517             :      */
     518           0 :     if (!enable && queue_num > vif_tx_queues_enabled[vif_id])
     519           0 :         return;
     520             : 
     521             :     /*
     522             :      * Each lcore that does tx has to have a queue assigned for every
     523             :      * interface. We assign queue 0 for pkt and netlink lcores. All
     524             :      * other queues (including queue 0) are distributed among forwarding
     525             :      * lcores.
     526             :      */
     527           0 :     if (queue_id == 0)
     528           0 :         starting_lcore = VR_DPDK_PACKET_LCORE_ID;
     529             :     else
     530           0 :         starting_lcore = VR_DPDK_FWD_LCORE_ID;
     531             : 
     532           0 :     for (lcore_id = starting_lcore, qid = 0; lcore_id < vr_dpdk.nb_fwd_lcores +
     533           0 :             VR_DPDK_FWD_LCORE_ID; ++lcore_id) {
     534             : 
     535             :         /*
     536             :          * Send cmd to destination lcore only if it has different queue enabled
     537             :          * curently.
     538             :          */
     539           0 :         if (vif_lcore_tx_queue[vif_id][lcore_id - VR_DPDK_PACKET_LCORE_ID] !=
     540             :                 qid) {
     541           0 :             vif_lcore_tx_queue[vif_id][lcore_id - VR_DPDK_PACKET_LCORE_ID] =
     542             :                     qid;
     543             : 
     544           0 :             arg = rte_malloc("virtio_tx_queue_set", sizeof(*arg), 0);
     545             : 
     546           0 :             arg->vif_id = vif_id;
     547           0 :             arg->queue_id = qid;
     548           0 :             arg->vif_gen = vif_gen;
     549             : 
     550           0 :             vr_dpdk_lcore_cmd_post(lcore_id, VR_DPDK_LCORE_TX_QUEUE_SET_CMD,
     551             :                                    (uint64_t)arg);
     552             :         }
     553             : 
     554           0 :         ++qid;
     555           0 :         qid %= queue_num + 1;
     556             :     }
     557             : 
     558             :     /* Save current number of TX queues enabled for vif */
     559           0 :     vif_tx_queues_enabled[vif_id] = queue_num;
     560             : }
     561             : 
     562             : /*
     563             :  * Assign given virtio queue to vRouter's dpdk (per lcore) tx queue.
     564             :  *
     565             :  * The assignment is done by setting correct virtio queue pointer in the
     566             :  * lcore's tx queue handler.
     567             :  *
     568             :  * This function is called only from the main loops of the lcores that have TX
     569             :  * queues (packet lcore, netlink lcore, forwarding lcores).
     570             :  */
     571             : void
     572           0 : vr_dpdk_virtio_tx_queue_set(void *arg)
     573             : {
     574           0 :     struct dpdk_virtio_tx_queue_set_params *p = arg;
     575             :     struct vr_dpdk_queue *tx_queue;
     576             :     struct dpdk_virtio_writer *port;
     577             :     struct vr_dpdk_lcore *lcore;
     578             :     struct vr_interface *vif;
     579             : 
     580             :     /* Check if vif is still valid */
     581           0 :     vif = __vrouter_get_interface(vrouter_get(0), p->vif_id);
     582           0 :     if (!vif || vif->vif_gen != p->vif_gen) {
     583           0 :         rte_free(arg);
     584           0 :         return;
     585             :     }
     586             : 
     587           0 :     lcore = vr_dpdk.lcores[rte_lcore_id()];
     588           0 :     tx_queue = &lcore->lcore_tx_queues[p->vif_id][0];
     589           0 :     port = (struct dpdk_virtio_writer *)tx_queue->q_queue_h;
     590             : 
     591             :     /* Assign new queue to the lcore's tx_queue handler */
     592           0 :     port->tx_virtioq = &vr_dpdk_virtio_txqs[p->vif_id][p->queue_id];
     593             : 
     594             :     /*
     595             :      * Each tx_queue has to have a f_flush method, but we do not need to crash
     596             :      * in other case.
     597             :      */
     598           0 :     if (tx_queue->txq_ops.f_flush)
     599           0 :         tx_queue->txq_ops.f_flush(tx_queue->q_queue_h);
     600             :     else
     601           0 :         RTE_LOG(ERR, VROUTER, "%s: Flush function for tx_queue(%p) unavailable\n",
     602             :                 __func__, tx_queue);
     603             : 
     604           0 :     rte_free(arg);
     605             : }
     606             : 
     607             : struct dpdk_virtio_rx_queue_set_params {
     608             :     bool enable;
     609             :     unsigned int vif_id;
     610             :     unsigned int vif_gen;
     611             :     unsigned int queue_id;
     612             : };
     613             : 
     614             : 
     615             : void
     616             : dpdk_lcore_queue_add(unsigned lcore_id, struct vr_dpdk_q_slist *q_head,
     617             :                      struct vr_dpdk_queue *queue);
     618             : void
     619             : dpdk_lcore_rx_queue_remove(struct vr_dpdk_lcore *lcore,
     620             :                            struct vr_dpdk_queue *rx_queue,
     621             :                            bool clear_f_rx);
     622             : 
     623             : /*
     624             :  * Called on uvhost lcore only.
     625             :  */
     626             : void
     627           0 : vr_dpdk_virtio_rx_queue_enable_disable(unsigned int vif_id,
     628             :                                        unsigned int vif_gen,
     629             :                                        unsigned int queue_id,
     630             :                                        bool enable)
     631             : {
     632             :     struct dpdk_virtio_rx_queue_set_params *arg;
     633             : 
     634             :     /*
     635             :      * Ignore requests for queue number 0. It has already been added to lcore's
     636             :      * list of queues and can never be disabled (qemu never sends the 'disable'
     637             :      * command for queue 0). Doing otherwise would result in double adding the
     638             :      * virtio queue to lcore's list of rx queues.
     639             :      */
     640           0 :     if (queue_id == 0)
     641           0 :         return;
     642             : 
     643           0 :     arg = rte_malloc("virtio_rx_queue_set", sizeof(*arg), 0);
     644             : 
     645           0 :     arg->vif_id = vif_id;
     646           0 :     arg->vif_gen = vif_gen;
     647           0 :     arg->queue_id = queue_id;
     648           0 :     arg->enable = enable;
     649             : 
     650           0 :     vr_dpdk_lcore_cmd_post(VR_DPDK_NETLINK_LCORE_ID,
     651             :                            VR_DPDK_LCORE_RX_QUEUE_SET_CMD, (uint64_t)arg);
     652             : }
     653             : 
     654             : /*
     655             :  * Called only on netlink lcore.
     656             :  */
     657             : void
     658           0 : vr_dpdk_virtio_rx_queue_set(void *arg)
     659             : {
     660           0 :     struct dpdk_virtio_rx_queue_set_params *p = arg;
     661             :     struct vr_interface *vif;
     662             :     struct vr_dpdk_queue *rx_queue;
     663             :     struct vr_dpdk_lcore *lcore;
     664             :     unsigned int lcore_id;
     665             :     struct vr_dpdk_lcore_rx_queue_remove_arg *rx_rm_arg;
     666             : 
     667             :     /* Check if vif is still valid */
     668           0 :     vif = __vrouter_get_interface(vrouter_get(0), p->vif_id);
     669           0 :     if (!vif || vif->vif_gen != p->vif_gen) {
     670           0 :         rte_free(arg);
     671           0 :         return;
     672             :     }
     673             : 
     674           0 :     if (p->enable) {
     675           0 :         lcore_id = vif_rx_queue_lcore[p->vif_id][p->queue_id];
     676           0 :         lcore = vr_dpdk.lcores[lcore_id];
     677           0 :         rx_queue = &lcore->lcore_rx_queues[p->vif_id];
     678           0 :         lcore->lcore_rx_queues[p->vif_id].vring_queue_id = p->queue_id;
     679           0 :         dpdk_lcore_queue_add(lcore_id, &lcore->lcore_rx_head, rx_queue);
     680             : 
     681             :     } else {
     682           0 :         lcore_id = vif_rx_queue_lcore[p->vif_id][p->queue_id];
     683           0 :         lcore = vr_dpdk.lcores[lcore_id];
     684           0 :         rx_queue = &lcore->lcore_rx_queues[p->vif_id];
     685           0 :         if (rx_queue->enabled) {
     686           0 :             rx_rm_arg = rte_malloc("lcore_rx_queue_rm_cmd", sizeof(*rx_rm_arg),
     687             :                     0);
     688           0 :             rx_rm_arg->vif_id = vif->vif_idx;
     689           0 :             rx_rm_arg->clear_f_rx = false;
     690           0 :             rx_rm_arg->free_arg = true;
     691           0 :             vr_dpdk_lcore_cmd_post(lcore_id, VR_DPDK_LCORE_RX_RM_CMD,
     692             :                                    (uint64_t)rx_rm_arg);
     693             :         }
     694             :     }
     695             : 
     696           0 :     rte_free(arg);
     697             : }
     698             : 
     699             : /*
     700             :  * vr_dpdk_guest_phys_to_host_virt - convert a guest physical address
     701             :  * to a host virtual address. Uses the guest memory map stored in the
     702             :  * vhost client for the guest interface.
     703             :  *
     704             :  * Returns address on success, NULL otherwise.
     705             :  */
     706             : static char *
     707         243 : vr_dpdk_guest_phys_to_host_virt(vr_uvh_client_t *vru_cl, uint64_t paddr)
     708             : {
     709             :     int i;
     710             :     vr_uvh_client_mem_region_t *reg;
     711             : 
     712         403 :     for (i = 0; i < vru_cl->vruc_num_mem_regions; i++) {
     713         403 :         reg = &vru_cl->vruc_mem_regions[i];
     714             : 
     715         403 :         if ((paddr >= reg->vrucmr_phys_addr) &&
     716         243 :                 (paddr <= (reg->vrucmr_phys_addr + reg->vrucmr_size))) {
     717         243 :             return ((char *) reg->vrucmr_mmap_addr) +
     718         243 :                         (paddr - reg->vrucmr_phys_addr);
     719             :         }
     720             :     }
     721             : 
     722           0 :     return NULL;
     723             : }
     724             : 
     725             : #ifdef RTE_PORT_STATS_COLLECT
     726             : 
     727             : #define DPDK_VIRTIO_READER_STATS_PKTS_IN_ADD(port, val) \
     728             :         port->stats.n_pkts_in += val
     729             : #define DPDK_VIRTIO_READER_STATS_PKTS_DROP_ADD(port, val) \
     730             :         port->stats.n_pkts_drop += val
     731             : 
     732             : #else
     733             : 
     734             : /* keep compiler happy, for unused variables */
     735             : #define DPDK_VIRTIO_READER_STATS_PKTS_IN_ADD(port, val) \
     736             :         (void)(val)
     737             : #define DPDK_VIRTIO_READER_STATS_PKTS_DROP_ADD(port, val) \
     738             :         (void)(val)
     739             : 
     740             : #endif
     741             : 
     742             : static inline uint32_t
     743           0 : dpdk_virtio_get_ip_tcp_hdr_len(char *pkt_addr, uint32_t pkt_len)
     744             : {
     745           0 :     struct vr_eth *eth_hdr = (struct vr_eth*)pkt_addr;
     746           0 :     struct vr_ip6 *ipv6_hdr = NULL;
     747           0 :     struct vr_tcp *tcp_hdr = NULL;
     748           0 :     unsigned int pull_len = VR_ETHER_HLEN;
     749             :     unsigned short eth_proto;
     750             : 
     751           0 :     if (unlikely(pkt_len < pull_len))
     752           0 :         return 0;
     753             : 
     754           0 :     eth_proto = eth_hdr->eth_proto;
     755             : 
     756             :     /* Skip VLAN tag which may be present if VM sends tagged pkts */
     757           0 :     while (eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_VLAN)) {
     758           0 :         if (unlikely(pkt_len < pull_len + VR_VLAN_HLEN))
     759           0 :             return 0;
     760           0 :         eth_proto = ((struct vr_vlan_hdr *)((uintptr_t)eth_hdr + pull_len))->vlan_proto;
     761           0 :         pull_len += VR_VLAN_HLEN;
     762             :     }
     763             : 
     764           0 :     if (likely(eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_IP))) {
     765           0 :         struct vr_ip *ipv4_hdr = NULL;
     766             :         uint32_t ipv4_hlen;
     767           0 :         ipv4_hdr = (struct vr_ip *)((uintptr_t)eth_hdr + pull_len);
     768             : 
     769           0 :         if (unlikely(pkt_len < pull_len + sizeof(struct vr_ip)))
     770           0 :             return 0;
     771             : 
     772           0 :         ipv4_hlen = ((ipv4_hdr->ip_hl) * RTE_IPV4_IHL_MULTIPLIER);
     773           0 :         pull_len += ipv4_hlen;
     774           0 :         tcp_hdr = (struct vr_tcp*)((uint8_t*)ipv4_hdr + ipv4_hlen);
     775           0 :     } else if (eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_IP6)) {
     776           0 :         ipv6_hdr = (struct vr_ip6 *)((uintptr_t)eth_hdr + pull_len);
     777             : 
     778           0 :         if (unlikely(pkt_len < pull_len + sizeof(struct vr_ip6)))
     779           0 :             return 0;
     780             : 
     781           0 :         pull_len += sizeof(*ipv6_hdr);
     782           0 :         tcp_hdr = (struct vr_tcp*)((uint8_t*)ipv6_hdr + sizeof(*ipv6_hdr));
     783             :     }
     784           0 :     if (likely(tcp_hdr != NULL)) {
     785           0 :         pull_len +=  (VR_TCP_OFFSET(tcp_hdr->tcp_offset_r_flags) << 2);
     786             :     }
     787             : 
     788           0 :     return pull_len;
     789             : }
     790             : 
     791           0 : static inline char *dpdk_pktmbuf_append(struct rte_mbuf *m, struct rte_mbuf *last, uint16_t len)
     792             : {
     793             :     void *tail;
     794             :     struct rte_mbuf *m_last;
     795             : 
     796             :     __rte_mbuf_sanity_check(m, 1);
     797             :     __rte_mbuf_sanity_check(last, 1);
     798             : 
     799           0 :     m_last = rte_pktmbuf_lastseg(last);
     800           0 :     if (unlikely(len > rte_pktmbuf_tailroom(m_last)))
     801           0 :         return NULL;
     802             : 
     803           0 :     tail = (char *)m_last->buf_addr + m_last->data_off + m_last->data_len;
     804           0 :     m_last->data_len = (uint16_t)(m_last->data_len + len);
     805           0 :     m->pkt_len  = (m->pkt_len + len);
     806           0 :     return (char*) tail;
     807             : }
     808             : 
     809             : /*
     810             :  * dpdk_virtio_create_mss_sized_mbuf_chain - Create a chained mbuf where each segment
     811             :  * in the chain is of length 'mss' and copy the data pointed to by pkt_addr
     812             :  *
     813             :  * @input -
     814             :  *    mbuf:       pointer to the mbuf where the chain needs to be created
     815             :  *    mss:        lenght of each segment in the chain
     816             :  *    pkt_addr:   pointer to the data which has to be copied to mbuf
     817             :  *    pkt_len:    length of the data which has to be copied
     818             :  *    header_len: first segment of the chain will have a length of mss + this value
     819             :  *                to account for the headers
     820             :  *
     821             :  * @output -
     822             :  *    0: success
     823             :  *   -1: failure
     824             :  */
     825             : static int
     826           0 : dpdk_virtio_create_mss_sized_mbuf_chain(struct rte_mbuf *mbuf,
     827             :         uint32_t mss, char* pkt_addr, uint32_t pkt_len, uint32_t header_len)
     828             : {
     829           0 :     char *tail_addr, *append_addr = pkt_addr;
     830           0 :     uint32_t pktlen_to_copy = pkt_len, copy_len;
     831           0 :     struct rte_mbuf *new_mbuf, *last_mbuf = rte_pktmbuf_lastseg(mbuf);
     832             : 
     833             :     /* header is only applicable for first segment */
     834           0 :     if (mbuf->nb_segs > 1)
     835           0 :         header_len = 0;
     836             : 
     837             :     /* Cannot compute checksum of odd sized mbufs in chain,
     838             :      * so make it even sized
     839             :      */
     840           0 :     if (mss & 1)
     841           0 :         mbuf->tso_segsz = mss -=1;
     842             : 
     843           0 :     while (pktlen_to_copy > 0) {
     844           0 :         copy_len = mss + header_len - last_mbuf->data_len;
     845           0 :         header_len = 0;
     846           0 :         if (pktlen_to_copy > copy_len) {
     847           0 :             tail_addr = dpdk_pktmbuf_append(mbuf, last_mbuf, copy_len);
     848           0 :             if (unlikely(tail_addr == NULL))
     849           0 :                 return -1;
     850           0 :             rte_memcpy(tail_addr, append_addr, copy_len);
     851           0 :             pktlen_to_copy -= copy_len;
     852           0 :             append_addr += copy_len;
     853           0 :             new_mbuf = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     854           0 :             if (unlikely(new_mbuf == NULL)) {
     855             :                 RTE_LOG_DP(DEBUG, VROUTER, "%s: mbuf alloc failed\n",__func__);
     856           0 :                 return -1;
     857             :             }
     858           0 :             last_mbuf->next = new_mbuf;
     859           0 :             last_mbuf = new_mbuf;
     860           0 :             mbuf->nb_segs += 1;
     861             :         } else {
     862             :             /* for last segment */
     863           0 :             tail_addr = dpdk_pktmbuf_append(mbuf, last_mbuf, pktlen_to_copy);
     864           0 :             if (unlikely(tail_addr == NULL))
     865           0 :                 return -1;
     866           0 :             rte_memcpy(tail_addr, append_addr, pktlen_to_copy);
     867           0 :             pktlen_to_copy = 0;
     868             :         }
     869             :     }
     870           0 :     return 0;
     871             : }
     872             : 
     873             : /*
     874             :  * dpdk_virtio_create_chained_mbuf - Create a chained mbuf and copy the data pointed
     875             :  * to by pkt_addr of len pkt_len
     876             :  */
     877             : static int
     878           1 : dpdk_virtio_create_chained_mbuf(struct rte_mbuf *mbuf, char* pkt_addr, uint32_t pkt_len)
     879             : {
     880           1 :     char *tail_addr, *append_addr = pkt_addr;
     881           1 :     uint32_t append_len = pkt_len;
     882             :     struct rte_mbuf *new_mbuf;
     883             : 
     884           5 :     while((tail_addr = rte_pktmbuf_append(mbuf, append_len)) == NULL) {
     885           4 :         uint32_t pkt_tailroom = rte_pktmbuf_tailroom(rte_pktmbuf_lastseg(mbuf));
     886           4 :         tail_addr = rte_pktmbuf_append(mbuf, pkt_tailroom);
     887           4 :         if (unlikely(tail_addr == NULL))
     888           0 :             return -1;
     889           4 :         rte_memcpy(tail_addr, append_addr, pkt_tailroom);
     890           4 :         append_len -= pkt_tailroom;
     891           4 :         append_addr += pkt_tailroom;
     892           4 :         new_mbuf = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     893           4 :         if (unlikely(new_mbuf == NULL)) {
     894             :             RTE_LOG_DP(DEBUG, VROUTER, "%s: mbuf alloc failed\n",__func__);
     895           0 :             return -1;
     896             :         }
     897           4 :         rte_pktmbuf_lastseg(mbuf)->next = new_mbuf;
     898           4 :         mbuf->nb_segs += 1;
     899             :     }
     900           1 :     rte_memcpy(tail_addr, append_addr, append_len);
     901           1 :     return 0;
     902             : }
     903             : 
     904             : /*
     905             :  * dpdk_virtio_from_vm_rx - receive packets from a virtio client so that
     906             :  * the packets can be handed to vrouter for forwarding. the virtio client is
     907             :  * usually a VM.
     908             :  *
     909             :  * Returns the number of packets received from the virtio.
     910             :  */
     911             : static int
     912   957357717 : dpdk_virtio_from_vm_rx(void *port, struct rte_mbuf **pkts, uint32_t max_pkts)
     913             : {
     914   957357717 :     struct dpdk_virtio_reader *p = (struct dpdk_virtio_reader *)port;
     915   957357717 :     vr_dpdk_virtioq_t *vq = p->rx_virtioq;
     916             :     uint16_t vq_hard_avail_idx, i;
     917             :     uint16_t avail_pkts, next_desc_idx, next_avail_idx;
     918             :     struct vring_desc *desc;
     919             :     char *pkt_addr, *tail_addr;
     920             :     struct rte_mbuf *mbuf;
     921   957357717 :     uint32_t pkt_len, nb_pkts = 0;
     922             :     vr_uvh_client_t *vru_cl;
     923             : 
     924   957357717 :     if (unlikely(vq->vdv_ready_state == VQ_NOT_READY)) {
     925   885091655 :         DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p is not ready\n",
     926             :                 __func__, vq);
     927   882469014 :         return 0;
     928             :     }
     929             : 
     930    72266062 :     vru_cl = vr_dpdk_virtio_get_vif_client(vq->vdv_vif_idx);
     931    99307437 :     if (unlikely(vru_cl == NULL))
     932           0 :         return 0;
     933             : 
     934    99307437 :     vq_hard_avail_idx = (*((volatile uint16_t *)&vq->vdv_avail->idx));
     935             : 
     936             :     /* Unsigned subtraction gives the right result even with wrap around. */
     937    99307437 :     avail_pkts = vq_hard_avail_idx - vq->vdv_last_used_idx;
     938    99307437 :     avail_pkts = RTE_MIN(avail_pkts, max_pkts);
     939    99307437 :     if (unlikely(avail_pkts == 0)) {
     940    99323911 :         DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p has no packets\n",
     941             :                     __func__, vq);
     942    99340041 :         return 0;
     943             :     }
     944             : 
     945           0 :     DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p AVAILABLE %u packets\n",
     946             :             __func__, vq, avail_pkts);
     947         320 :     for (i = 0; i < avail_pkts; i++) {
     948         160 :         uint32_t header_len = 0;
     949             :         /* Allocate a mbuf. */
     950         160 :         mbuf = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     951         160 :         if (unlikely(mbuf == NULL)) {
     952           0 :             p->nb_nombufs++;
     953           0 :             DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p no_mbufs=%"PRIu64"\n",
     954             :                     __func__, vq, p->nb_nombufs);
     955           0 :             break;
     956             :         }
     957             : 
     958         160 :         next_avail_idx = (vq->vdv_last_used_idx + i) & (vq->vdv_size - 1);
     959         160 :         next_desc_idx = vq->vdv_avail->ring[next_avail_idx];
     960             :         /*
     961             :          * Move the (chain of) descriptors to the vdv_used list. The used
     962             :          * index will, however, only be updated at the end of the loop.
     963             :          */
     964         160 :         vq->vdv_used->ring[next_avail_idx].id = next_desc_idx;
     965         160 :         vq->vdv_used->ring[next_avail_idx].len = 0;
     966             : 
     967         160 :         desc = &vq->vdv_desc[next_desc_idx];
     968         160 :         pkt_len = desc->len;
     969         160 :         pkt_addr = vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
     970             :         /* Check the descriptor is sane. */
     971         160 :         if (unlikely(desc->len < vq->vdv_hlen ||
     972             :                 desc->addr == 0 || pkt_addr == NULL)) {
     973           0 :             goto free_mbuf;
     974             :         }
     975         160 :         mbuf->tso_segsz = 0;
     976             :         /* Now pkt_addr points to the virtio_net_hdr. */
     977         160 :         if (((struct virtio_net_hdr *)pkt_addr)->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
     978         160 :                 mbuf->ol_flags |= PKT_RX_IP_CKSUM_BAD;
     979         160 :         if (((struct virtio_net_hdr *)pkt_addr)->gso_type == VIRTIO_NET_HDR_GSO_TCPV4) {
     980           0 :                 mbuf->ol_flags |= PKT_RX_GSO_TCP4;
     981           0 :                 mbuf->tso_segsz = ((struct virtio_net_hdr *)pkt_addr)->gso_size;
     982         160 :         } else if (((struct virtio_net_hdr *)pkt_addr)->gso_type == VIRTIO_NET_HDR_GSO_TCPV6) {
     983           0 :                 mbuf->ol_flags |= PKT_RX_GSO_TCP6;
     984           0 :                 mbuf->tso_segsz = ((struct virtio_net_hdr *)pkt_addr)->gso_size;
     985             :         }
     986             : 
     987             :         /* Skip virtio_net_hdr  */
     988         160 :         if (likely(desc->flags & VRING_DESC_F_NEXT &&
     989             :                 pkt_len == vq->vdv_hlen)) {
     990           0 :             DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p pkt %u F_NEXT\n",
     991             :                 __func__, vq, i);
     992           0 :             desc = &vq->vdv_desc[desc->next];
     993           0 :             pkt_len = desc->len;
     994           0 :             pkt_addr = vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
     995             :         } else {
     996         160 :             DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p pkt %u no F_NEXT\n",
     997             :                 __func__, vq, i);
     998         160 :             pkt_addr += vq->vdv_hlen;
     999         160 :             pkt_len -= vq->vdv_hlen;
    1000             :         }
    1001             :         /* Now pkt_addr points to the packet data. */
    1002         160 :         if (mbuf->tso_segsz == 0) {
    1003         160 :             tail_addr = rte_pktmbuf_append(mbuf, pkt_len);
    1004             :             /* Check we ready to copy the data. */
    1005         160 :             if (unlikely(desc->addr == 0 || pkt_addr == NULL)) {
    1006           0 :                 goto free_mbuf;
    1007         160 :             } else if (unlikely(tail_addr == NULL)) {
    1008             :                 /* If insufficient tailroom, create a chained mbuf and copy the data */
    1009           1 :                 if (unlikely(dpdk_virtio_create_chained_mbuf(mbuf, pkt_addr, pkt_len) < 0)) {
    1010           0 :                     goto free_mbuf;
    1011             :                 }
    1012             :             } else {
    1013             :                 /* No chaining - Just Copy first descriptor data. */
    1014         159 :                 rte_memcpy(tail_addr, pkt_addr, pkt_len);
    1015             :             }
    1016             :         } else {
    1017           0 :             header_len = dpdk_virtio_get_ip_tcp_hdr_len(pkt_addr, pkt_len);
    1018           0 :             if (unlikely(dpdk_virtio_create_mss_sized_mbuf_chain(mbuf,
    1019             :                             mbuf->tso_segsz, pkt_addr, pkt_len, header_len) < 0)) {
    1020           0 :                 goto free_mbuf;
    1021             :             }
    1022             :         }
    1023             : 
    1024             :         /*
    1025             :          * Gather mbuf from several virtio buffers.
    1026             :          */
    1027         160 :         while (unlikely(desc->flags & VRING_DESC_F_NEXT)) {
    1028           0 :             desc = &vq->vdv_desc[desc->next];
    1029           0 :             pkt_len = desc->len;
    1030           0 :             pkt_addr = vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
    1031           0 :             if (mbuf->tso_segsz == 0) {
    1032           0 :                 tail_addr = rte_pktmbuf_append(mbuf, pkt_len);
    1033             :                 /* Check we ready to copy the data. */
    1034           0 :                 if (unlikely(desc->addr == 0 || pkt_addr == NULL)) {
    1035           0 :                     goto free_mbuf;
    1036           0 :                 } else if (unlikely(tail_addr == NULL)) {
    1037             :                     /* If insufficient tailroom, create a chained mbuf and copy the data */
    1038           0 :                     if (unlikely(dpdk_virtio_create_chained_mbuf(mbuf, pkt_addr, pkt_len) < 0)) {
    1039           0 :                         goto free_mbuf;
    1040             :                     }
    1041             :                 } else {
    1042             :                     /* No chaining - Just append next descriptor(s) data. */
    1043           0 :                     rte_memcpy(tail_addr, pkt_addr, pkt_len);
    1044             :                 }
    1045             :             } else {
    1046           0 :                 if (unlikely(dpdk_virtio_create_mss_sized_mbuf_chain(mbuf,
    1047             :                                 mbuf->tso_segsz, pkt_addr, pkt_len, header_len) < 0)) {
    1048           0 :                     goto free_mbuf;
    1049             :                 }
    1050             : 
    1051             :             }
    1052             :         }
    1053             : 
    1054         160 :         pkts[nb_pkts] = mbuf;
    1055         160 :         nb_pkts++;
    1056         160 :         continue;
    1057             : 
    1058           0 :     free_mbuf:
    1059           0 :         DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p DROP desc->addr %p "
    1060             :             "pkt_addr %p tail_addr %p len %d\n",
    1061             :             __func__, vq, desc->addr, pkt_addr, tail_addr, pkt_len);
    1062           0 :         DPDK_VIRTIO_READER_STATS_PKTS_DROP_ADD(p, 1);
    1063           0 :         rte_pktmbuf_free(mbuf);
    1064             :     }
    1065             : 
    1066             :     /*
    1067             :      * Do not call the guest if there are no descriptors processed.
    1068             :      *
    1069             :      * If there are no free mbufs on host, the TX queue in guest gets
    1070             :      * filled up. This makes the guest kernel to switch to interrupt mode
    1071             :      * and clear the VRING_AVAIL_F_NO_INTERRUPT flag.
    1072             :      *
    1073             :      * Meanwhile the host polls the virtio queue, sees the available
    1074             :      * descriptors and interrupts the guest. Those interrupts get unhandled by
    1075             :      * the guest virtio driver, so after 100K of the interrupts the IRQ get
    1076             :      * reported and disabled by the guest kernel.
    1077             :      */
    1078         160 :     if (likely(i > 0)) {
    1079         160 :         vq->vdv_last_used_idx += i;
    1080             :         rte_wmb();
    1081         160 :         vq->vdv_used->idx += i;
    1082             :         RTE_LOG_DP(DEBUG, VROUTER,
    1083             :                 "%s: vif %d vq %p vdv_last_used_idx %d vdv_used->idx %u vdv_avail->idx %u\n",
    1084             :                 __func__, vq->vdv_vif_idx, vq, vq->vdv_last_used_idx,
    1085             :                 vq->vdv_used->idx, vq->vdv_avail->idx);
    1086             : 
    1087             :         /* Call guest if required. */
    1088         160 :         if (unlikely(!(vq->vdv_avail->flags & VRING_AVAIL_F_NO_INTERRUPT))) {
    1089         160 :             p->nb_syscalls++;
    1090         160 :             eventfd_write(vq->vdv_callfd, 1);
    1091             :         }
    1092             :     }
    1093             : 
    1094         160 :     DPDK_UDEBUG(VROUTER, &vq->vdv_hash, "%s: queue %p RETURNS %u pkts\n",
    1095             :             __func__, vq, nb_pkts);
    1096             : 
    1097         160 :     DPDK_VIRTIO_READER_STATS_PKTS_IN_ADD(p, nb_pkts);
    1098             : 
    1099         160 :     return nb_pkts;
    1100             : }
    1101             : 
    1102             : #ifdef RTE_PORT_STATS_COLLECT
    1103             : 
    1104             : #define DPDK_VIRTIO_WRITER_STATS_PKTS_IN_ADD(port, val) \
    1105             :         port->stats.n_pkts_in += val
    1106             : #define DPDK_VIRTIO_WRITER_STATS_PKTS_DROP_ADD(port, val) \
    1107             :         port->stats.n_pkts_drop += val
    1108             : 
    1109             : #else
    1110             : 
    1111             : /* keep compiler happy, for unused variables */
    1112             : #define DPDK_VIRTIO_WRITER_STATS_PKTS_IN_ADD(port, val) \
    1113             :         (void)(val)
    1114             : #define DPDK_VIRTIO_WRITER_STATS_PKTS_DROP_ADD(port, val) \
    1115             :         (void)(val)
    1116             : 
    1117             : #endif
    1118             : 
    1119             : static inline int32_t __attribute__((always_inline))
    1120             : dpdk_virtio_dev_to_vm_tx_burst_simple(struct dpdk_virtio_writer *p,
    1121             :         vr_dpdk_virtioq_t *vq, uint16_t res_base_idx, uint16_t res_end_idx,
    1122             :         struct rte_mbuf **pkts, uint32_t count, uint8_t mrg_hdr)
    1123             : {
    1124             :     struct vring_desc *desc;
    1125             :     struct rte_mbuf *buff;
    1126             :     /* The virtio_hdr is initialised to 0. */
    1127          83 :     struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {{0, 0, 0, 0, 0, 0}, 1};
    1128          83 :     uint64_t buff_addr = 0;
    1129          83 :     uint64_t buff_hdr_addr = 0;
    1130             :     uint32_t head[VR_DPDK_VIRTIO_TX_BURST_SZ];
    1131          83 :     uint32_t head_idx, packet_success = 0;
    1132             :     uint16_t res_cur_idx;
    1133             :     uint8_t virtio_hdr_len;
    1134             :     vr_uvh_client_t *vru_cl;
    1135             : 
    1136          83 :     vru_cl = vr_dpdk_virtio_get_vif_client(vq->vdv_vif_idx);
    1137          83 :     if (unlikely(vru_cl == NULL))
    1138           0 :         return 0;
    1139             : 
    1140          83 :     res_cur_idx = res_base_idx;
    1141             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: Current Index %d| End Index %d\n",
    1142             :             __func__, res_cur_idx, res_end_idx);
    1143             : 
    1144             :     /* Prefetch available ring to retrieve indexes. */
    1145          83 :     rte_prefetch0(&vq->vdv_avail->ring[res_cur_idx & (vq->vdv_size - 1)]);
    1146             : 
    1147             :     /* Retrieve all of the head indexes first to avoid caching issues. */
    1148         166 :     for (head_idx = 0; head_idx < count; head_idx++)
    1149          83 :         head[head_idx] = vq->vdv_avail->ring[(res_cur_idx + head_idx) &
    1150          83 :                     (vq->vdv_size - 1)];
    1151             : 
    1152          83 :     virtio_hdr_len = (mrg_hdr)? sizeof(struct virtio_net_hdr_mrg_rxbuf):
    1153             :                                 sizeof(struct virtio_net_hdr);
    1154             : 
    1155             :     /* Prefetch descriptor index. */
    1156          83 :     rte_prefetch0(&vq->vdv_desc[head[packet_success]]);
    1157             : 
    1158         166 :     while (res_cur_idx != res_end_idx) {
    1159          83 :         uint32_t offset = 0, vb_offset = 0;
    1160          83 :         uint32_t pkt_len, len_to_cpy, data_len, total_copied = 0;
    1161          83 :         uint8_t hdr = 0, uncompleted_pkt = 0;
    1162             : 
    1163             :         /* Get descriptor from available ring */
    1164          83 :         desc = &vq->vdv_desc[head[packet_success]];
    1165             : 
    1166          83 :         buff = pkts[packet_success];
    1167             : 
    1168             :         /* Convert from gpa to vva (guest physical addr -> vhost virtual addr) */
    1169          83 :         buff_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
    1170             : 
    1171             :         /* Copy virtio_hdr to packet and increment buffer address */
    1172          83 :         buff_hdr_addr = buff_addr;
    1173             : 
    1174          83 :         if (unlikely(buff_addr == (uint64_t)NULL)) {
    1175             :             /* Retry with next descriptor */
    1176           0 :             uncompleted_pkt = 1;
    1177           0 :             goto next_descr;
    1178             :         }
    1179             : 
    1180             :         /* Prefetch buffer address. */
    1181          83 :         rte_prefetch0((void *)(uintptr_t)buff_addr);
    1182             : 
    1183             :         /*
    1184             :          * If the descriptors are chained the header and data are
    1185             :          * placed in separate buffers.
    1186             :          */
    1187          83 :         if (likely(desc->flags & VRING_DESC_F_NEXT)
    1188           0 :             && !mrg_hdr && (desc->len == sizeof(struct virtio_net_hdr))) {
    1189             :             /*
    1190             :              * TODO: verify that desc->next is sane below.
    1191             :              */
    1192           0 :             desc = &vq->vdv_desc[desc->next];
    1193             :             /* Buffer address translation. */
    1194           0 :             buff_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
    1195           0 :             if (unlikely(buff_addr == (uint64_t)NULL)) {
    1196             :                 /* Retry with next descriptor */
    1197           0 :                 uncompleted_pkt = 1;
    1198           0 :                 goto next_descr;
    1199             :             }
    1200             :         } else {
    1201          83 :             vb_offset += virtio_hdr_len;
    1202          83 :             hdr = 1;
    1203             :         }
    1204             : 
    1205          83 :         pkt_len = rte_pktmbuf_pkt_len(buff);
    1206          83 :         data_len = rte_pktmbuf_data_len(buff);
    1207          83 :         len_to_cpy = RTE_MIN(data_len,
    1208             :             hdr ? desc->len - virtio_hdr_len : desc->len);
    1209          87 :         while (total_copied < pkt_len) {
    1210             :             /* Copy mbuf data to buffer */
    1211          87 :             rte_memcpy((void *)(uintptr_t)(buff_addr + vb_offset),
    1212          87 :                 rte_pktmbuf_mtod_offset(buff, const void *, offset),
    1213             :                 len_to_cpy);
    1214             : 
    1215          87 :             offset += len_to_cpy;
    1216          87 :             vb_offset += len_to_cpy;
    1217          87 :             total_copied += len_to_cpy;
    1218             : 
    1219             :             /* The whole packet completes */
    1220          87 :             if (likely(total_copied == pkt_len))
    1221          83 :                 break;
    1222             : 
    1223             :             /* The current segment completes */
    1224           4 :             if (offset == data_len) {
    1225           4 :                 buff = buff->next;
    1226           4 :                 offset = 0;
    1227           4 :                 data_len = rte_pktmbuf_data_len(buff);
    1228             :             }
    1229             : 
    1230             :             /* The current vring descriptor done */
    1231           4 :             if (vb_offset == desc->len) {
    1232           0 :                 if (desc->flags & VRING_DESC_F_NEXT) {
    1233           0 :                     desc = &vq->vdv_desc[desc->next];
    1234           0 :                     buff_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl, desc->addr);
    1235           0 :                     if (unlikely(buff_addr == (uint64_t)NULL)) {
    1236             :                         /* Retry with next descriptor */
    1237           0 :                         uncompleted_pkt = 1;
    1238           0 :                         goto next_descr;
    1239             :                     }
    1240           0 :                     vb_offset = 0;
    1241             :                 } else {
    1242             :                     /* Room in vring buffer is not enough */
    1243           0 :                     uncompleted_pkt = 1;
    1244           0 :                     break;
    1245             :                 }
    1246             :             }
    1247           4 :             len_to_cpy = RTE_MIN(data_len - offset, desc->len - vb_offset);
    1248             :         };
    1249             : 
    1250           0 : next_descr:
    1251             :         /* Update used ring with desc information */
    1252          83 :         vq->vdv_used->ring[res_cur_idx & (vq->vdv_size - 1)].id =
    1253          83 :                             head[packet_success];
    1254             : 
    1255             :         /* Drop the packet if it is uncompleted */
    1256          83 :         if (unlikely(uncompleted_pkt == 1))
    1257           0 :             vq->vdv_used->ring[res_cur_idx & (vq->vdv_size - 1)].len =
    1258             :                            virtio_hdr_len;
    1259             :         else
    1260          83 :             vq->vdv_used->ring[res_cur_idx & (vq->vdv_size - 1)].len =
    1261          83 :                             pkt_len + virtio_hdr_len;
    1262             : 
    1263          83 :         res_cur_idx++;
    1264          83 :         packet_success++;
    1265             : 
    1266             :         /* TODO: in DPDK 2.1 we do not copy the header
    1267             :         if (unlikely(uncompleted_pkt == 1))
    1268             :             continue;
    1269             :         */
    1270          83 :         if (buff_hdr_addr) {
    1271          83 :             rte_memcpy((void *)(uintptr_t)buff_hdr_addr,
    1272             :                 (const void *)&virtio_hdr, virtio_hdr_len);
    1273             :         }
    1274             : 
    1275          83 :         if (likely(res_cur_idx < res_end_idx)) {
    1276             :             /* Prefetch descriptor index. */
    1277           0 :             rte_prefetch0(&vq->vdv_desc[head[packet_success]]);
    1278             :         }
    1279             :     }
    1280             : 
    1281          83 :     rte_compiler_barrier();
    1282             : 
    1283             :     /* Wait until it's our turn to add our buffer to the used ring. */
    1284          83 :     while (unlikely(vq->vdv_last_used_idx != res_base_idx))
    1285           0 :         rte_pause();
    1286             : 
    1287          83 :     *(volatile uint16_t *)&vq->vdv_used->idx += count;
    1288          83 :     vq->vdv_last_used_idx = res_end_idx;
    1289             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: vif %d vq %p last_used_idx %d used->idx %d\n",
    1290             :             __func__, vq->vdv_vif_idx, vq, vq->vdv_last_used_idx, vq->vdv_used->idx);
    1291             : 
    1292             :     /* flush used->idx update before we read avail->flags. */
    1293             :     rte_mb();
    1294             : 
    1295             :     /* Kick the guest if necessary. */
    1296          83 :     if (unlikely(!(vq->vdv_avail->flags & VRING_AVAIL_F_NO_INTERRUPT))) {
    1297          83 :         p->nb_syscalls++;
    1298          83 :         eventfd_write(vq->vdv_callfd, 1);
    1299             :     }
    1300          83 :     return count;
    1301             : }
    1302             : 
    1303             : /**
    1304             :  * This function adds buffers to the virtio devices RX virtqueue. Buffers can
    1305             :  * be received from the physical port or from another virtio device. A packet
    1306             :  * count is returned to indicate the number of packets that are succesfully
    1307             :  * added to the RX queue. This function works when mergeable is disabled.
    1308             :  *
    1309             :  * This is an adaptation of DPDK virtio_dev_rx() function.
    1310             :  * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
    1311             :  * BSD LICENSE
    1312             :  */
    1313             : static inline uint32_t __attribute__((always_inline))
    1314         105 : dpdk_virtio_dev_to_vm_tx_burst(struct dpdk_virtio_writer *p,
    1315             :         vr_dpdk_virtioq_t *vq, struct rte_mbuf **pkts, uint32_t count)
    1316             : {
    1317             :     uint16_t res_base_idx, res_end_idx, avail_idx, free_entries;
    1318         105 :     uint8_t success = 0;
    1319             : 
    1320         105 :     if (unlikely(vq->vdv_ready_state == VQ_NOT_READY))
    1321          22 :         return 0;
    1322             : 
    1323             :     /*
    1324             :      * As many data cores may want access to available buffers,
    1325             :      * they need to be reserved.
    1326             :      */
    1327             :     do {
    1328          83 :         res_base_idx = vq->vdv_last_used_idx_res;
    1329          83 :         avail_idx = *((volatile uint16_t *)&vq->vdv_avail->idx);
    1330             : 
    1331          83 :         free_entries = (avail_idx - res_base_idx);
    1332             :         /*check that we have enough buffers*/
    1333          83 :         if (unlikely(count > free_entries))
    1334           0 :             count = free_entries;
    1335             : 
    1336          83 :         if (unlikely(count == 0))
    1337           0 :             return 0;
    1338             : 
    1339          83 :         res_end_idx = res_base_idx + count;
    1340             :         /* vq->vdv_last_used_idx_res is atomically updated. */
    1341             :         /* TODO: Allow to disable cmpset if no concurrency in application. */
    1342          83 :         success = rte_atomic16_cmpset(&vq->vdv_last_used_idx_res,
    1343             :                 res_base_idx, res_end_idx);
    1344          83 :     } while (unlikely(success == 0));
    1345             : 
    1346         166 :     return dpdk_virtio_dev_to_vm_tx_burst_simple(p, vq,
    1347             :                    res_base_idx, res_end_idx,
    1348             :                    pkts, count, !VIRTIO_HDR_MRG_RXBUF);
    1349             : }
    1350             : 
    1351             : static inline uint32_t __attribute__((always_inline))
    1352             : copy_from_mbuf_to_vring(vr_dpdk_virtioq_t *vq, vr_uvh_client_t *vru_cl, uint16_t res_base_idx,
    1353             :     uint16_t res_end_idx, struct vq_buf_vector *buf_vec,
    1354             :     struct virtio_net_hdr_mrg_rxbuf* virtio_hdr,
    1355             :     struct rte_mbuf *pkt)
    1356             : {
    1357           0 :     uint32_t vec_idx = 0;
    1358           0 :     uint32_t entry_success = 0;
    1359           0 :     uint16_t cur_idx = res_base_idx;
    1360           0 :     uint64_t vb_addr = 0;
    1361           0 :     uint64_t vb_hdr_addr = 0;
    1362           0 :     uint32_t seg_offset = 0;
    1363           0 :     uint32_t vb_offset = 0;
    1364             :     uint32_t seg_avail;
    1365             :     uint32_t vb_avail;
    1366             :     uint32_t cpy_len, entry_len;
    1367             : 
    1368           0 :     if (pkt == NULL)
    1369           0 :         return 0;
    1370             : 
    1371             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: Current Index %d| "
    1372             :         "End Index %d\n",
    1373             :         __func__, cur_idx, res_end_idx);
    1374             : 
    1375             :     /*
    1376             :      * Convert from gpa to vva
    1377             :      * (guest physical addr -> vhost virtual addr)
    1378             :      */
    1379           0 :     vb_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl,
    1380           0 :                                                         buf_vec[vec_idx].buf_addr);
    1381           0 :     vb_hdr_addr = vb_addr;
    1382             : 
    1383             :     /* Prefetch buffer address. */
    1384           0 :     rte_prefetch0((void *)(uintptr_t)vb_addr);
    1385             : 
    1386             :     RTE_LOG_DP(DEBUG, VROUTER, "%s RX: Num merge buffers %d\n",
    1387             :         __func__, virtio_hdr->num_buffers);
    1388             : 
    1389           0 :     rte_memcpy((void *)(uintptr_t)vb_hdr_addr,
    1390           0 :         (const void *)virtio_hdr, vq->vdv_hlen);
    1391             : 
    1392           0 :     seg_avail = rte_pktmbuf_data_len(pkt);
    1393           0 :     vb_offset = vq->vdv_hlen;
    1394           0 :     vb_avail = buf_vec[vec_idx].buf_len - vq->vdv_hlen;
    1395             : 
    1396           0 :     entry_len = vq->vdv_hlen;
    1397             : 
    1398           0 :     if (vb_avail == 0) {
    1399           0 :         uint32_t desc_idx =
    1400           0 :             buf_vec[vec_idx].desc_idx;
    1401             : 
    1402           0 :         if ((vq->vdv_desc[desc_idx].flags
    1403           0 :             & VRING_DESC_F_NEXT) == 0) {
    1404             :             /* Update vdv_used ring with vdv_desc information */
    1405           0 :             vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].id
    1406           0 :                 = buf_vec[vec_idx].desc_idx;
    1407           0 :             vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].len
    1408           0 :                 = entry_len;
    1409             : 
    1410           0 :             entry_len = 0;
    1411           0 :             cur_idx++;
    1412           0 :             entry_success++;
    1413             :         }
    1414             : 
    1415           0 :         vec_idx++;
    1416           0 :         vb_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl,
    1417           0 :                                                           buf_vec[vec_idx].buf_addr);
    1418             : 
    1419             :         /* Prefetch buffer address. */
    1420           0 :         rte_prefetch0((void *)(uintptr_t)vb_addr);
    1421           0 :         vb_offset = 0;
    1422           0 :         vb_avail = buf_vec[vec_idx].buf_len;
    1423             :     }
    1424             : 
    1425           0 :     cpy_len = RTE_MIN(vb_avail, seg_avail);
    1426             : 
    1427           0 :     while (cpy_len > 0) {
    1428             :         /* Copy mbuf data to vring buffer */
    1429           0 :         rte_memcpy((void *)(uintptr_t)(vb_addr + vb_offset),
    1430           0 :             rte_pktmbuf_mtod_offset(pkt, const void *, seg_offset),
    1431             :             cpy_len);
    1432             : 
    1433           0 :         seg_offset += cpy_len;
    1434           0 :         vb_offset += cpy_len;
    1435           0 :         seg_avail -= cpy_len;
    1436           0 :         vb_avail -= cpy_len;
    1437           0 :         entry_len += cpy_len;
    1438             : 
    1439           0 :         if (seg_avail != 0) {
    1440             :             /*
    1441             :              * The virtio buffer in this vring
    1442             :              * entry reach to its end.
    1443             :              * But the segment doesn't complete.
    1444             :              */
    1445           0 :             if ((vq->vdv_desc[buf_vec[vec_idx].desc_idx].flags &
    1446             :                 VRING_DESC_F_NEXT) == 0) {
    1447             :                 /* Update vdv_used ring with vdv_desc information */
    1448           0 :                 vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].id
    1449           0 :                     = buf_vec[vec_idx].desc_idx;
    1450           0 :                 vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].len
    1451           0 :                     = entry_len;
    1452           0 :                 entry_len = 0;
    1453           0 :                 cur_idx++;
    1454           0 :                 entry_success++;
    1455             :             }
    1456             : 
    1457           0 :             vec_idx++;
    1458           0 :             vb_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl,
    1459           0 :                                                         buf_vec[vec_idx].buf_addr);
    1460           0 :             vb_offset = 0;
    1461           0 :             vb_avail = buf_vec[vec_idx].buf_len;
    1462           0 :             cpy_len = RTE_MIN(vb_avail, seg_avail);
    1463             :         } else {
    1464             :             /*
    1465             :              * This current segment complete, need continue to
    1466             :              * check if the whole packet complete or not.
    1467             :              */
    1468           0 :             pkt = pkt->next;
    1469           0 :             if (pkt != NULL) {
    1470             :                 /*
    1471             :                  * There are more segments.
    1472             :                  */
    1473           0 :                 if (vb_avail == 0) {
    1474             :                     /*
    1475             :                      * This current buffer from vring is
    1476             :                      * vdv_used up, need fetch next buffer
    1477             :                      * from buf_vec.
    1478             :                      */
    1479           0 :                     uint32_t desc_idx =
    1480           0 :                         buf_vec[vec_idx].desc_idx;
    1481             : 
    1482           0 :                     if ((vq->vdv_desc[desc_idx].flags &
    1483             :                         VRING_DESC_F_NEXT) == 0) {
    1484           0 :                         uint16_t wrapped_idx =
    1485           0 :                             cur_idx & (vq->vdv_size - 1);
    1486             :                         /*
    1487             :                          * Update vdv_used ring with the
    1488             :                          * descriptor information
    1489             :                          */
    1490           0 :                         vq->vdv_used->ring[wrapped_idx].id
    1491           0 :                             = desc_idx;
    1492           0 :                         vq->vdv_used->ring[wrapped_idx].len
    1493           0 :                             = entry_len;
    1494           0 :                         entry_success++;
    1495           0 :                         entry_len = 0;
    1496           0 :                         cur_idx++;
    1497             :                     }
    1498             : 
    1499             :                     /* Get next buffer from buf_vec. */
    1500           0 :                     vec_idx++;
    1501           0 :                     vb_addr = (uintptr_t)vr_dpdk_guest_phys_to_host_virt(vru_cl,
    1502           0 :                                                     buf_vec[vec_idx].buf_addr);
    1503           0 :                     vb_avail =
    1504           0 :                         buf_vec[vec_idx].buf_len;
    1505           0 :                     vb_offset = 0;
    1506             :                 }
    1507             : 
    1508           0 :                 seg_offset = 0;
    1509           0 :                 seg_avail = rte_pktmbuf_data_len(pkt);
    1510           0 :                 cpy_len = RTE_MIN(vb_avail, seg_avail);
    1511             :             } else {
    1512             :                 /*
    1513             :                  * This whole packet completes.
    1514             :                  */
    1515             :                 /* Update vdv_used ring with vdv_desc information */
    1516           0 :                 vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].id
    1517           0 :                     = buf_vec[vec_idx].desc_idx;
    1518           0 :                 vq->vdv_used->ring[cur_idx & (vq->vdv_size - 1)].len
    1519           0 :                     = entry_len;
    1520           0 :                 entry_success++;
    1521           0 :                 break;
    1522             :             }
    1523             :         }
    1524             :     }
    1525             : 
    1526           0 :     return entry_success;
    1527             : }
    1528             : 
    1529             : static inline void __attribute__((always_inline))
    1530             : update_secure_len(vr_dpdk_virtioq_t *vq, uint32_t id,
    1531             :     uint32_t *secure_len, struct vq_buf_vector *buf_vec, uint32_t *vec_idx)
    1532             : {
    1533           0 :     uint16_t wrapped_idx = id & (vq->vdv_size - 1);
    1534           0 :     uint32_t idx = vq->vdv_avail->ring[wrapped_idx];
    1535             :     uint8_t next_desc;
    1536           0 :     uint32_t len = *secure_len;
    1537           0 :     uint32_t vec_id = *vec_idx;
    1538             : 
    1539             :     do {
    1540           0 :         if (vec_id >= VR_BUF_VECTOR_MAX)
    1541           0 :             break;
    1542           0 :         next_desc = 0;
    1543           0 :         len += vq->vdv_desc[idx].len;
    1544           0 :         buf_vec[vec_id].buf_addr = vq->vdv_desc[idx].addr;
    1545           0 :         buf_vec[vec_id].buf_len = vq->vdv_desc[idx].len;
    1546           0 :         buf_vec[vec_id].desc_idx = idx;
    1547           0 :         vec_id++;
    1548             : 
    1549           0 :         if (vq->vdv_desc[idx].flags & VRING_DESC_F_NEXT) {
    1550           0 :             idx = vq->vdv_desc[idx].next;
    1551           0 :             next_desc = 1;
    1552             :         }
    1553           0 :     } while (next_desc);
    1554             : 
    1555           0 :     *secure_len = len;
    1556           0 :     *vec_idx = vec_id;
    1557           0 : }
    1558             : 
    1559             : static inline uint32_t __attribute__((always_inline))
    1560           0 : dpdk_virtio_dev_to_vm_tx_burst_mergeable(struct dpdk_virtio_writer *p,
    1561             :         vr_dpdk_virtioq_t *vq, struct rte_mbuf **pkts, uint32_t count)
    1562             : {
    1563           0 :     uint32_t pkt_idx = 0, start_idx = 0, entry_success = 0, simple_count;
    1564             :     uint16_t avail_idx;
    1565             :     uint16_t res_base_idx, res_cur_idx;
    1566           0 :     uint8_t success = 0;
    1567             :     vr_uvh_client_t *vru_cl;
    1568             :     struct vq_buf_vector buf_vec[VR_BUF_VECTOR_MAX];
    1569             : 
    1570           0 :     if (unlikely(vq->vdv_ready_state == VQ_NOT_READY))
    1571           0 :         return 0;
    1572             : 
    1573           0 :     vru_cl = vr_dpdk_virtio_get_vif_client(vq->vdv_vif_idx);
    1574           0 :     if (unlikely(vru_cl == NULL))
    1575           0 :         return 0;
    1576             : 
    1577           0 :     count = RTE_MIN((uint32_t)VR_DPDK_VIRTIO_TX_BURST_SZ, count);
    1578             : 
    1579           0 :     if (count == 0)
    1580           0 :         return 0;
    1581             : 
    1582             :     /* Check if we can call -
    1583             :      * dpdk_virtio_dev_to_vm_tx_burst_simple() for some/all pkts
    1584             :      */
    1585             :     do {
    1586           0 :         res_base_idx = vq->vdv_last_used_idx_res;
    1587           0 :         res_cur_idx = res_base_idx;
    1588           0 :         avail_idx = *((volatile uint16_t *)&vq->vdv_avail->idx);
    1589           0 :         for (pkt_idx = 0; pkt_idx < count; pkt_idx++) {
    1590           0 :             uint32_t pkt_len = pkts[pkt_idx]->pkt_len + vq->vdv_hlen;
    1591           0 :             if (unlikely(res_cur_idx == avail_idx)) {
    1592             :                 RTE_LOG_DP(DEBUG, VROUTER,
    1593             :                     "Failed "
    1594             :                     "to get enough vdv_desc from "
    1595             :                     "vring\n");
    1596           0 :                 count = pkt_idx;
    1597           0 :                 break;
    1598             :             } else {
    1599             :                 uint8_t next_desc;
    1600           0 :                 uint16_t wrapped_idx = res_cur_idx & (vq->vdv_size - 1);
    1601           0 :                 uint32_t len = 0, idx = vq->vdv_avail->ring[wrapped_idx];
    1602             :                 do {
    1603           0 :                     next_desc = 0;
    1604           0 :                     len += vq->vdv_desc[idx].len;
    1605           0 :                     if (vq->vdv_desc[idx].flags & VRING_DESC_F_NEXT) {
    1606           0 :                         idx = vq->vdv_desc[idx].next;
    1607           0 :                         next_desc = 1;
    1608             :                     }
    1609           0 :                     if (len > pkt_len)
    1610           0 :                         break;
    1611           0 :                 }while (next_desc);
    1612           0 :                 if (len < pkt_len)
    1613           0 :                     break;
    1614           0 :                 res_cur_idx++;
    1615             :             }
    1616             :         }
    1617             : 
    1618             :         /* If there are no packets to pass to
    1619             :          * dpdk_virtio_dev_to_vm_tx_burst_simple() function, break
    1620             :          */
    1621           0 :         if (pkt_idx == 0)
    1622           0 :             break;
    1623             : 
    1624           0 :         success = rte_atomic16_cmpset(&vq->vdv_last_used_idx_res,
    1625             :                 res_base_idx, res_cur_idx);
    1626           0 :     } while (unlikely(success == 0));
    1627             : 
    1628           0 :     if (pkt_idx) {
    1629           0 :         simple_count = dpdk_virtio_dev_to_vm_tx_burst_simple(p, vq,
    1630             :                                     res_base_idx, res_cur_idx,
    1631             :                                     pkts, pkt_idx, VIRTIO_HDR_MRG_RXBUF);
    1632           0 :         if (simple_count < pkt_idx)
    1633           0 :             return simple_count;
    1634             :     }
    1635             : 
    1636           0 :     start_idx = pkt_idx;
    1637           0 :     for (pkt_idx = start_idx; pkt_idx < count; pkt_idx++) {
    1638           0 :         struct virtio_net_hdr_mrg_rxbuf virtio_hdr = {
    1639             :             {0, 0, 0, 0, 0, 0}, 0};
    1640           0 :         uint32_t pkt_len = pkts[pkt_idx]->pkt_len + vq->vdv_hlen;
    1641             : 
    1642             :         do {
    1643             :             /*
    1644             :              * As many data cores may want access to available
    1645             :              * buffers, they need to be reserved.
    1646             :              */
    1647           0 :             uint32_t secure_len = 0;
    1648           0 :             uint32_t vec_idx = 0;
    1649             : 
    1650           0 :             res_base_idx = vq->vdv_last_used_idx_res;
    1651           0 :             res_cur_idx = res_base_idx;
    1652             : 
    1653             :             do {
    1654           0 :                 avail_idx = *((volatile uint16_t *)&vq->vdv_avail->idx);
    1655           0 :                 if (unlikely(res_cur_idx == avail_idx)) {
    1656             :                     RTE_LOG_DP(DEBUG, VROUTER,
    1657             :                         "Failed "
    1658             :                         "to get enough vdv_desc from "
    1659             :                         "vring\n");
    1660           0 :                     return pkt_idx;
    1661             :                 } else {
    1662           0 :                     update_secure_len(vq, res_cur_idx, &secure_len, buf_vec, &vec_idx);
    1663           0 :                     res_cur_idx++;
    1664             :                 }
    1665           0 :             } while (pkt_len > secure_len);
    1666             : 
    1667             :             /* vq->vdv_last_used_idx_res is atomically updated. */
    1668           0 :             success = rte_atomic16_cmpset(&vq->vdv_last_used_idx_res,
    1669             :                             res_base_idx,
    1670             :                             res_cur_idx);
    1671           0 :         } while (success == 0);
    1672             : 
    1673             :         /* Fill the virtio hdr */
    1674           0 :         virtio_hdr.num_buffers = res_cur_idx - res_base_idx;
    1675           0 :         if (pkts[pkt_idx]->ol_flags & PKT_RX_GSO_TCP4) {
    1676           0 :             virtio_hdr.hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
    1677           0 :             virtio_hdr.hdr.gso_size = pkts[pkt_idx]->tso_segsz;
    1678           0 :         } else if (pkts[pkt_idx]->ol_flags & PKT_RX_GSO_TCP6) {
    1679           0 :             virtio_hdr.hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
    1680           0 :             virtio_hdr.hdr.gso_size = pkts[pkt_idx]->tso_segsz;
    1681             :         }
    1682             : 
    1683           0 :         entry_success = copy_from_mbuf_to_vring(vq, vru_cl, res_base_idx,
    1684           0 :             res_cur_idx, buf_vec, &virtio_hdr, pkts[pkt_idx]);
    1685             : 
    1686           0 :         rte_compiler_barrier();
    1687             : 
    1688             :         /*
    1689             :          * Wait until it's our turn to add our buffer
    1690             :          * to the vdv_used ring.
    1691             :          */
    1692           0 :         while (unlikely(vq->vdv_last_used_idx != res_base_idx))
    1693           0 :             rte_pause();
    1694             : 
    1695           0 :         *(volatile uint16_t *)&vq->vdv_used->idx += entry_success;
    1696           0 :         vq->vdv_last_used_idx = res_cur_idx;
    1697             : 
    1698             :         /* flush vdv_used->idx update before we read vdv_avail->flags. */
    1699             :         rte_mb();
    1700             : 
    1701             :         /* Kick the guest if necessary. */
    1702           0 :         if (unlikely(!(vq->vdv_avail->flags & VRING_AVAIL_F_NO_INTERRUPT))) {
    1703           0 :             p->nb_syscalls++;
    1704           0 :             eventfd_write(vq->vdv_callfd, 1);
    1705             :         }
    1706             :     }
    1707             : 
    1708           0 :     return count;
    1709             : }
    1710             : 
    1711             : void
    1712           0 : vr_dpdk_set_vhost_send_func(unsigned int vif_idx, uint32_t mrg)
    1713             : {
    1714             :     int i;
    1715             :     vr_dpdk_virtioq_t *vq;
    1716             : 
    1717           0 :     if (vif_idx >= VR_MAX_INTERFACES) {
    1718           0 :         return;
    1719             :     }
    1720             : 
    1721           0 :     for (i = 0; i < VR_DPDK_VIRTIO_MAX_QUEUES*2; i++) {
    1722           0 :         if (i & 1) {
    1723           0 :             vq = &vr_dpdk_virtio_rxqs[vif_idx][i/2];
    1724             :         } else {
    1725           0 :             vq = &vr_dpdk_virtio_txqs[vif_idx][i/2];
    1726             :         }
    1727             : 
    1728           0 :         if (mrg) {
    1729           0 :             vq->vdv_send_func = dpdk_virtio_dev_to_vm_tx_burst_mergeable;
    1730           0 :             vq->vdv_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
    1731             :         } else {
    1732           0 :             vq->vdv_send_func = dpdk_virtio_dev_to_vm_tx_burst;
    1733           0 :             vq->vdv_hlen = sizeof(struct virtio_net_hdr);
    1734             :         }
    1735             :     }
    1736             : }
    1737             : 
    1738             : static inline void
    1739         130 : dpdk_virtio_send_burst(struct dpdk_virtio_writer *p)
    1740             : {
    1741         130 :     uint32_t nb_tx = 0;
    1742             :     int i;
    1743             : 
    1744         130 :     if (likely(p->tx_buf_count)) {
    1745             :         /*
    1746             :          * prefetch the tx buffer to be sent
    1747             :          * This will avoid large cpu cycles in the
    1748             :          * dpdk_virtio_dev_to_vm_tx_burst_mergeable()
    1749             :          */
    1750         266 :         for (i=0;i<p->tx_buf_count;i++)
    1751         136 :             rte_prefetch0((void *)p->tx_buf[i]);
    1752         130 :         if (likely(p->tx_virtioq->vdv_send_func != NULL)) {
    1753         105 :             nb_tx = p->tx_virtioq->vdv_send_func(p, p->tx_virtioq,
    1754         105 :                             p->tx_buf, p->tx_buf_count);
    1755             :         }
    1756             : 
    1757         130 :         DPDK_VIRTIO_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
    1758             :         /* dpdk_virtio_dev_to_vm_tx_burst() does not free any mbufs */
    1759         266 :         while (likely(p->tx_buf_count)) {
    1760         136 :             p->tx_buf_count--;
    1761         136 :             p->tx_mbufs -= p->tx_buf[p->tx_buf_count]->nb_segs;
    1762         136 :             rte_pktmbuf_free(p->tx_buf[p->tx_buf_count]);
    1763             :         }
    1764             :     }
    1765         130 : }
    1766             : 
    1767             : /*
    1768             :  * dpdk_virtio_to_vm_tx - sends a packet from vrouter to a virtio client. The
    1769             :  * virtio client is usually a VM.
    1770             :  *
    1771             :  * Returns nothing.
    1772             :  */
    1773             : static int
    1774         136 : dpdk_virtio_to_vm_tx(void *port, struct rte_mbuf *pkt)
    1775             : {
    1776         136 :     struct dpdk_virtio_writer *p = (struct dpdk_virtio_writer *)port;
    1777         136 :     const unsigned lcore_id = rte_lcore_id();
    1778         136 :     struct vr_dpdk_lcore *lcore = NULL;
    1779             : 
    1780         136 :     if (lcore_id >= VR_DPDK_FWD_LCORE_ID) {
    1781         134 :         lcore = vr_dpdk.lcores[lcore_id];
    1782         134 :         p->last_pkt_tx = lcore->lcore_fwd_loops;
    1783             :     }
    1784             : 
    1785         136 :     p->tx_buf[p->tx_buf_count++] = pkt;
    1786         136 :     p->tx_mbufs += pkt->nb_segs;
    1787         136 :     DPDK_VIRTIO_WRITER_STATS_PKTS_IN_ADD(p, 1);
    1788             : 
    1789         136 :     if (unlikely(p->tx_mbufs >= VR_DPDK_VIRTIO_TX_BURST_SZ)) {
    1790           0 :         dpdk_virtio_send_burst(p);
    1791           0 :         if (lcore) {
    1792           0 :             p->last_pkt_tx_flush = lcore->lcore_fwd_loops;
    1793             :         }
    1794             :     }
    1795             : 
    1796         136 :     return 0;
    1797             : }
    1798             : 
    1799             : /*
    1800             :  * dpdk_virtio_to_vm_flush - flushes packets from vrouter to a virtio client.
    1801             :  * The virtio client is usually a VM.
    1802             :  *
    1803             :  * Returns nothing.
    1804             :  */
    1805             : static int
    1806   172717844 : dpdk_virtio_to_vm_flush(void *port)
    1807             : {
    1808   172717844 :     struct dpdk_virtio_writer *p = (struct dpdk_virtio_writer *)port;
    1809             :     unsigned lcore_id;
    1810   172717844 :     struct vr_dpdk_lcore *lcore = NULL;
    1811             : 
    1812   172717844 :     if (p->tx_buf_count == 0) {
    1813   172710853 :         return 0;
    1814             :     }
    1815             : 
    1816        6991 :     lcore_id = rte_lcore_id();
    1817         130 :     if (lcore_id >= VR_DPDK_FWD_LCORE_ID) {
    1818         128 :         lcore = vr_dpdk.lcores[lcore_id];
    1819             :     }
    1820             : 
    1821         130 :     if (lcore) {
    1822             :         /*
    1823             :          * Flush the TX queue if it has been a while since it was last done OR
    1824             :          * if there are packets in the queue and no packets have been enqueued
    1825             :          * for a short while. The latter condition helps to reduce latency in
    1826             :          * case there isn't a lot of traffic on the queue.
    1827             :          */
    1828         128 :         if ((lcore->lcore_fwd_loops - p->last_pkt_tx_flush) <
    1829             :                     VR_DPDK_TX_FLUSH_LOOPS) {
    1830           0 :             if ((lcore->lcore_fwd_loops - p->last_pkt_tx) <
    1831             :                     VR_DPDK_TX_IDLE_LOOPS) {
    1832           0 :                 return 0;
    1833             :             }
    1834             :         }
    1835             :     }
    1836             : 
    1837         130 :     dpdk_virtio_send_burst(p);
    1838         130 :     if (lcore) {
    1839         128 :         p->last_pkt_tx_flush = lcore->lcore_fwd_loops;
    1840             :     }
    1841             : 
    1842         130 :     return 0;
    1843             : }
    1844             : 
    1845             : /*
    1846             :  * vr_dpdk_virtio_set_vring_base - sets the vring base using data sent by
    1847             :  * vhost client.
    1848             :  *
    1849             :  * Returns 0 on success, -1 otherwise.
    1850             :  */
    1851             : int
    1852         388 : vr_dpdk_virtio_set_vring_base(unsigned int vif_idx, unsigned int vring_idx,
    1853             :                                unsigned int vring_base)
    1854             : {
    1855             :     vr_dpdk_virtioq_t *vq;
    1856             : 
    1857         388 :     if ((vif_idx >= VR_MAX_INTERFACES)
    1858         388 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    1859           0 :         return -1;
    1860             :     }
    1861             : 
    1862             :     /*
    1863             :      * RX rings are even numbered and TX rings are odd numbered from the
    1864             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    1865             :      * vrouter's RX ring and vice versa.
    1866             :      */
    1867         388 :     if (vring_idx & 1) {
    1868         194 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    1869             :     } else {
    1870         194 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    1871             :     }
    1872             : 
    1873         388 :     vq->vdv_last_used_idx = vring_base;
    1874         388 :     vq->vdv_last_used_idx_res = vring_base;
    1875         388 :     return 0;
    1876             : }
    1877             : 
    1878             : /*
    1879             :  * vr_dpdk_virtio_get_vring_base - gets the vring base for the specified vring
    1880             :  * sent by the vhost client.
    1881             :  *
    1882             :  * Returns 0 on success, -1 otherwise.
    1883             :  */
    1884             : int
    1885           0 : vr_dpdk_virtio_get_vring_base(unsigned int vif_idx, unsigned int vring_idx,
    1886             :                                unsigned int *vring_basep)
    1887             : {
    1888             :     vr_dpdk_virtioq_t *vq;
    1889             : 
    1890           0 :     if ((vif_idx >= VR_MAX_INTERFACES)
    1891           0 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    1892           0 :         return -1;
    1893             :     }
    1894             : 
    1895             :     /*
    1896             :      * RX rings are even numbered and TX rings are odd numbered from the
    1897             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    1898             :      * vrouter's RX ring and vice versa.
    1899             :      */
    1900           0 :     if (vring_idx & 1) {
    1901           0 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    1902             :     } else {
    1903           0 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    1904             :     }
    1905             : 
    1906           0 :     *vring_basep = vq->vdv_last_used_idx;
    1907             : 
    1908             :     /*
    1909             :      * This is usually called when qemu shuts down a virtio queue. Set the
    1910             :      * state to indicate that this queue should not be used any more.
    1911             :      */
    1912           0 :     vq->vdv_ready_state = VQ_NOT_READY;
    1913             :     rte_wmb();
    1914           0 :     synchronize_rcu();
    1915             : 
    1916             :     /* Reset the queue. We reset only those values we analyze in
    1917             :      * uvhm_check_vring_ready()
    1918             :      */
    1919           0 :     vq->vdv_desc = NULL;
    1920           0 :     if (vq->vdv_callfd) {
    1921           0 :         close(vq->vdv_callfd);
    1922           0 :         vq->vdv_callfd = 0;
    1923             :     }
    1924             : 
    1925           0 :     return 0;
    1926             : }
    1927             : 
    1928             : /*
    1929             :  * vr_dpdk_virtio_recover_vring_base - recovers the vring base from the shared
    1930             :  * memory after vRouter crash.
    1931             :  *
    1932             :  * Returns 0 on success, -1 otherwise.
    1933             :  */
    1934             : int
    1935         388 : vr_dpdk_virtio_recover_vring_base(unsigned int vif_idx, unsigned int vring_idx)
    1936             : {
    1937             :     vr_dpdk_virtioq_t *vq;
    1938             : 
    1939         388 :     if ((vif_idx >= VR_MAX_INTERFACES)
    1940         388 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    1941           0 :         return -1;
    1942             :     }
    1943             : 
    1944         388 :     if (vring_idx & 1) {
    1945         194 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    1946             :     } else {
    1947         194 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    1948             :     }
    1949             : 
    1950         388 :     if (vq->vdv_used) {
    1951             :         /* Reading base index from the shared memory. */
    1952         388 :         if (vq->vdv_last_used_idx != vq->vdv_used->idx) {
    1953           0 :             RTE_LOG(INFO, UVHOST, "    recovering vring base %d -> %d\n",
    1954             :                     vq->vdv_last_used_idx, vq->vdv_used->idx);
    1955           0 :             vr_dpdk_virtio_set_vring_base(vif_idx, vring_idx, vq->vdv_used->idx);
    1956             :         }
    1957             :     }
    1958             : 
    1959         388 :     return 0;
    1960             : }
    1961             : 
    1962             : /*
    1963             :  * vr_dpdk_set_vring_addr - Sets the address of the virtio descriptor and
    1964             :  * available/used rings based on messages sent by the vhost client.
    1965             :  *
    1966             :  * Returns 0 on success, -1 otherwise.
    1967             :  */
    1968             : int
    1969         388 : vr_dpdk_set_vring_addr(unsigned int vif_idx, unsigned int vring_idx,
    1970             :                        struct vring_desc *vrucv_desc,
    1971             :                        struct vring_avail *vrucv_avail,
    1972             :                        struct vring_used *vrucv_used)
    1973             : {
    1974             :     vr_dpdk_virtioq_t *vq;
    1975             : 
    1976         388 :     if ((vif_idx >= VR_MAX_INTERFACES)
    1977         388 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    1978           0 :         return -1;
    1979             :     }
    1980             : 
    1981             :     /*
    1982             :      * RX rings are even numbered and TX rings are odd numbered from the
    1983             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    1984             :      * vrouter's RX ring and vice versa.
    1985             :      */
    1986         388 :     if (vring_idx & 1) {
    1987         194 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    1988             :     } else {
    1989         194 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    1990             :     }
    1991             : 
    1992         388 :     vq->vdv_desc = vrucv_desc;
    1993         388 :     vq->vdv_avail = vrucv_avail;
    1994         388 :     vq->vdv_used = vrucv_used;
    1995             : 
    1996             :     /*
    1997             :      * Tell the guest that it need not interrupt vrouter when it updates the
    1998             :      * available ring (as vrouter is polling it).
    1999             :      */
    2000         388 :     vq->vdv_used->flags |= VRING_USED_F_NO_NOTIFY;
    2001             : 
    2002         388 :     return 0;
    2003             : }
    2004             : 
    2005             : /*
    2006             :  * vr_dpdk_set_ring_num_desc - sets the number of descriptors in a vring
    2007             :  * based on messages from the vhost client.
    2008             :  *
    2009             :  * Returns 0 on success, -1 otherwise.
    2010             :  */
    2011             : int
    2012         388 : vr_dpdk_set_ring_num_desc(unsigned int vif_idx, unsigned int vring_idx,
    2013             :                           unsigned int num_desc)
    2014             : {
    2015             :     vr_dpdk_virtioq_t *vq;
    2016             : 
    2017         388 :     if ((vif_idx >= VR_MAX_INTERFACES) || (vring_idx > 2 * VR_DPDK_VIRTIO_MAX_QUEUES)) {
    2018           0 :         return -1;
    2019             :     }
    2020             : 
    2021             :     /*
    2022             :      * RX rings are even numbered and TX rings are odd numbered from the
    2023             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    2024             :      * vrouter's RX ring and vice versa.
    2025             :      */
    2026         388 :     if (vring_idx & 1) {
    2027         194 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    2028             :     } else {
    2029         194 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    2030             :     }
    2031             : 
    2032         388 :     vq->vdv_size = num_desc;
    2033             : 
    2034         388 :     return 0;
    2035             : }
    2036             : 
    2037             : /*
    2038             :  * vr_dpdk_set_ring_callfd - set the eventd used to raise interrupts in
    2039             :  * the guest (if required). Returns 0 on success, -1 otherwise.
    2040             :  */
    2041             : int
    2042         388 : vr_dpdk_set_ring_callfd(unsigned int vif_idx, unsigned int vring_idx,
    2043             :                         int callfd)
    2044             : {
    2045             :     vr_dpdk_virtioq_t *vq;
    2046             : 
    2047         388 :     if ((vif_idx >= VR_MAX_INTERFACES)
    2048         388 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    2049           0 :         return -1;
    2050             :     }
    2051             : 
    2052             :     /*
    2053             :      * RX rings are even numbered and TX rings are odd numbered from the
    2054             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    2055             :      * vrouter's RX ring and vice versa.
    2056             :      */
    2057         388 :     if (vring_idx & 1) {
    2058         194 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    2059             :     } else {
    2060         194 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    2061             :     }
    2062             : 
    2063         388 :     if (vq->vdv_callfd > 0) {
    2064           0 :         close(vq->vdv_callfd);
    2065             :     }
    2066         388 :     vq->vdv_callfd = callfd;
    2067             : 
    2068         388 :     return 0;
    2069             : }
    2070             : 
    2071             : /*
    2072             :  * vr_dpdk_set_virtq_ready - sets the virtio queue ready state to indicate
    2073             :  * whether forwarding can start on the virtio queue or not.
    2074             :  *
    2075             :  * Returns 0 on success, -1 otherwise.
    2076             :  */
    2077             : int
    2078         776 : vr_dpdk_set_virtq_ready(unsigned int vif_idx, unsigned int vring_idx,
    2079             :                         vq_ready_state_t ready)
    2080             : {
    2081             :     vr_dpdk_virtioq_t *vq;
    2082             : 
    2083         776 :     if ((vif_idx >= VR_MAX_INTERFACES)
    2084         776 :         || (vring_idx >= (2 * VR_DPDK_VIRTIO_MAX_QUEUES))) {
    2085           0 :         return -1;
    2086             :     }
    2087             : 
    2088             :     /*
    2089             :      * RX rings are even numbered and TX rings are odd numbered from the
    2090             :      * VM's point of view. From vrouter's point of view, VM's TX ring is
    2091             :      * vrouter's RX ring and vice versa.
    2092             :      */
    2093         776 :     if (vring_idx & 1) {
    2094         388 :         vq = &vr_dpdk_virtio_rxqs[vif_idx][vring_idx/2];
    2095             :     } else {
    2096         388 :         vq = &vr_dpdk_virtio_txqs[vif_idx][vring_idx/2];
    2097             :     }
    2098             : 
    2099         776 :     if (vq->vdv_hlen == 0) {
    2100             :         struct vr_interface *vif;
    2101         266 :         vif = __vrouter_get_interface(vrouter_get(0), vq->vdv_vif_idx);
    2102         266 :         if (vif && (vif->vif_flags & VIF_FLAG_MRG_RXBUF)) {
    2103           0 :             vq->vdv_send_func = dpdk_virtio_dev_to_vm_tx_burst_mergeable;
    2104           0 :             vq->vdv_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
    2105             :         } else {
    2106         266 :             vq->vdv_send_func = dpdk_virtio_dev_to_vm_tx_burst;
    2107         266 :             vq->vdv_hlen = sizeof(struct virtio_net_hdr);
    2108             :         }
    2109             :     }
    2110             : 
    2111         776 :     vq->vdv_ready_state = ready;
    2112             : 
    2113         776 :     return 0;
    2114             : }
    2115             : 
    2116             : /*
    2117             :  * vr_dpdk_virtio_set_vif_client - sets a pointer to per vif state. Currently
    2118             :  * used to store a pointer to the vhost client structure.
    2119             :  *
    2120             :  * Returns nothing.
    2121             :  */
    2122             : void
    2123         401 : vr_dpdk_virtio_set_vif_client(unsigned int idx, void *client)
    2124             : {
    2125         401 :     if (idx >= VR_MAX_INTERFACES) {
    2126           0 :         return;
    2127             :     }
    2128             : 
    2129         401 :     vr_dpdk_vif_clients[idx] = client;
    2130             : 
    2131         401 :     return;
    2132             : }
    2133             : 
    2134             : /*
    2135             :  * vr_dpdk_virtio_get_vif_client - returns a pointer to per vif state if it
    2136             :  * exists, NULL otherwise.
    2137             :  */
    2138             : void *
    2139    99405963 : vr_dpdk_virtio_get_vif_client(unsigned int idx)
    2140             : {
    2141    99405963 :     if (idx >= VR_MAX_INTERFACES) {
    2142           0 :         return NULL;
    2143             :     }
    2144             : 
    2145    99405963 :     return vr_dpdk_vif_clients[idx];
    2146             : }
    2147             : 
    2148             : static int
    2149         336 : dpdk_virtio_reader_stats_read(void *port,
    2150             :     struct rte_port_in_stats *stats, int clear)
    2151             : {
    2152         336 :     struct dpdk_virtio_reader *p = (struct dpdk_virtio_reader *)port;
    2153             : 
    2154         336 :     if (stats != NULL)
    2155         336 :         memcpy(stats, &p->stats, sizeof(p->stats));
    2156             : 
    2157         336 :     if (clear)
    2158          20 :         memset(&p->stats, 0, sizeof(p->stats));
    2159             : 
    2160         336 :     return 0;
    2161             : }
    2162             : 
    2163             : static int
    2164         672 : dpdk_virtio_writer_stats_read(void *port,
    2165             :     struct rte_port_out_stats *stats, int clear)
    2166             : {
    2167         672 :     struct dpdk_virtio_reader *p = (struct dpdk_virtio_reader *)port;
    2168             : 
    2169         672 :     if (stats != NULL)
    2170         672 :         memcpy(stats, &p->stats, sizeof(p->stats));
    2171             : 
    2172         672 :     if (clear)
    2173          40 :         memset(&p->stats, 0, sizeof(p->stats));
    2174             : 
    2175         672 :     return 0;
    2176             : }
    2177             : 
    2178             : /* Update extra statistics for virtio queue */
    2179             : void
    2180         948 : vr_dpdk_virtio_xstats_update(struct vr_interface_stats *stats,
    2181             :     struct vr_dpdk_queue *queue)
    2182             : {
    2183             :     struct dpdk_virtio_reader *reader;
    2184             :     struct dpdk_virtio_writer *writer;
    2185             : 
    2186         948 :     if (queue->rxq_ops.f_rx == vr_dpdk_virtio_reader_ops.f_rx) {
    2187         316 :         reader = (struct dpdk_virtio_reader *)queue->q_queue_h;
    2188         316 :         stats->vis_port_isyscalls = reader->nb_syscalls;
    2189         316 :         stats->vis_port_inombufs = reader->nb_nombufs;
    2190         632 :     } else if (queue->txq_ops.f_tx == vr_dpdk_virtio_writer_ops.f_tx) {
    2191         632 :         writer = (struct dpdk_virtio_writer *)queue->q_queue_h;
    2192         632 :         stats->vis_port_osyscalls = writer->nb_syscalls;
    2193             :     }
    2194         948 : }

Generated by: LCOV version 1.14