LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_dpdk_ethdev.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 82 498 16.5 %
Date: 2026-08-03 02:19:58 Functions: 3 22 13.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2014 Semihalf.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU General Public License as
       6             :  * published by the Free Software Foundation version 2.
       7             :  *
       8             :  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
       9             :  * kind, whether express or implied; without even the implied warranty
      10             :  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      11             :  * GNU General Public License for more details.
      12             :  *
      13             :  * vr_dpdk_ethdev.c -- DPDK ethernet device
      14             :  *
      15             :  */
      16             : 
      17             : #include "vr_dpdk.h"
      18             : #include "vr_dpdk_usocket.h"
      19             : 
      20             : #include <vr_mpls.h>
      21             : 
      22             : #include <rte_eth_bond.h>
      23             : #include <rte_errno.h>
      24             : #include <rte_ethdev_pci.h>
      25             : #include <rte_ethdev.h>
      26             : #include <rte_hash_crc.h>
      27             : #include <rte_ip.h>
      28             : #include <rte_port_ethdev.h>
      29             : #include <rte_udp.h>
      30             : #include <linux/netlink.h>
      31             : #include <linux/rtnetlink.h>
      32             : 
      33             : extern int vr_rxd_sz, vr_txd_sz;
      34             : extern unsigned int datapath_offloads;
      35             : unsigned int vr_dpdk_master_port_id;
      36             : extern bool vr_no_load_balance;
      37             : 
      38             : struct rte_eth_conf ethdev_conf = {
      39             :     .link_speeds = ETH_LINK_SPEED_AUTONEG,
      40             :     .rxmode = { /* Port RX configuration. */
      41             :         /* The multi-queue packet distribution mode to be used, e.g. RSS. */
      42             :         .mq_mode            = ETH_MQ_RX_RSS,
      43             :         .max_rx_pkt_len     = VR_DEF_MAX_PACKET_SZ, /* Only used if jumbo_frame enabled */
      44             :         .offloads           = DEV_RX_OFFLOAD_CHECKSUM | DEV_RX_OFFLOAD_JUMBO_FRAME,
      45             :     },
      46             :     .rx_adv_conf = {
      47             :         .rss_conf = { /* Port RSS configuration */
      48             :             .rss_key            = NULL, /* If not NULL, 40-byte hash key */
      49             :             .rss_key_len        = 0,    /* Hash key length in bytes */
      50             :             /* Hash functions to apply */
      51             :             .rss_hf             = ETH_RSS_IP | ETH_RSS_UDP | ETH_RSS_TCP,
      52             :         },
      53             :     },
      54             :     .txmode = { /* Port TX configuration. */
      55             :         .mq_mode            = ETH_MQ_TX_NONE, /* TX multi-queues mode */
      56             :         /* For i40e specifically */
      57             :         .pvid               = 0,
      58             :         .hw_vlan_reject_tagged      = 0, /* If set, reject sending out tagged pkts */
      59             :         .hw_vlan_reject_untagged    = 0, /* If set, reject sending out untagged pkts */
      60             :         .hw_vlan_insert_pvid        = 0, /* If set, enable port based VLAN insertion */
      61             :     },
      62             :     .fdir_conf = {
      63             : #if VR_DPDK_USE_HW_FILTERING
      64             :         .mode = RTE_FDIR_MODE_PERFECT,          /* Flow Director mode. */
      65             :         .status = RTE_FDIR_REPORT_STATUS,       /* How to report FDIR hash. */
      66             : #else
      67             :         .mode = RTE_FDIR_MODE_NONE,
      68             :         .status = RTE_FDIR_NO_REPORT_STATUS,
      69             : #endif
      70             :         .pballoc = RTE_FDIR_PBALLOC_64K,        /* Space for FDIR filters. */
      71             :         /* RX queue of packets matching a "drop" filter in perfect mode. */
      72             :         .drop_queue = 0,
      73             :         .flex_conf = {
      74             :         },
      75             :     },
      76             :     .intr_conf = {
      77             :         .lsc = 1, /* Enable Link status interrupts */
      78             :     },
      79             : };
      80             : 
      81             : /* RX and TX Prefetch, Host, and Write-back threshold values should be
      82             :  * carefully set for optimal performance. Consult the network
      83             :  * controller's datasheet and supporting DPDK documentation for guidance
      84             :  * on how these parameters should be set.
      85             :  */
      86             : /* RX ring configuration */
      87             : static const struct rte_eth_rxconf default_rx_queue_conf = {
      88             :     .rx_thresh = {
      89             :         .pthresh = 8,   /* Ring prefetch threshold */
      90             :         .hthresh = 8,   /* Ring host threshold */
      91             :         .wthresh = 4,   /* Ring writeback threshold */
      92             :     },
      93             :     /* Do not immediately free RX descriptors */
      94             :     .rx_free_thresh = VR_DPDK_RX_BURST_SZ,
      95             :     .offloads           = DEV_RX_OFFLOAD_CHECKSUM | DEV_RX_OFFLOAD_JUMBO_FRAME,
      96             : };
      97             : 
      98             : /*
      99             :  * These default values are optimized for use with the Intel(R) 82599 10 GbE
     100             :  * Controller and the DPDK ixgbe PMD. Consider using other values for other
     101             :  * network controllers and/or network drivers.
     102             :  */
     103             : /* TX ring configuration */
     104             : static const struct rte_eth_txconf default_tx_queue_conf = {
     105             :     .tx_thresh = {
     106             :         .pthresh = 32,  /* Ring prefetch threshold */
     107             :         .hthresh = 0,   /* Ring host threshold */
     108             :         .wthresh = 0,   /* Ring writeback threshold */
     109             :     },
     110             :     .offloads  = DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | DEV_TX_OFFLOAD_IPV4_CKSUM,
     111             :     .tx_free_thresh = 32,
     112             :     .tx_rs_thresh = 32,      /* Use PMD default values */
     113             : };
     114             : 
     115             : #if VR_DPDK_USE_HW_FILTERING
     116             : /* Add hardware filter */
     117             : int
     118             : vr_dpdk_ethdev_filter_add(struct vr_interface *vif, uint16_t queue_id,
     119             :     unsigned dst_ip, unsigned mpls_label)
     120             : {
     121             :     struct vr_dpdk_ethdev *ethdev = (struct vr_dpdk_ethdev *)vif->vif_os;
     122             :     uint8_t port_id = ethdev->ethdev_port_id;
     123             :     struct rte_fdir_filter filter;
     124             :     int ret;
     125             : 
     126             :     /* accept 2-byte labels only */
     127             :     if (mpls_label > 0xffff)
     128             :         return -EINVAL;
     129             : 
     130             :     if (queue_id > VR_DPDK_MAX_NB_RX_QUEUES)
     131             :         return -EINVAL;
     132             : 
     133             :     memset(&filter, 0, sizeof(filter));
     134             :     filter.iptype = RTE_FDIR_IPTYPE_IPV4;
     135             :     filter.l4type = RTE_FDIR_L4TYPE_UDP;
     136             :     filter.ip_dst.ipv4_addr = dst_ip;
     137             :     filter.port_dst = rte_cpu_to_be_16((uint16_t)VR_MPLS_OVER_UDP_DST_PORT);
     138             :     filter.flex_bytes = rte_cpu_to_be_16((uint16_t)mpls_label);
     139             : 
     140             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: ip_dst=0x%x port_dst=%d flex_bytes=%d\n", __func__,
     141             :         (unsigned)dst_ip, (unsigned)VR_MPLS_OVER_UDP_DST_PORT, (unsigned)mpls_label);
     142             : 
     143             :     if (queue_id >= 0xFF) {
     144             :         RTE_LOG(ERR, VROUTER, "    error adding perfect filter for eth device %"
     145             :                 PRIu8 ": queue ID %" PRIu16 " is out of range\n",
     146             :                  port_id, queue_id);
     147             :         return -EINVAL;
     148             :     }
     149             :     ret = rte_eth_dev_fdir_add_perfect_filter(port_id, &filter, (uint16_t)mpls_label,
     150             :         (uint8_t)queue_id, 0);
     151             :     if (ret == 0)
     152             :         ethdev->ethdev_queue_states[queue_id] = VR_DPDK_QUEUE_FILTERING_STATE;
     153             : 
     154             :     return ret;
     155             : }
     156             : #endif
     157             : 
     158             : /* Get a ready queue ID */
     159             : uint16_t
     160           0 : vr_dpdk_ethdev_ready_queue_id_get(struct vr_interface *vif)
     161             : {
     162             :     uint16_t i;
     163           0 :     struct vr_dpdk_ethdev *ethdev = (struct vr_dpdk_ethdev *)vif->vif_os;
     164             : 
     165           0 :     for (i = ethdev->ethdev_nb_rss_queues; i < ethdev->ethdev_nb_rx_queues; i++) {
     166           0 :         if (ethdev->ethdev_queue_states[i] == VR_DPDK_QUEUE_READY_STATE) {
     167           0 :             return i;
     168             :         }
     169             :     }
     170           0 :     return VR_DPDK_INVALID_QUEUE_ID;
     171             : }
     172             : 
     173             : /* Release ethdev RX queue */
     174             : static void
     175           0 : dpdk_ethdev_rx_queue_release(unsigned lcore_id,
     176             :         unsigned queue_index __attribute__((unused)),
     177             :         struct vr_interface *vif)
     178             : {
     179           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     180           0 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif->vif_idx];
     181           0 :     struct vr_dpdk_queue_params *rx_queue_params
     182           0 :                         = &lcore->lcore_rx_queue_params[vif->vif_idx];
     183             : 
     184             :     /* free the queue */
     185           0 :     if (rx_queue->rxq_ops.f_free(rx_queue->q_queue_h)) {
     186           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u eth device RX queue\n",
     187             :                     lcore_id);
     188             :     }
     189             : 
     190             :     /* reset the queue */
     191           0 :     vrouter_put_interface(rx_queue->q_vif);
     192           0 :     memset(rx_queue, 0, sizeof(*rx_queue));
     193           0 :     memset(rx_queue_params, 0, sizeof(*rx_queue_params));
     194           0 : }
     195             : 
     196             : /* Init eth RX queue */
     197             : struct vr_dpdk_queue *
     198           0 : vr_dpdk_ethdev_rx_queue_init(unsigned lcore_id, struct vr_interface *vif,
     199             :     unsigned queue_or_lcore_id)
     200             : {
     201           0 :     uint16_t rx_queue_id = queue_or_lcore_id;
     202             :     uint8_t port_id;
     203           0 :     unsigned int vif_idx = vif->vif_idx;
     204           0 :     const unsigned int socket_id = rte_lcore_to_socket_id(lcore_id);
     205             : 
     206             :     struct vr_dpdk_ethdev *ethdev;
     207           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     208           0 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif_idx];
     209           0 :     struct vr_dpdk_queue_params *rx_queue_params
     210             :                     = &lcore->lcore_rx_queue_params[vif_idx];
     211             : 
     212           0 :     ethdev = (struct vr_dpdk_ethdev *)vif->vif_os;
     213           0 :     port_id = ethdev->ethdev_port_id;
     214             : 
     215             :     /* init queue */
     216           0 :     rx_queue->rxq_ops = rte_port_ethdev_reader_ops;
     217           0 :     rx_queue->q_queue_h = NULL;
     218           0 :     rx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     219             : 
     220             :     /* create the queue */
     221           0 :     struct rte_port_ethdev_reader_params reader_params = {
     222             :         .port_id = port_id,
     223             :         .queue_id = rx_queue_id,
     224             :     };
     225           0 :     rx_queue->q_queue_h = rx_queue->rxq_ops.f_create(&reader_params, socket_id);
     226           0 :     if (rx_queue->q_queue_h == NULL) {
     227           0 :         RTE_LOG(ERR, VROUTER, "    error creating eth device %" PRIu8
     228             :                 " RX queue %" PRIu16 "\n", port_id, rx_queue_id);
     229           0 :         return NULL;
     230             :     }
     231             : 
     232           0 :     rx_queue->vring_queue_id = rx_queue_id;
     233             :     /* store queue params */
     234           0 :     rx_queue_params->qp_release_op = &dpdk_ethdev_rx_queue_release;
     235           0 :     rx_queue_params->qp_ethdev.queue_id = rx_queue_id;
     236           0 :     rx_queue_params->qp_ethdev.port_id = port_id;
     237             : 
     238           0 :     return rx_queue;
     239             : }
     240             : 
     241             : /* Release ethdev TX queue */
     242             : static void
     243           0 : dpdk_ethdev_tx_queue_release(unsigned lcore_id, unsigned queue_index,
     244             :         struct vr_interface *vif)
     245             : {
     246             :     int i;
     247             : 
     248           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     249             :     struct vr_dpdk_queue *tx_queue;
     250             :     struct vr_dpdk_queue_params *tx_queue_params;
     251             : 
     252           0 :     tx_queue = &lcore->lcore_tx_queues[vif->vif_idx][queue_index];
     253           0 :     tx_queue_params =
     254           0 :         &lcore->lcore_tx_queue_params[vif->vif_idx][queue_index];
     255             : 
     256             :     /* remove queue params from the list of bonds to TX */
     257           0 :     for (i = 0; i < lcore->lcore_nb_bonds_to_tx; i++) {
     258           0 :         if (likely(lcore->lcore_bonds_to_tx[i] == tx_queue_params)) {
     259           0 :             lcore->lcore_bonds_to_tx[i] = NULL;
     260           0 :             lcore->lcore_nb_bonds_to_tx--;
     261           0 :             RTE_VERIFY(lcore->lcore_nb_bonds_to_tx <= VR_DPDK_MAX_BONDS);
     262             :             /* copy the last element to the empty spot */
     263           0 :             lcore->lcore_bonds_to_tx[i] = lcore->lcore_bonds_to_tx[lcore->lcore_nb_bonds_to_tx];
     264           0 :             break;
     265             :         }
     266             :     }
     267             : 
     268           0 :     tx_queue->txq_ops.f_tx = NULL;
     269             :     rte_wmb();
     270             : 
     271             :     /* flush and free the queue */
     272           0 :     if (tx_queue->txq_ops.f_free(tx_queue->q_queue_h)) {
     273           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u eth device TX queue\n",
     274             :                     lcore_id);
     275             :     }
     276             : 
     277             :     /* reset the queue */
     278           0 :     vrouter_put_interface(tx_queue->q_vif);
     279           0 :     memset(tx_queue, 0, sizeof(*tx_queue));
     280           0 :     memset(tx_queue_params, 0, sizeof(*tx_queue_params));
     281           0 : }
     282             : 
     283             : /* Init eth TX queue */
     284             : struct vr_dpdk_queue *
     285           0 : vr_dpdk_ethdev_tx_queue_init(unsigned lcore_id, struct vr_interface *vif,
     286             :     unsigned queue_or_lcore_id)
     287             : {
     288             :     uint8_t port_id;
     289           0 :     uint16_t tx_queue_id = queue_or_lcore_id;
     290           0 :     unsigned int vif_idx = vif->vif_idx, dpdk_queue_index;
     291           0 :     const unsigned int socket_id = rte_lcore_to_socket_id(lcore_id);
     292             : 
     293             :     struct vr_dpdk_ethdev *ethdev;
     294           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     295             :     struct vr_dpdk_queue *tx_queue;
     296             :     struct vr_dpdk_queue_params *tx_queue_params;
     297             : 
     298           0 :     ethdev = (struct vr_dpdk_ethdev *)vif->vif_os;
     299           0 :     port_id = ethdev->ethdev_port_id;
     300             : 
     301           0 :     if (lcore->lcore_hw_queue_to_dpdk_index[vif->vif_idx]) {
     302           0 :         dpdk_queue_index =
     303           0 :             lcore->lcore_hw_queue_to_dpdk_index[vif->vif_idx][tx_queue_id];
     304             :     } else {
     305           0 :         dpdk_queue_index = 0;
     306             :     }
     307             : 
     308           0 :     tx_queue = &lcore->lcore_tx_queues[vif_idx][dpdk_queue_index];
     309           0 :     tx_queue_params = &lcore->lcore_tx_queue_params[vif_idx][dpdk_queue_index];
     310             : 
     311             :     /* init queue */
     312           0 :     tx_queue->txq_ops = rte_port_ethdev_writer_ops;
     313           0 :     tx_queue->q_queue_h = NULL;
     314           0 :     tx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     315             : 
     316             :     /* create the queue */
     317           0 :     struct rte_port_ethdev_writer_params writer_params = {
     318             :         .port_id = port_id,
     319             :         .queue_id = tx_queue_id,
     320             :         .tx_burst_sz = VR_DPDK_TX_BURST_SZ,
     321             :     };
     322           0 :     tx_queue->q_queue_h = tx_queue->txq_ops.f_create(&writer_params, socket_id);
     323           0 :     if (tx_queue->q_queue_h == NULL) {
     324           0 :         RTE_LOG(ERR, VROUTER, "    error creating eth device %" PRIu8
     325             :                 " TX queue %" PRIu16 "\n", port_id, tx_queue_id);
     326           0 :         return NULL;
     327             :     }
     328             : 
     329             :     /* store queue params */
     330           0 :     tx_queue_params->qp_release_op = &dpdk_ethdev_tx_queue_release;
     331           0 :     tx_queue_params->qp_ethdev.queue_id = tx_queue_id;
     332           0 :     tx_queue_params->qp_ethdev.port_id = port_id;
     333             : 
     334             :     /* for the queue 0 add queue params to the list of bonds to TX */
     335           0 :     if (ethdev->ethdev_nb_slaves > 0 && tx_queue_id == 0) {
     336             :         /* make sure queue params have been stored */
     337             :         rte_wmb();
     338           0 :         lcore->lcore_bonds_to_tx[lcore->lcore_nb_bonds_to_tx++] = tx_queue_params;
     339           0 :         RTE_VERIFY(lcore->lcore_nb_bonds_to_tx <= VR_DPDK_MAX_BONDS);
     340             :     }
     341             : 
     342           0 :     return tx_queue;
     343             : }
     344             : 
     345             : /*
     346             :  * vr_max_tx_queues_adjust - bond devices always return dev_info indicating
     347             :  * 512 TX queues are supported. vrouter clips down to a max of VR_DPDK_MAX_NB_TX_QUEUES.
     348             :  * However, if any of the bond slaves does not support this many TX queues, the
     349             :  * number needs to be reduced further to a value that the NIC can support. Also,
     350             :  * bnxt report max_tx_queues of 170, but fails to configure more than 8 TX queues.
     351             :  */
     352             : static void
     353           0 : vr_max_tx_queues_adjust(struct vr_dpdk_ethdev *ethdev, uint16_t *nb_tx_q)
     354             : {
     355             :     struct rte_eth_dev_info dev_info;
     356             :     int i;
     357             : 
     358           0 :     VR_DPDK_RTE_ETH_FOREACH_DEV(i)
     359             :     {
     360           0 :         rte_eth_dev_info_get(i, &dev_info);
     361           0 :         if (dev_info.driver_name) {
     362           0 :             if (strncmp(dev_info.driver_name, "net_bnxt",
     363             :                          strlen("net_bnxt") + 1) == 0) {
     364           0 :                 if (*nb_tx_q > VR_DPDK_MAX_NB_TX_Q_BNXT) {
     365           0 :                     RTE_LOG(INFO, VROUTER, "TX queues changed from %d to %d due to port %d\n",
     366             :                         *nb_tx_q, VR_DPDK_MAX_NB_TX_Q_BNXT, i);
     367           0 :                     *nb_tx_q = VR_DPDK_MAX_NB_TX_Q_BNXT;
     368             :                 }
     369             :             }
     370             :         }
     371             :     }
     372             : 
     373           0 :     return;
     374             : }
     375             : 
     376             : /* Update device info */
     377             : static void
     378           0 : dpdk_ethdev_info_update(struct vr_dpdk_ethdev *ethdev)
     379             : {
     380             :     struct rte_eth_dev_info dev_info;
     381             : 
     382           0 :     rte_eth_dev_info_get(ethdev->ethdev_port_id, &dev_info);
     383             : 
     384           0 :     ethdev->ethdev_nb_rx_queues = RTE_MIN(dev_info.max_rx_queues,
     385             :         VR_DPDK_MAX_NB_RX_QUEUES);
     386             : 
     387           0 :     if (dev_info.max_tx_queues > VR_DPDK_MAX_NB_TX_QUEUES)
     388           0 :         dev_info.max_tx_queues = VR_DPDK_MAX_NB_TX_QUEUES;
     389             : 
     390             :     /*
     391             :      * If a device advertises max_tx_queues higher than it
     392             :      * can actually support, reduce the value to a number
     393             :      * that it can support.
     394             :      */
     395           0 :     vr_max_tx_queues_adjust(ethdev, &dev_info.max_tx_queues);
     396             : 
     397           0 :     ethdev->ethdev_nb_tx_queues = dev_info.max_tx_queues;
     398             : 
     399             :     /* Check if we have dedicated an lcore for SR-IOV VF IO. */
     400           0 :     if (vr_dpdk.vf_lcore_id) {
     401           0 :         ethdev->ethdev_nb_rx_queues = ethdev->ethdev_nb_tx_queues = 1;
     402             :     }
     403             : 
     404           0 :     ethdev->ethdev_nb_rss_queues = RTE_MIN(RTE_MIN(ethdev->ethdev_nb_rx_queues,
     405             :         vr_dpdk.nb_fwd_lcores), VR_DPDK_MAX_NB_RSS_QUEUES);
     406           0 :     ethdev->ethdev_reta_size = RTE_MIN(dev_info.reta_size,
     407             :         VR_DPDK_MAX_RETA_SIZE);
     408             : 
     409             :     /*
     410             :      * If the NIC driver sets reta_size to a value that is not a power of
     411             :      * 2, align it as DPDK expects it to be a power of 2.
     412             :      */
     413           0 :     ethdev->ethdev_reta_size = RTE_ALIGN(ethdev->ethdev_reta_size, RTE_RETA_GROUP_SIZE);
     414             : 
     415             :     RTE_LOG_DP(DEBUG, VROUTER, "dev_info: driver_name=%s if_index=%u"
     416             :             " max_rx_queues=%" PRIu16 " max_tx_queues=%" PRIu16
     417             :             " max_vfs=%" PRIu16 " max_vmdq_pools=%" PRIu16
     418             :             " rx_offload_capa=%" PRIx64 " tx_offload_capa=%" PRIx64 "\n",
     419             :             dev_info.driver_name, dev_info.if_index,
     420             :             dev_info.max_rx_queues, dev_info.max_tx_queues,
     421             :             dev_info.max_vfs, dev_info.max_vmdq_pools,
     422             :             dev_info.rx_offload_capa, dev_info.tx_offload_capa);
     423             : 
     424             : #if !VR_DPDK_USE_HW_FILTERING
     425             :     /* use RSS queues only */
     426           0 :     ethdev->ethdev_nb_rx_queues = ethdev->ethdev_nb_rss_queues;
     427             : #else
     428             :     /* we use just RSS queues if the device does not support RETA */
     429             :     if (ethdev->ethdev_reta_size == 0)
     430             :         ethdev->ethdev_nb_rx_queues = ethdev->ethdev_nb_rss_queues;
     431             : #endif
     432             : 
     433           0 :     RTE_LOG(INFO, VROUTER, "Using %d TX queues, %d RX queues\n",
     434             :             ethdev->ethdev_nb_tx_queues, 
     435             :             ethdev->ethdev_nb_rx_queues);
     436             : 
     437           0 :     return;
     438             : }
     439             : 
     440             : /* Setup ethdev hardware queues */
     441             : /* If (tx|rx)_conf is null, default_(tx|rx)_queue_conf will be used instead */
     442             : static int
     443           0 : dpdk_ethdev_queues_setup(struct vr_dpdk_ethdev *ethdev,
     444             :     struct rte_eth_txconf *tx_conf, struct rte_eth_rxconf *rx_conf)
     445             : {
     446             :     int ret, i;
     447           0 :     uint8_t port_id = ethdev->ethdev_port_id;
     448             :     struct rte_mempool *mempool;
     449             : 
     450             :     /* configure RX queues */
     451             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: nb_rx_queues=%u nb_tx_queues=%u\n",
     452             :         __func__, (unsigned)ethdev->ethdev_nb_rx_queues,
     453             :             (unsigned)ethdev->ethdev_nb_tx_queues);
     454             : 
     455           0 :     for (i = 0; i < VR_DPDK_MAX_NB_RX_QUEUES; i++) {
     456           0 :         if (i < ethdev->ethdev_nb_rss_queues) {
     457           0 :             mempool = vr_dpdk.rss_mempool;
     458           0 :             ethdev->ethdev_queue_states[i] = VR_DPDK_QUEUE_RSS_STATE;
     459           0 :         } else if (i < ethdev->ethdev_nb_rx_queues) {
     460           0 :             if (vr_dpdk.nb_free_mempools == 0) {
     461           0 :                 RTE_LOG(ERR, VROUTER, "    error assigning mempool to eth device %"
     462             :                     PRIu8 " RX queue %d\n", port_id, i);
     463           0 :                 return -ENOMEM;
     464             :             }
     465           0 :             vr_dpdk.nb_free_mempools--;
     466           0 :             mempool = vr_dpdk.free_mempools[vr_dpdk.nb_free_mempools];
     467           0 :             ethdev->ethdev_queue_states[i] = VR_DPDK_QUEUE_READY_STATE;
     468             :         } else {
     469           0 :             ethdev->ethdev_queue_states[i] = VR_DPDK_QUEUE_NONE;
     470           0 :             continue;
     471             :         }
     472             : 
     473           0 :         ret = rte_eth_rx_queue_setup(port_id, i, vr_rxd_sz,
     474             :             SOCKET_ID_ANY, rx_conf ? rx_conf : &default_rx_queue_conf, mempool);
     475           0 :         if (ret < 0) {
     476             :             /* return mempool to the list */
     477           0 :             if (mempool != vr_dpdk.rss_mempool)
     478           0 :                 vr_dpdk.nb_free_mempools++;
     479           0 :             RTE_LOG(ERR, VROUTER, "    error setting up eth device %" PRIu8 " RX queue %d"
     480             :                     ": %s (%d)\n", port_id, i, rte_strerror(-ret), -ret);
     481           0 :             return ret;
     482             :         }
     483             :         /* map RX queue to stats counter ignoring any errors */
     484           0 :         rte_eth_dev_set_rx_queue_stats_mapping(port_id, i, i);
     485             : 
     486             :         /* save queue mempool pointer */
     487           0 :         ethdev->ethdev_mempools[i] = mempool;
     488             :     }
     489           0 :     i = ethdev->ethdev_nb_rx_queues - ethdev->ethdev_nb_rss_queues;
     490           0 :     RTE_LOG(INFO, VROUTER, "    setup %d RSS queue(s) and %d filtering queue(s)\n",
     491             :         (int)ethdev->ethdev_nb_rss_queues, i);
     492             : 
     493             :     /* configure TX queues */
     494           0 :     for (i = 0; i < ethdev->ethdev_nb_tx_queues; i++) {
     495           0 :         ret = rte_eth_tx_queue_setup(port_id, i, vr_txd_sz,
     496             :             SOCKET_ID_ANY, tx_conf ? tx_conf : &default_tx_queue_conf);
     497           0 :         if (ret < 0) {
     498           0 :             RTE_LOG(ERR, VROUTER, "    error setting up eth device %" PRIu8 " TX queue %d"
     499             :                     ": %s (%d)\n", port_id, i, rte_strerror(-ret), -ret);
     500           0 :             return ret;
     501             :         }
     502             :         /* map TX queue to stats counter ignoring any errors */
     503           0 :         rte_eth_dev_set_tx_queue_stats_mapping(port_id, i, i);
     504             :     }
     505           0 :     return 0;
     506             : }
     507             : 
     508             : static void
     509           0 : dpdk_ethdev_reta_show(uint8_t port_id, uint16_t reta_size)
     510           0 : {
     511           0 :     int nb_entries = reta_size/RTE_RETA_GROUP_SIZE;
     512           0 :     struct rte_eth_rss_reta_entry64 reta_entries[nb_entries];
     513             :     struct rte_eth_rss_reta_entry64 *reta;
     514             :     uint16_t i, idx, shift;
     515             :     int ret, entry;
     516             : 
     517           0 :     for (entry = 0; entry < nb_entries; entry++) {
     518           0 :         reta = &reta_entries[entry];
     519             : 
     520             :         /* reset RSS redirection table */
     521           0 :         memset(reta, 0, sizeof(*reta));
     522           0 :         reta->mask = 0xffffffffffffffffULL;
     523             :     }
     524             : 
     525           0 :     ret = rte_eth_dev_rss_reta_query(port_id, reta_entries, reta_size);
     526           0 :     if (ret != 0) {
     527           0 :         RTE_LOG(ERR, VROUTER, "Error getting RSS RETA info: %s (%d)\n",
     528             :             rte_strerror(ret), ret);
     529           0 :         return;
     530             :     }
     531             : 
     532           0 :     for (i = 0; i < reta_size; i++) {
     533           0 :         idx = i / RTE_RETA_GROUP_SIZE;
     534           0 :         shift = i % RTE_RETA_GROUP_SIZE;
     535           0 :         if (!(reta_entries[idx].mask & (1ULL << shift)))
     536           0 :             continue;
     537             :         RTE_LOG_DP(DEBUG, VROUTER, "        hash index=%u, queue=%u\n",
     538             :                     i, reta_entries[idx].reta[shift]);
     539             :     }
     540             : }
     541             : 
     542             : /* Init RSS */
     543             : int
     544           0 : vr_dpdk_ethdev_rss_init(struct vr_dpdk_ethdev *ethdev)
     545             : {
     546             :     int ret, i, j, entry;
     547           0 :     uint8_t port_id = ethdev->ethdev_port_id;
     548           0 :     int nb_entries = ethdev->ethdev_reta_size/RTE_RETA_GROUP_SIZE;
     549             :     struct rte_eth_rss_reta_entry64 reta_entries[VR_DPDK_MAX_RETA_ENTRIES];
     550             :     struct rte_eth_rss_reta_entry64 *reta;
     551             : 
     552             :     /* There is nothing to configure if the device does not support RETA.
     553             :      * If the device reported few RX queues earlier, we assume those
     554             :      * queues are preconfigured for RSS by default.
     555             :      */
     556           0 :     if (ethdev->ethdev_reta_size == 0)
     557           0 :         return 0;
     558             : 
     559             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS RETA BEFORE:\n", __func__);
     560           0 :     dpdk_ethdev_reta_show(port_id, ethdev->ethdev_reta_size);
     561             : 
     562           0 :     for (entry = 0; entry < nb_entries; entry++) {
     563           0 :         reta = &reta_entries[entry];
     564             : 
     565             :         /* create new RSS redirection table */
     566           0 :         memset(reta, 0, sizeof(*reta));
     567           0 :         reta->mask = 0xffffffffffffffffULL;
     568           0 :         for (i = j = 0; i < RTE_RETA_GROUP_SIZE; i++) {
     569           0 :             reta->reta[i] = j++;
     570           0 :             if (ethdev->ethdev_queue_states[j] != VR_DPDK_QUEUE_RSS_STATE)
     571           0 :                 j = 0;
     572             :         }
     573             :     }
     574             : 
     575             :     /* update RSS redirection table */
     576           0 :     ret = rte_eth_dev_rss_reta_update(port_id, reta_entries,
     577           0 :                 ethdev->ethdev_reta_size);
     578             : 
     579             :     /* no error if the device does not support RETA configuration */
     580           0 :     if (ret == -ENOTSUP)
     581           0 :         return 0;
     582             : 
     583           0 :     if (ret < 0) {
     584           0 :         RTE_LOG(ERR, VROUTER, "    error initializing ethdev %" PRIu8 " RSS: %s (%d)\n",
     585             :             port_id, rte_strerror(-ret), -ret);
     586             :     }
     587             : 
     588             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS RETA AFTER:\n", __func__);
     589           0 :     dpdk_ethdev_reta_show(port_id, ethdev->ethdev_reta_size);
     590             : 
     591           0 :     return ret;
     592             : }
     593             : 
     594             : /* Init hardware filtering */
     595             : static void
     596           0 : dpdk_ethdev_mempools_free(struct vr_dpdk_ethdev *ethdev)
     597             : {
     598             :     int i;
     599             : 
     600           0 :     for (i = ethdev->ethdev_nb_rss_queues; i < ethdev->ethdev_nb_rx_queues; i++) {
     601           0 :         if (ethdev->ethdev_mempools[i] != NULL
     602           0 :             && ethdev->ethdev_mempools[i] != vr_dpdk.rss_mempool) {
     603           0 :             vr_dpdk.free_mempools[vr_dpdk.nb_free_mempools++] =
     604           0 :                 ethdev->ethdev_mempools[i];
     605           0 :             ethdev->ethdev_mempools[i] = NULL;
     606           0 :             ethdev->ethdev_queue_states[i] = VR_DPDK_QUEUE_READY_STATE;
     607             :         }
     608             :     }
     609           0 : }
     610             : 
     611             : #if VR_DPDK_USE_HW_FILTERING
     612             : /* Init hardware filtering */
     613             : int
     614             : vr_dpdk_ethdev_filtering_init(struct vr_interface *vif,
     615             :         struct vr_dpdk_ethdev *ethdev)
     616             : {
     617             :     int ret;
     618             :     uint8_t port_id = ethdev->ethdev_port_id;
     619             :     struct rte_fdir_masks masks;
     620             :     struct rte_eth_fdir fdir_info;
     621             : 
     622             :     /* probe Flow Director */
     623             :     memset(&fdir_info, 0, sizeof(fdir_info));
     624             :     ret = rte_eth_dev_fdir_get_infos(port_id, &fdir_info);
     625             :     if (ret == 0) {
     626             :         /* enable hardware filtering */
     627             :         RTE_LOG(INFO, VROUTER, "    enable hardware filtering for ethdev %"
     628             :             PRIu8 "\n", port_id);
     629             :         vif->vif_flags |= VIF_FLAG_FILTERING_OFFLOAD;
     630             :     } else {
     631             :         vif->vif_flags &= ~VIF_FLAG_FILTERING_OFFLOAD;
     632             :         /* free filtering mempools */
     633             :         dpdk_ethdev_mempools_free(ethdev);
     634             :         /* the ethdev does not support hardware filtering - it's not an error */
     635             :         return 0;
     636             :     }
     637             : 
     638             :     memset(&masks, 0, sizeof(masks));
     639             :     masks.dst_ipv4_mask = 0xffffffff;
     640             :     masks.dst_port_mask = 0xffff;
     641             :     masks.flexbytes = 1;
     642             : 
     643             :     ret = rte_eth_dev_fdir_set_masks(port_id, &masks);
     644             :     if (ret < 0) {
     645             :         RTE_LOG(ERR, VROUTER, "    error setting ethdev %" PRIu8
     646             :             " Flow Director masks: %s (%d)\n", port_id, rte_strerror(-ret), -ret);
     647             :     }
     648             : 
     649             :     return ret;
     650             : }
     651             : #endif
     652             : 
     653             : /* Update device bond info */
     654             : static void
     655           0 : dpdk_ethdev_bond_info_update(struct vr_dpdk_ethdev *ethdev)
     656             : {
     657             :     int i, slave_port_id, ret;
     658           0 :     int port_id = ethdev->ethdev_port_id;
     659           0 :     uint16_t mtu = 0;
     660             :     struct rte_pci_addr *pci_addr;
     661             :     struct rte_ether_addr bond_mac, mac_addr;
     662           0 :     struct rte_ether_addr lacp_mac = { .addr_bytes = {0x01, 0x80, 0xc2, 0, 0, 0x02} };
     663             : 
     664           0 :     if (rte_eth_bond_mode_get(port_id) == -1) {
     665           0 :         ethdev->ethdev_nb_slaves = -1;
     666             :     } else {
     667           0 :         ethdev->ethdev_nb_slaves = rte_eth_bond_slaves_get(port_id,
     668           0 :             ethdev->ethdev_slaves, VR_DPDK_BOND_MAX_SLAVES);
     669             : 
     670           0 :         memset(&mac_addr, 0, sizeof(bond_mac));
     671           0 :         rte_eth_macaddr_get(port_id, &bond_mac);
     672           0 :         RTE_LOG(INFO, VROUTER, "    bond eth device %" PRIu8
     673             :             " configured MAC " MAC_FORMAT "\n",
     674             :             port_id, MAC_VALUE(bond_mac.addr_bytes));
     675             :         /* log out and configure bond members */
     676           0 :         for (i = 0; i < ethdev->ethdev_nb_slaves; i++) {
     677           0 :             slave_port_id = ethdev->ethdev_slaves[i];
     678           0 :             if (!rte_eth_devices[port_id].data->mtu) {
     679           0 :                 rte_eth_dev_get_mtu(slave_port_id, &mtu);
     680           0 :                 rte_eth_devices[port_id].data->mtu = mtu;
     681             :             }
     682           0 :             memset(&mac_addr, 0, sizeof(mac_addr));
     683           0 :             rte_eth_macaddr_get(slave_port_id, &mac_addr);
     684           0 :             pci_addr = &(RTE_DEV_TO_PCI(rte_eth_devices[slave_port_id].device)->addr);
     685           0 :             RTE_LOG(INFO, VROUTER, "    bond member eth device %" PRIu8
     686             :                 " PCI " PCI_PRI_FMT " MAC " MAC_FORMAT "\n",
     687             :                 slave_port_id, pci_addr->domain, pci_addr->bus,
     688             :                 pci_addr->devid, pci_addr->function,
     689             :                 MAC_VALUE(mac_addr.addr_bytes));
     690             : 
     691             :             /* We just try to add the mc address. In any case, the bond driver would
     692             :              * enable the 'all multicast' mode
     693             :              */
     694           0 :             if ((ret=rte_eth_dev_set_mc_addr_list(slave_port_id, &lacp_mac, 1)) != 0)
     695           0 :                 RTE_LOG(INFO, VROUTER, "    bond member eth device %" PRIu8
     696             :                     ": unable to add multicast addresses %d\n", slave_port_id,ret);
     697             : 
     698             :             /*
     699             :              * Need to set the dev mac to disable the promiscuous mode
     700             :              */
     701           0 :             if ((ret=rte_eth_dev_mac_addr_add(slave_port_id, &bond_mac, 0)) != 0)
     702           0 :                 RTE_LOG(INFO, VROUTER, "    bond member eth device %" PRIu8
     703             :                     ": unable to add MAC addresses %d\n", slave_port_id,ret);
     704             :             else {
     705           0 :                 RTE_LOG(INFO, VROUTER, "    disabling promiscuous mode for device %d\n", slave_port_id);
     706           0 :                 rte_eth_promiscuous_disable(ethdev->ethdev_port_id);
     707             :             }
     708             : 
     709             :         }
     710           0 :         rte_eth_allmulticast_enable(ethdev->ethdev_port_id);
     711             :     }
     712           0 : }
     713             : 
     714             : /* Check if port_id is a bond slave. */
     715             : bool
     716           0 : vr_dpdk_ethdev_bond_port_match(uint8_t port_id, struct vr_dpdk_ethdev *ethdev)
     717             : {
     718             :     int i;
     719             : 
     720           0 :     if (ethdev->ethdev_nb_slaves > 0) {
     721           0 :         for (i = 0; i < ethdev->ethdev_nb_slaves; i++) {
     722           0 :             if (port_id == ethdev->ethdev_slaves[i])
     723           0 :                 break;
     724             :         }
     725             : 
     726           0 :         if (i < ethdev->ethdev_nb_slaves)
     727           0 :             return true;
     728             :     }
     729             : 
     730           0 :     return false;
     731             : }
     732             : 
     733             : 
     734             : /*
     735             :  * Function to send bond interface state to Agent
     736             :  * info->status 0 - down
     737             :  * info->status 1 - up
     738             :  * Called when bond master/slave interface goes down or comes up
     739             :  */
     740             : void
     741           0 : vr_dpdk_nl_send_bond_intf_state(struct vr_dpdk_bond_member_info *info,
     742             :         unsigned type, uint8_t vif_idx)
     743             : {
     744             :     int nl_fd;
     745             :     char buf[1024];
     746             :     struct nlmsghdr *nlh;
     747             :     struct ifinfomsg *ifinfo;
     748             :     struct nlattr *nla;
     749             :     int len, n;
     750             :     char *if_name_buf;
     751             :     struct sockaddr_nl sa;
     752             : 
     753           0 :     if (info == NULL) {
     754           0 :         RTE_LOG(ERR, VROUTER, "Bond member info is NULL\n");
     755           0 :         return;
     756             :     }
     757           0 :     memset(buf, 0, sizeof(buf));
     758           0 :     memset(&sa, 0, sizeof(sa));
     759           0 :     sa.nl_family = AF_NETLINK;
     760           0 :     sa.nl_pid = 0;
     761           0 :     sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
     762             : 
     763           0 :     nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     764           0 :     if (nl_fd < 0) {
     765           0 :         RTE_LOG(ERR, VROUTER, "Error creating netlink socket\n");
     766           0 :         goto error;
     767             :     }
     768           0 :     bind(nl_fd, (struct sockaddr *)&sa, sizeof(sa));
     769           0 :     nlh = (struct nlmsghdr *)buf;
     770             : 
     771           0 :     nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(struct ifinfomsg);
     772           0 :     nlh->nlmsg_type = RTM_NEWLINK;
     773           0 :     nlh->nlmsg_flags = NLM_F_REQUEST;
     774           0 :     nlh->nlmsg_seq = 1;
     775           0 :     nlh->nlmsg_pid = 0;
     776           0 :     ifinfo = (struct ifinfomsg *)(buf + NLMSG_HDRLEN);
     777             : 
     778           0 :     ifinfo->ifi_family = 0;
     779           0 :     ifinfo->ifi_type = type;
     780             : 
     781             :     /* Set index to -1 as agent needs only the interface name */
     782           0 :     ifinfo->ifi_index = -1;
     783             : 
     784           0 :     if (info->status)
     785           0 :         ifinfo->ifi_flags = IFF_MULTICAST|IFF_RUNNING|IFF_BROADCAST|IFF_UP;
     786             :     else
     787           0 :         ifinfo->ifi_flags = IFF_BROADCAST|IFF_UP;
     788             :     /* ifi_change needs to be set to 0xFFFFFFFF by default
     789             :      * as its a reserved field
     790             :      */
     791           0 :     ifinfo->ifi_change = 0xFFFFFFFF;
     792             : 
     793           0 :     nla = (struct nlattr *)(buf + NLMSG_HDRLEN + sizeof(struct ifinfomsg));
     794             : 
     795           0 :     if_name_buf = (char *)nla + NLA_HDRLEN;
     796             : 
     797           0 :     sprintf(if_name_buf,"%s %s %x", info->intf_name, info->intf_drv_name,
     798             :             vif_idx);
     799             : 
     800           0 :     len = NLA_HDRLEN + NLA_ALIGN(strlen(if_name_buf) + 1);
     801             : 
     802           0 :     nla->nla_len = len;
     803           0 :     nla->nla_type = IFLA_IFNAME;
     804             : 
     805             : 
     806           0 :     len += (NLMSG_HDRLEN + sizeof(struct ifinfomsg));
     807             : 
     808           0 :     nlh->nlmsg_len = len;
     809             : 
     810           0 :     n = sendto(nl_fd, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa));
     811           0 :     if (n != len) {
     812           0 :         RTE_LOG(ERR, VROUTER, "Error sending netlink bond interface message\n");
     813             :     }
     814             :     else
     815           0 :         RTE_LOG(INFO, VROUTER, "Notifed Link status update to agent for \
     816             :                 interface name %s\n",
     817             :             info->intf_name);
     818             : 
     819           0 :     close(nl_fd);
     820           0 : error:
     821           0 :     return;
     822             : }
     823             : 
     824             : static int
     825           0 : vr_dpdk_bond_send_port_info(uint16_t port_id, uint8_t vif_idx)
     826             : {
     827             :     int ret;
     828           0 :     char *str[] = {"UP", "DOWN"};
     829             :     struct rte_eth_link link;
     830             :     unsigned bond_type;
     831             :     uint32_t dev_flags;
     832             :     struct vr_dpdk_bond_member_info member_info;
     833             : 
     834           0 :     memset(&member_info, 0, sizeof(member_info));
     835             : 
     836           0 :     rte_eth_link_get_nowait(port_id, &link);
     837           0 :     member_info.status = link.link_status;
     838             : 
     839           0 :     ret = rte_eth_dev_get_name_by_port(port_id, member_info.intf_name);
     840           0 :     if(ret != 0)
     841           0 :         RTE_LOG(ERR, VROUTER, "%s: Error getting bond interface name "
     842             :                             "port_id:%d\n", __func__, port_id);
     843             : 
     844           0 :     if(rte_eth_devices[port_id].device->driver->name != NULL)
     845           0 :         snprintf(member_info.intf_drv_name, (VR_INTERFACE_NAME_LEN - 1),
     846           0 :                 "%s", rte_eth_devices[port_id].device->driver->name);
     847             : 
     848           0 :     RTE_LOG(INFO, VROUTER, "Port ID: %d Link Status: %s intf_name:%s \
     849             :             drv_name:%s \n\n", port_id, (link.link_status?str[0]:str[1]),
     850             :             member_info.intf_name, member_info.intf_drv_name);
     851             : 
     852           0 :     dev_flags = rte_eth_devices[port_id].data->dev_flags;
     853           0 :     bond_type = (dev_flags & RTE_ETH_DEV_BONDED_SLAVE) ? VR_DPDK_BOND_SLAVE :
     854             :         VR_DPDK_BOND_MASTER;
     855             : 
     856           0 :     vr_dpdk_nl_send_bond_intf_state(&member_info, bond_type, vif_idx);
     857             : 
     858           0 :     return 0;
     859             : 
     860             : }
     861             : 
     862             : static int
     863           0 : vr_dpdk_bond_intf_callback(uint16_t port_id, enum rte_eth_event_type type,
     864             :         void *param, void *ret_param __rte_unused)
     865             : {
     866             : 
     867           0 :     struct vr_dpdk_ethdev *ethdev = (struct vr_dpdk_ethdev *)param;
     868             : 
     869           0 :     if(NULL == ethdev) {
     870           0 :         RTE_LOG(ERR, VROUTER, "%s: ethdev is null\n", __func__);
     871           0 :         return -1;
     872             :     }
     873             : 
     874             :     /* On few platforms, Master lsc(callback) is not called.
     875             :      * Forcing here to send Master notification before
     876             :      * sending child interface */
     877           0 :     if(ethdev->ethdev_port_id != port_id)
     878           0 :             vr_dpdk_bond_send_port_info(ethdev->ethdev_port_id, ethdev->ethdev_vif_idx);
     879             : 
     880           0 :     return vr_dpdk_bond_send_port_info(port_id, ethdev->ethdev_vif_idx);
     881             : 
     882             : }
     883             : 
     884             : static void
     885           0 : vr_dpdk_bond_intf_cb_register(struct vr_dpdk_ethdev *ethdev)
     886             : {
     887             : 
     888           0 :     int i = 0, ret = 0;
     889             : 
     890             :     /* Fetching port-id for master bond interface */
     891           0 :     uint8_t port_id = ethdev->ethdev_port_id;
     892           0 :     vr_dpdk_master_port_id = port_id;
     893             : 
     894             :     /* Registering callback notification for Master bond interface */
     895           0 :     ret = rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC,
     896             :             vr_dpdk_bond_intf_callback, ethdev);
     897             : 
     898           0 :     if(ret)
     899           0 :         RTE_LOG(ERR, VROUTER, "Failed to setup callback for event \
     900             :                 RTE_ETH_EVENT_INTR_LSC for portid: %d\n", port_id);
     901             :     else {
     902             :         /* During system initialization, notify agent about the master
     903             :          * and number of slaves */
     904           0 :         vr_dpdk_bond_send_port_info(port_id, ethdev->ethdev_vif_idx);
     905             :     }
     906             : 
     907             :     /* For slave interface*/
     908           0 :     for (i = 0; i < ethdev->ethdev_nb_slaves; i++) {
     909             : 
     910           0 :         port_id = ethdev->ethdev_slaves[i];
     911             : 
     912             :         /* Registering callback notification for slave bond interfaces */
     913           0 :         ret = rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC,
     914             :                 vr_dpdk_bond_intf_callback, ethdev);
     915           0 :         if(ret)
     916           0 :             RTE_LOG(ERR, VROUTER, "Failed to setup callback for event \
     917             :                     RTE_ETH_EVENT_INTR_LSC for portid: %d\n", port_id);
     918             :         else
     919           0 :             vr_dpdk_bond_send_port_info(port_id, ethdev->ethdev_vif_idx);
     920             :     }
     921           0 : }
     922             : 
     923             : /* Init ethernet device */
     924             : int
     925           0 : vr_dpdk_ethdev_init(struct vr_dpdk_ethdev *ethdev, struct rte_eth_conf *dev_conf,
     926             :     struct rte_eth_txconf *tx_conf, struct rte_eth_rxconf *rx_conf)
     927             : {
     928             :     uint8_t port_id;
     929             :     int ret;
     930             :     struct vr_interface *vif;
     931             : 
     932           0 :     port_id = ethdev->ethdev_port_id;
     933           0 :     ethdev->ethdev_ptr = &rte_eth_devices[port_id];
     934           0 :     vif = __vrouter_get_interface(vrouter_get(0), ethdev->ethdev_vif_idx);
     935             : 
     936           0 :     dpdk_ethdev_info_update(ethdev);
     937             : 
     938           0 :     ret = rte_eth_dev_configure(port_id, ethdev->ethdev_nb_rx_queues,
     939           0 :         ethdev->ethdev_nb_tx_queues, dev_conf);
     940           0 :     if (ret < 0) {
     941           0 :         RTE_LOG(ERR, VROUTER, "    error configuring eth dev %" PRIu8
     942             :                 ": %s (%d)\n",
     943             :             port_id, rte_strerror(-ret), -ret);
     944           0 :         return ret;
     945             :     }
     946             : 
     947           0 :     if (rte_eth_devices[port_id].device->driver != NULL &&
     948           0 :        (strcmp(rte_eth_devices[port_id].device->driver->name, "net_bonding") == 0)) {
     949           0 :         dpdk_ethdev_bond_info_update(ethdev);
     950             : 
     951             :     }
     952             : 
     953             :     /* Register notifications only for fabric device */
     954           0 :     if (vif_is_fabric(vif))
     955           0 :         vr_dpdk_bond_intf_cb_register(ethdev);
     956             : 
     957           0 :     if(vr_dpdk_get_ddp()) {
     958           0 :         ret = vr_dpdk_process_ddp_package(VR_DPDK_DDP_ADD);
     959           0 :         if(ret != 0) {
     960             :             /* By Default DDP is set, If firmware programming not success on
     961             :              * any ports, then dont disable software load balancing */
     962           0 :             vr_dpdk_reset_ddp();
     963             :         }
     964             :     }
     965             : 
     966           0 :     ret = dpdk_ethdev_queues_setup(ethdev, tx_conf, rx_conf);
     967           0 :     if (ret < 0)
     968           0 :         return ret;
     969             : 
     970             :     /* Promisc mode
     971             :      * KNI generates random MACs for e1000e NICs, so we need this
     972             :      * option enabled for the development on servers with those NICs
     973             :      */
     974             : #if VR_DPDK_ENABLE_PROMISC
     975             :     rte_eth_promiscuous_enable(port_id);
     976             : #endif
     977             : 
     978           0 :     rte_spinlock_init(&ethdev->ethdev_lock);
     979             : 
     980           0 :     return 0;
     981             : }
     982             : 
     983             : /* Release ethernet device */
     984             : int
     985           0 : vr_dpdk_ethdev_release(struct vr_dpdk_ethdev *ethdev)
     986             : {
     987           0 :     ethdev->ethdev_ptr = NULL;
     988             : 
     989           0 :     dpdk_ethdev_mempools_free(ethdev);
     990             : 
     991           0 :     return 0;
     992             : }
     993             : 
     994             : /*
     995             :  * dpdk_mbuf_rss_hash - emulate RSS hash for the mbuf.
     996             :  *
     997             :  * Returns:
     998             :  *     0 if hash was not calculated
     999             :  *     1 if hash was calculated.
    1000             :  */
    1001             : static inline int
    1002         148 : dpdk_mbuf_rss_hash(struct rte_mbuf *mbuf, struct vr_ip *ipv4_hdr,
    1003             :                                           struct vr_ip6 *ipv6_hdr)
    1004             : {
    1005             :     uint64_t *ip_addr_ptr;
    1006         148 :     uint32_t *l4_ptr = NULL;
    1007         148 :     uint32_t hash = 0;
    1008             :     unsigned char ip_proto, i;
    1009             : 
    1010         148 :     if (likely(ipv4_hdr != NULL)) {
    1011             :         /**
    1012             :          * Both source and destination IPv4 addresses are 4-bytes long,
    1013             :          * so they can be hashed at once with single 8-byte hashing funcion.
    1014             :          *
    1015             :          * We use SSE4.2 CRC hash. No need to match NIC's Toeplitz hash ATM.
    1016             :          */
    1017         125 :         ip_addr_ptr = (uint64_t *)((uintptr_t)ipv4_hdr +
    1018             :                         offsetof(struct vr_ip, ip_saddr));
    1019         125 :         hash = rte_hash_crc_8byte(*ip_addr_ptr, hash);
    1020             : 
    1021         125 :         if (likely(!vr_ip_fragment(ipv4_hdr))) {
    1022          82 :             ip_proto = ipv4_hdr->ip_proto;
    1023          82 :             l4_ptr = (uint32_t *)((uintptr_t)ipv4_hdr +
    1024          82 :                             (ipv4_hdr->ip_hl) * RTE_IPV4_IHL_MULTIPLIER);
    1025             :         } else {
    1026          43 :             ip_proto = 0;
    1027             :         }
    1028          23 :     } else if (ipv6_hdr != NULL) {
    1029             :         /**
    1030             :          * Both source and destination IPv6 addresses are 16-bytes long,
    1031             :          * and DPDK hashing functions can calculate 8-bytes at once, so hashing
    1032             :          * has to be done in four steps, each address hashed from the beginning
    1033             :          * to the middle, and from the middle to the end. In the header, first
    1034             :          * comes source address, which is followed by destination address. This
    1035             :          * lets us to set the pointer to the beginning of source address and
    1036             :          * move it by 64 bits after hash is calculated.
    1037             :          */
    1038         115 :         for (i = 0; i < 4; i++) {
    1039          92 :             ip_addr_ptr = (uint64_t *)((uintptr_t)ipv6_hdr +
    1040          92 :                             offsetof(struct rte_ipv6_hdr, src_addr) + 8*i);
    1041          92 :             hash = rte_hash_crc_8byte(*ip_addr_ptr, hash);
    1042             :         }
    1043             : 
    1044          23 :         ip_proto = ipv6_hdr->ip6_nxt;
    1045             :          /* In case of extended header L4 is not hashed. */
    1046          23 :         l4_ptr = (uint32_t *)((uintptr_t)ipv6_hdr + sizeof(struct rte_ipv6_hdr));
    1047             :     } else {
    1048           0 :         return 0;
    1049             :     }
    1050             : 
    1051         148 :     switch (ip_proto) {
    1052          22 :     case VR_IP_PROTO_TCP:
    1053          22 :         hash = rte_hash_crc_4byte(*l4_ptr, hash);
    1054          22 :         break;
    1055          27 :     case VR_IP_PROTO_UDP:
    1056          27 :         hash = rte_hash_crc_4byte(*l4_ptr, hash);
    1057          27 :         break;
    1058           0 :     case VR_IP_PROTO_GRE:
    1059           0 :         if (likely(l4_ptr != NULL)) {
    1060           0 :             struct vr_gre_key* gre_hdr = (struct vr_gre_key *)l4_ptr;
    1061             : 
    1062           0 :             if (likely(gre_hdr->gre_comm_hdr.gre_flags & VR_GRE_FLAG_KEY))  {
    1063           0 :                 hash = rte_hash_crc_4byte(gre_hdr->gre_key , hash);
    1064             :             }
    1065             :         }
    1066           0 :         break;
    1067             :     }
    1068             : 
    1069         148 :     mbuf->ol_flags |= PKT_RX_RSS_HASH;
    1070         148 :     mbuf->hash.rss = hash;
    1071             :     RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS hash: 0x%x (emulated)\n",
    1072             :             __func__, mbuf->hash.rss);
    1073             : 
    1074         148 :     return 1;
    1075             : }
    1076             : 
    1077             : /* dpdk_mbuf_parse_and_hash_packets
    1078             :  *
    1079             :  * Parse incoming packet. Check L2, L3 headers, encapsulation type, perform
    1080             :  * TCP MSS adjust if needed, then call hashing function to.
    1081             :  *
    1082             :  * Return:
    1083             :  *   -1 if packet length is too short to contain valid header
    1084             :  *   0 if there is no need to perform hashing (ie. unsupported encap type,
    1085             :  *       packet already hashed)
    1086             :  *   dpdk_mbuf_rss_hash() if hashing is needed. dpdk_mbuf_rss_hash() returns 1
    1087             :  *       if hash was calculated, 0 if not.
    1088             :  *
    1089             :  * TODO: if we ever need to set L4 lengths or packet type flags, or other info
    1090             :  * about received packets, this is a good place to do it.
    1091             :  */
    1092             : static int
    1093         160 : dpdk_mbuf_parse_and_hash_packets(struct rte_mbuf *mbuf)
    1094             : {
    1095         160 :     struct vr_eth *eth_hdr = rte_pktmbuf_mtod(mbuf, struct vr_eth *);
    1096         160 :     struct vr_ip *ipv4_hdr = NULL;
    1097         160 :     struct vr_ip *ipv4_inner_hdr = NULL;
    1098         160 :     struct vr_ip6 *ipv6_hdr = NULL;
    1099         160 :     struct vr_ip6 *ipv6_inner_hdr = NULL;
    1100         160 :     struct vr_udp *udp_hdr = NULL;
    1101         160 :     struct vr_gre *gre_hdr = NULL;
    1102             :     struct rte_vlan_hdr *vlan_hdr;
    1103         160 :     unsigned int pull_len = VR_ETHER_HLEN, ipv4_len;
    1104             :     int encap_type, helper_ret;
    1105         160 :     unsigned short gre_udp_encap = 0, gre_hdr_len = VR_GRE_BASIC_HDR_LEN,
    1106             :                    eth_proto, udp_port;
    1107         160 :     uint16_t mbuf_data_len = rte_pktmbuf_data_len(mbuf);
    1108             : 
    1109         160 :     if (unlikely(mbuf_data_len < pull_len))
    1110           0 :         return -1;
    1111             : 
    1112         160 :     eth_proto = eth_hdr->eth_proto;
    1113             : 
    1114             :     /* Skip VLAN tag. It may be present if we handle tagged packet from VM. */
    1115         160 :     while (eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_VLAN)) {
    1116           0 :         if (unlikely(mbuf_data_len < pull_len + VR_VLAN_HLEN))
    1117           0 :             return -1;
    1118             : 
    1119             :         /* Store the first VLAN TCI for further use. */
    1120           0 :         if (likely((mbuf->ol_flags & PKT_RX_VLAN) == 0)) {
    1121           0 :             vlan_hdr = (struct rte_vlan_hdr *)(eth_hdr + 1);
    1122           0 :             mbuf->ol_flags |= PKT_RX_VLAN;
    1123           0 :             mbuf->vlan_tci = rte_be_to_cpu_16(vlan_hdr->vlan_tci);
    1124             :         }
    1125             : 
    1126           0 :         eth_proto = ((struct vr_vlan_hdr *)((uintptr_t)eth_hdr + pull_len))->vlan_proto;
    1127           0 :         pull_len += VR_VLAN_HLEN;
    1128             :     }
    1129             : 
    1130         160 :     if (likely(eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_IP))) {
    1131         125 :         ipv4_hdr = (struct vr_ip *)((uintptr_t)eth_hdr + pull_len);
    1132             : 
    1133         125 :         if (unlikely(mbuf_data_len < pull_len + sizeof(struct vr_ip)))
    1134           0 :             return -1;
    1135             : 
    1136         125 :         ipv4_len = (ipv4_hdr->ip_hl) * RTE_IPV4_IHL_MULTIPLIER;
    1137         125 :         pull_len += ipv4_len;
    1138             : 
    1139         125 :         if (ipv4_hdr->ip_proto == VR_IP_PROTO_GRE) {
    1140           0 :             gre_hdr = (struct vr_gre *)((uintptr_t)ipv4_hdr + ipv4_len);
    1141             : 
    1142             :             /* Don't do hashing for GRE IP fragments since it may not have 
    1143             :              * the actual GRE header, do regular routing instead */
    1144           0 :             if (unlikely(vr_ip_fragment(ipv4_hdr))) {
    1145           0 :                     return 0;
    1146             :             }
    1147             : 
    1148           0 :             if (unlikely(mbuf_data_len < pull_len + VR_GRE_BASIC_HDR_LEN))
    1149           0 :                 return -1;
    1150             : 
    1151           0 :             if (likely(gre_hdr->gre_proto == VR_GRE_PROTO_MPLS_NO)) {
    1152             :                 /* We are not RFC 1701 compliant receiver. */
    1153           0 :                 if (unlikely(gre_hdr->gre_flags & (~(VR_GRE_FLAG_CSUM |
    1154             :                                                         VR_GRE_FLAG_KEY))))
    1155           0 :                     return 0;
    1156             : 
    1157           0 :                 if (gre_hdr->gre_flags & VR_GRE_FLAG_CSUM) {
    1158           0 :                     gre_hdr_len += (VR_GRE_CKSUM_HDR_LEN -
    1159             :                         VR_GRE_BASIC_HDR_LEN);
    1160             :                 }
    1161           0 :                 if (gre_hdr->gre_flags & VR_GRE_FLAG_KEY) {
    1162           0 :                     gre_hdr_len += (VR_GRE_KEY_HDR_LEN -
    1163             :                         VR_GRE_BASIC_HDR_LEN);
    1164             :                 }
    1165             : 
    1166           0 :                 pull_len += gre_hdr_len;
    1167           0 :                 gre_udp_encap = gre_hdr->gre_proto;
    1168             : 
    1169             :                 /* If ddp enabled, hashing not required */
    1170           0 :                 if (vr_dpdk_get_ddp()) {
    1171           0 :                     mbuf->ol_flags |= PKT_RX_RSS_HASH;
    1172             :                 } else {
    1173             :                     /*
    1174             :                      * mbuf->ol_flags & PKT_RX_RSS_HASH is mistakenly set
    1175             :                      * by the NIC driver for MPLS over GRE packets. It is
    1176             :                      * removed here and will be set after we perform hashing.
    1177             :                      */
    1178           0 :                     mbuf->ol_flags &= ~PKT_RX_RSS_HASH;
    1179             :                 }
    1180             :                 /* Go to parsing. */
    1181             :             } else {
    1182           0 :                 return dpdk_mbuf_rss_hash(mbuf, ipv4_hdr, NULL); /* Looks like GRE, but no MPLS. */
    1183             :             }
    1184         125 :         } else if (ipv4_hdr->ip_proto == VR_IP_PROTO_UDP) {
    1185             :             /* At this point the packet may be:
    1186             :              *  IP with inner packet carried in MPLS-over-UDP, or
    1187             :              *  IP with inner packet carried in VXLAN, or
    1188             :              *  just regular UDP inside IP.
    1189             :              */
    1190          24 :             udp_hdr = (struct vr_udp *)((uintptr_t)ipv4_hdr + ipv4_len);
    1191             : 
    1192          24 :             if (likely(vr_ip_transport_header_valid(ipv4_hdr))) {
    1193          24 :                 if (unlikely(mbuf_data_len < pull_len + sizeof(struct vr_udp)))
    1194           0 :                     return -1;
    1195             :             }
    1196             : 
    1197             :             /*
    1198             :              * If it is a packet from VM, it for sure will not be MPLS-over-UDP,
    1199             :              * so go directly to hashing procedure.
    1200             :              */
    1201             :             /*
    1202             :              * TODO: we can't rely on RSS_HASH flag here, since there might be
    1203             :              * NICs which does not set the flag yet carry MPLSoUDP packets.
    1204             :              *
    1205             :              * Instead we have to check the vif type to make sure the packet is
    1206             :              * from a VM.
    1207             :              */
    1208          24 :             if (unlikely((mbuf->ol_flags & PKT_RX_RSS_HASH) == 0))
    1209          24 :                 return dpdk_mbuf_rss_hash(mbuf, ipv4_hdr, ipv6_hdr);
    1210             : 
    1211           0 :             if (likely(!vr_ip_fragment(ipv4_hdr))) {
    1212           0 :                 udp_port = rte_be_to_cpu_16(udp_hdr->udp_dport);
    1213           0 :                 if (likely(vr_mpls_udp_port(udp_port) || vr_vxlan_udp_port(udp_port))) {
    1214           0 :                     pull_len += sizeof(struct vr_udp);
    1215           0 :                     gre_udp_encap = udp_hdr->udp_dport;
    1216             :                     /* Go to parsing. */
    1217             :                 } else {
    1218             :                     /* UDP from the wire, but not MPLS-over-UDP nor VXLAN. */
    1219           0 :                     return 0;
    1220             :                 }
    1221             :             }
    1222         101 :         } else if ((mbuf->ol_flags & PKT_RX_RSS_HASH) == 0) {
    1223             :             /* Looks like no tunneling, perhaps a packet from a VM. */
    1224         101 :             return dpdk_mbuf_rss_hash(mbuf, ipv4_hdr, ipv6_hdr);
    1225             :         } else {
    1226             :             RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS hash: 0x%x (from NIC)\n",
    1227             :                     __func__, mbuf->hash.rss);
    1228           0 :             return 0; /* Not MPLS-over-GRE, not MPLS-over-UDP, not anything from VM. */
    1229             :         }
    1230             : 
    1231           0 :         helper_ret = vr_inner_pkt_parse(rte_pktmbuf_mtod(mbuf, unsigned char *),
    1232             :                                         vr_mpls_tunnel_type, &encap_type,
    1233           0 :                                         NULL, &pull_len, mbuf->buf_len,
    1234             :                                         &ipv4_inner_hdr, &ipv6_inner_hdr,
    1235           0 :                                         gre_udp_encap, ipv4_hdr->ip_proto);
    1236           0 :         if (helper_ret == PKT_RET_SLOW_PATH)
    1237           0 :             return -1;
    1238           0 :         else if (helper_ret == PKT_RET_UNHANDLED)
    1239           0 :             return 0;
    1240             : 
    1241             :         /* If not inner IPv4 nor IPv6 - nothing to do. */
    1242           0 :         if (unlikely(ipv4_inner_hdr == NULL))
    1243           0 :             return 0; /* Inner IPv6 packets have ipv4_inner_hdr != NULL */
    1244             : 
    1245           0 :         helper_ret = vr_ip_transport_parse(ipv4_inner_hdr, ipv6_inner_hdr,
    1246           0 :                                            NULL, mbuf->buf_len,
    1247             :                                            dpdk_adjust_tcp_mss, NULL, NULL,
    1248             :                                            NULL, &pull_len);
    1249           0 :         if (unlikely(helper_ret == PKT_RET_SLOW_PATH))
    1250           0 :             return -1;
    1251             : 
    1252             :         /* Packet may already be hashed by the NIC */
    1253           0 :         if (mbuf->ol_flags & PKT_RX_RSS_HASH) {
    1254             :             RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS hash: 0x%x (from NIC)\n",
    1255             :                     __func__, mbuf->hash.rss);
    1256           0 :             return 0;
    1257             :         } else {
    1258             :             /* For GRE packets we need to hash inner packet */
    1259           0 :             if (gre_hdr) {
    1260           0 :                 if (ipv6_inner_hdr) {
    1261           0 :                     ipv6_hdr = ipv6_inner_hdr;
    1262           0 :                     ipv4_hdr = NULL;
    1263           0 :                 } else if (ipv4_inner_hdr) {
    1264           0 :                     ipv4_hdr = ipv4_inner_hdr;
    1265             :                 }
    1266             :             }
    1267             :             /* Go to hashing */
    1268             :         }
    1269          35 :     } else if (eth_proto == rte_cpu_to_be_16(VR_ETH_PROTO_IP6)) {
    1270          23 :         ipv6_hdr = (struct vr_ip6 *)((uintptr_t)eth_hdr + pull_len);
    1271             : 
    1272          23 :         if (unlikely(mbuf_data_len < pull_len + sizeof(struct vr_ip6)))
    1273           0 :             return -1;
    1274             : 
    1275             :         /**
    1276             :          * There's no IPv6 as a tunnel between nodes, so it is either a packet
    1277             :          * from VM, or some non-related IPv6 packet from the wire.
    1278             :          */
    1279          23 :         if ((mbuf->ol_flags & PKT_RX_RSS_HASH) == 0) {
    1280          23 :             return dpdk_mbuf_rss_hash(mbuf, ipv4_hdr, ipv6_hdr);
    1281             :         } else {
    1282             :             RTE_LOG_DP(DEBUG, VROUTER, "%s: RSS hash: 0x%x (from NIC)\n",
    1283             :                     __func__, mbuf->hash.rss);
    1284           0 :             return 0;
    1285             :         }
    1286             :     } else {
    1287          12 :         return 0;
    1288             :     }
    1289             : 
    1290           0 :     return dpdk_mbuf_rss_hash(mbuf, ipv4_hdr, ipv6_hdr);
    1291             : }
    1292             : 
    1293             : /*
    1294             :  * vr_dpdk_ethdev_rx_emulate - emulate smart NIC RX:
    1295             :  *  - strip VLAN tags for packets received from fabric interface
    1296             :  *  - calculate RSS hash if not present
    1297             :  *  - recalculate RSS hash for MPLSoGRE packets
    1298             :  *
    1299             :  * Returns 0 on no hash changes, otherwise a bitmask of mbufs to distribute.
    1300             :  */
    1301             : uint64_t
    1302         160 : vr_dpdk_ethdev_rx_emulate(struct vr_interface *vif,
    1303             :     struct rte_mbuf *pkts[VR_DPDK_RX_BURST_SZ], uint32_t *nb_pkts)
    1304             : {
    1305         160 :     uint64_t mask_to_distribute = 0, mask_to_distribute_ret = 0,
    1306         160 :              mask_to_drop = 0;
    1307         160 :     unsigned i, offload_en, nb_pkts_ret = 0;
    1308             :     int ret;
    1309             : 
    1310             :     /* prefetch the mbufs */
    1311         320 :     for (i = 0; i < *nb_pkts; i++) {
    1312         160 :         rte_prefetch0(rte_pktmbuf_mtod(pkts[i], uint8_t *));
    1313         160 :         rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], uint8_t *, RTE_CACHE_LINE_SIZE));
    1314             :     }
    1315             : 
    1316             :     /* emulate VLAN stripping if needed */
    1317         320 :     for (i = 0; i < *nb_pkts; i++) {
    1318         160 :         rte_vlan_strip(pkts[i]);
    1319             :     }
    1320             : 
    1321             :     /* indicate packets from namespace don't have checksum calculated */
    1322         160 :     if (unlikely(vif_is_namespace(vif)))
    1323           0 :         for (i = 0; i < *nb_pkts; i++)
    1324           0 :             pkts[i]->ol_flags |= PKT_RX_IP_CKSUM_BAD;
    1325             : 
    1326         160 :     offload_en = vif_is_fabric(vif) && datapath_offloads;
    1327             :     /* parse packet headers and emulate RSS hash */
    1328         320 :     for (i = 0; i < *nb_pkts; i++) {
    1329             : 
    1330             :         /* datapath offloads calculated the RSS for flow tagged packets */
    1331         160 :         if (!(offload_en && (pkts[i]->ol_flags & PKT_RX_FDIR_ID))) {
    1332         160 :             ret = dpdk_mbuf_parse_and_hash_packets(pkts[i]);
    1333             : 
    1334             :             /* If software load-balancing is not required, continue */
    1335         160 :             if (vr_no_load_balance)
    1336           0 :                 continue;
    1337             : 
    1338             :             /**
    1339             :              * ret:
    1340             :              *     -1 -> packet is invalid and needs to be dropped
    1341             :              *      1 -> packet to be distributed (bit in mask_to_distribute set)
    1342             :              *      0 -> packet to be routed (bit in mask_to_distribute not set)
    1343             :              */
    1344         160 :             if (ret == 1) {
    1345         148 :                 mask_to_distribute |= 1ULL << i;
    1346          12 :             } else if (unlikely(ret == -1)) {
    1347           0 :                 mask_to_drop |= 1ULL << i;
    1348             :             }
    1349             :         }
    1350             :     }
    1351             : 
    1352             :     /**
    1353             :      * Drop invalid packets masked with mask_to_drop and remove them from the
    1354             :      * array. Bits in mask_to_distribute need to be rewritten in order to get
    1355             :      * rid of bits refering to dropped packets.
    1356             :      */
    1357         160 :     if (unlikely(mask_to_drop != 0)) {
    1358           0 :         for (i = 0; i < *nb_pkts; i++) {
    1359           0 :             if (mask_to_drop & (1ULL << i)) {
    1360           0 :                 vr_dpdk_pfree(pkts[i], vif, VP_DROP_PULL);
    1361             :             } else {
    1362           0 :                 pkts[nb_pkts_ret] = pkts[i];
    1363           0 :                 if (mask_to_distribute & (1ULL << i)) {
    1364           0 :                     mask_to_distribute_ret |= 1ULL << nb_pkts_ret;
    1365             :                 }
    1366           0 :                 nb_pkts_ret++;
    1367             :             }
    1368             :         }
    1369             : 
    1370             :         /* Return number of valid packets and update mask_to_distribute */
    1371           0 :         *nb_pkts = nb_pkts_ret;
    1372           0 :         mask_to_distribute = mask_to_distribute_ret;
    1373             :     }
    1374             : 
    1375         160 :     return mask_to_distribute;
    1376             : }

Generated by: LCOV version 1.14