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

Generated by: LCOV version 1.14