LCOV - code coverage report
Current view: top level - dpdklibs/src - EALSetup.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 153 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 31 0

            Line data    Source code
       1              : /**
       2              :  * @file EALSetup.hpp EAL setup functions for DPDK
       3              :  *
       4              :  * This is part of the DUNE DAQ , copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : // #ifndef DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
       9              : // #define DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
      10              : 
      11              : #include "logging/Logging.hpp"
      12              : 
      13              : #include <boost/program_options/parsers.hpp>
      14              : 
      15              : #include "dpdklibs/EALSetup.hpp"
      16              : #include "dpdklibs/Issues.hpp"
      17              : 
      18              : #include <rte_eal.h>
      19              : #include <rte_ethdev.h>
      20              : 
      21              : namespace dunedaq {
      22              : namespace dpdklibs {
      23              : namespace ealutils {
      24              : 
      25              : #define NUM_MBUFS 8191
      26              : #define MBUF_CACHE_SIZE 250
      27              : 
      28              : #define PG_JUMBO_FRAME_LEN (9600 + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN)
      29              : #ifndef RTE_JUMBO_ETHER_MTU
      30              : #define RTE_JUMBO_ETHER_MTU (PG_JUMBO_FRAME_LEN - RTE_ETHER_HDR_LEN - RTE_ETHER_CRC_LEN) /*< Ethernet MTU. */
      31              : #endif
      32              : 
      33              : // static volatile uint8_t dpdk_quit_signal;
      34              : 
      35              : static const struct rte_eth_conf iface_conf_default = {
      36              :   .rxmode = {
      37              :     .mtu = 9000,
      38              :     .max_lro_pkt_size = 9000,
      39              :     //.split_hdr_size = 0, // deprecated in dpdk@22.10
      40              :     .offloads = (RTE_ETH_RX_OFFLOAD_TIMESTAMP 
      41              :                | RTE_ETH_RX_OFFLOAD_IPV4_CKSUM
      42              :                | RTE_ETH_RX_OFFLOAD_UDP_CKSUM),
      43              :   },
      44              : 
      45              :   .txmode = {
      46              :     .offloads = (RTE_ETH_TX_OFFLOAD_MULTI_SEGS),
      47              :   },
      48              : };
      49              : 
      50              : std::string
      51            0 : get_mac_addr_str(const rte_ether_addr& addr)
      52              : {
      53            0 :   std::stringstream macstr;
      54            0 :   macstr << std::hex << static_cast<int>(addr.addr_bytes[0]) << ":" << static_cast<int>(addr.addr_bytes[1]) << ":"
      55            0 :          << static_cast<int>(addr.addr_bytes[2]) << ":" << static_cast<int>(addr.addr_bytes[3]) << ":"
      56            0 :          << static_cast<int>(addr.addr_bytes[4]) << ":" << static_cast<int>(addr.addr_bytes[5]) << std::dec;
      57            0 :   return macstr.str();
      58            0 : }
      59              : 
      60              : // Modifies Ethernet device configuration to multi-queue RSS with offload
      61              : void
      62            0 : iface_conf_rss_mode(struct rte_eth_conf& iface_conf, bool mode, bool offload)
      63              : {
      64            0 :   if (mode) {
      65            0 :     iface_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
      66            0 :     if (offload) {
      67            0 :       iface_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
      68              :     }
      69              :   } else {
      70            0 :     iface_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_NONE;
      71              :   }
      72            0 : }
      73              : 
      74              : // Enables RX in promiscuous mode for the Ethernet device.
      75              : int
      76            0 : iface_promiscuous_mode(std::uint16_t iface, bool mode)
      77              : {
      78            0 :   int retval = -1;
      79            0 :   retval = rte_eth_promiscuous_get(iface);
      80            0 :   TLOG() << "Before modification attempt, promiscuous mode is: " << retval;
      81            0 :   if (mode) {
      82            0 :     retval = rte_eth_promiscuous_enable(iface);
      83              :   } else {
      84            0 :     retval = rte_eth_promiscuous_disable(iface);
      85              :   }
      86            0 :   if (retval != 0) {
      87            0 :     TLOG() << "Couldn't modify promiscuous mode of iface[" << iface << "]! Error code: " << retval;
      88              :   }
      89            0 :   retval = rte_eth_promiscuous_get(iface);
      90            0 :   TLOG() << "New promiscuous mode of iface[" << iface << "] is: " << retval;
      91            0 :   return retval;
      92              : }
      93              : 
      94              : int
      95            0 : iface_init(uint16_t iface,
      96              :            uint16_t rx_rings,
      97              :            uint16_t tx_rings,
      98              :            uint16_t rx_ring_size,
      99              :            uint16_t tx_ring_size,
     100              :            std::map<int, std::unique_ptr<rte_mempool>>& mbuf_pool,
     101              :            bool with_reset,
     102              :            bool with_mq_rss,
     103              :            bool check_link_status)
     104              : {
     105            0 :   struct rte_eth_conf iface_conf = iface_conf_default;
     106            0 :   uint16_t nb_rxd = rx_ring_size;
     107            0 :   uint16_t nb_txd = tx_ring_size;
     108            0 :   int retval = -1;
     109            0 :   uint16_t q;
     110            0 :   struct rte_eth_dev_info dev_info;
     111            0 :   struct rte_eth_txconf txconf;
     112            0 :   struct rte_eth_link link;
     113              : 
     114              :   // Get interface validity
     115            0 :   if (!rte_eth_dev_is_valid_port(iface)) {
     116            0 :     TLOG() << "Specified interface " << iface << " is not valid in EAL!";
     117            0 :     throw InvalidEALPort(ERS_HERE, iface);
     118              :   }
     119              : 
     120              :   // Get interface info
     121            0 :   if ((retval = rte_eth_dev_info_get(iface, &dev_info)) != 0) {
     122            0 :     TLOG() << "Error during getting device (iface " << iface << ") retval: " << retval;
     123            0 :     throw FailedToRetrieveInterfaceInfo(ERS_HERE, iface, retval);
     124              :   }
     125              : 
     126            0 :   TLOG() << "Iface " << iface << " RX Ring info :"
     127            0 :          << " min " << dev_info.rx_desc_lim.nb_min << " max " << dev_info.rx_desc_lim.nb_max << " align "
     128            0 :          << dev_info.rx_desc_lim.nb_align;
     129              : 
     130              :   // Carry out a reset of the interface
     131            0 :   if (with_reset) {
     132            0 :     if ((retval = rte_eth_dev_reset(iface)) != 0) {
     133            0 :       throw FailedToResetInterface(ERS_HERE, iface, retval);
     134              :     }
     135              :   }
     136              : 
     137              :   // Should we configure MQ RSS and offload?
     138            0 :   if (with_mq_rss) {
     139            0 :     iface_conf_rss_mode(iface_conf, true, true); // with_rss, with_offload
     140              :     // RSS
     141            0 :     if ((iface_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) != 0) {
     142            0 :       TLOG() << "Ethdev port config prepared with RX RSS mq_mode!";
     143            0 :       if ((iface_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH) != 0) {
     144            0 :         TLOG() << "Ethdev port config prepared with RX RSS mq_mode with offloading is requested!";
     145              :       }
     146              :     }
     147              :   }
     148              : 
     149            0 :   TLOG() << "Configuring Iface " << iface << " rx rings: " << rx_rings << ", tx rings " << tx_rings;
     150              : 
     151              :   // Configure the Ethernet interface
     152            0 :   if ((retval = rte_eth_dev_configure(iface, rx_rings, tx_rings, &iface_conf)) != 0) {
     153            0 :     throw FailedToConfigureInterface(ERS_HERE, iface, "Device Configuration", retval);
     154              :   }
     155              : 
     156              :   // Set MTU of interface
     157            0 :   rte_eth_dev_set_mtu(iface, RTE_JUMBO_ETHER_MTU);
     158            0 :   {
     159            0 :     uint16_t mtu;
     160            0 :     rte_eth_dev_get_mtu(iface, &mtu);
     161            0 :     TLOG() << "Interface: " << iface << " MTU: " << mtu;
     162              :   }
     163              : 
     164              :   // Set PTYPE parsing. RS FIXME: This function needs to be factorized, with overall better offloading control.
     165              :   // On most Intel and Mellanox drivers, packet_type will automatically be set if:
     166              :   //   - the hardware supports RTE_ETH_RX_OFFLOAD_*PTYPE
     167              :   //   - and ptype RX parsing is enabled in the PMD
     168              :   // Some PMDs require calling:
     169            0 :   rte_eth_dev_set_ptypes(iface, RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK, NULL, 0);
     170              : 
     171              :   // // Adjust RX/TX ring sizes
     172              :   // retval = rte_eth_dev_adjust_nb_rx_tx_desc(iface, &nb_rxd, &nb_txd);
     173              :   // if (retval != 0)
     174              :   //   return retval;
     175              : 
     176            0 :   if ((retval = rte_eth_dev_adjust_nb_rx_tx_desc(iface, &nb_rxd, &nb_txd)) != 0) {
     177            0 :     throw FailedToConfigureInterface(ERS_HERE, iface, "Adjust tx/rx descriptors", retval);
     178              :   }
     179              : 
     180              :   // Allocate and set up RX queues for interface.
     181            0 :   for (q = 0; q < rx_rings; q++) {
     182              :     // retval = rte_eth_rx_queue_setup(iface, q, nb_rxd, rte_eth_dev_socket_id(iface), NULL, mbuf_pool[q].get());
     183            0 :     if ((retval = rte_eth_rx_queue_setup(iface, q, nb_rxd, rte_eth_dev_socket_id(iface), NULL, mbuf_pool[q].get())) <
     184              :         0) {
     185              :       // return retval;
     186            0 :       throw FailedToConfigureInterface(ERS_HERE, iface, "Rx queues setup", retval);
     187              :     }
     188              :   }
     189              : 
     190            0 :   txconf = dev_info.default_txconf;
     191            0 :   txconf.offloads = iface_conf.txmode.offloads;
     192              : 
     193              :   // These values influenced by Sec. 8.4.4 of https://doc.dpdk.org/guides-1.8/prog_guide/poll_mode_drv.html
     194            0 :   txconf.tx_rs_thresh = 32;
     195            0 :   txconf.tx_free_thresh = 32;
     196            0 :   txconf.tx_thresh.wthresh = 0;
     197              : 
     198              :   // Allocate and set up TX queues for interface.
     199            0 :   for (q = 0; q < tx_rings; q++) {
     200            0 :     if ((retval = rte_eth_tx_queue_setup(iface, q, nb_txd, rte_eth_dev_socket_id(iface), &txconf)) < 0) {
     201            0 :       throw FailedToConfigureInterface(ERS_HERE, iface, "Tx queues setup", retval);
     202              :     }
     203              :   }
     204              : 
     205              :   // Start the Ethernet interface.
     206            0 :   if ((retval = rte_eth_dev_start(iface)) < 0) {
     207            0 :     throw FailedToConfigureInterface(ERS_HERE, iface, "MAC address retrival", retval);
     208              :   }
     209              : 
     210            0 :   if ((retval = rte_eth_link_get(iface, &link)) != 0) {
     211            0 :     throw FailedToRetrieveLinkStatus(ERS_HERE, iface, retval);
     212              :   }
     213              : 
     214            0 :   TLOG() << "Link: speed=" << link.link_speed << " duplex=" << link.link_duplex << " autoneg=" << link.link_autoneg
     215            0 :          << " status=" << link.link_status;
     216              : 
     217            0 :   if (check_link_status && link.link_status == 0) {
     218            0 :     throw LinkOffline(ERS_HERE, iface);
     219              :   }
     220              : 
     221              :   // Display the interface MAC address.
     222            0 :   struct rte_ether_addr addr;
     223            0 :   if ((retval = rte_eth_macaddr_get(iface, &addr)) == 0) {
     224            0 :     TLOG() << "MAC address: " << get_mac_addr_str(addr);
     225              :   } else {
     226            0 :     throw FailedToConfigureInterface(ERS_HERE, iface, "MAC address retrival", retval);
     227              :   }
     228              : 
     229              :   // Get interface info
     230            0 :   if ((retval = rte_eth_dev_info_get(iface, &dev_info)) != 0) {
     231            0 :     TLOG() << "Error during getting device (iface " << iface << ") retval: " << retval;
     232            0 :     throw FailedToConfigureInterface(ERS_HERE, iface, "Device information retrival", retval);
     233              :   }
     234              : 
     235            0 :   TLOG() << "Iface[" << iface << "] Rx Ring info:"
     236            0 :          << " min=" << dev_info.rx_desc_lim.nb_min << " max=" << dev_info.rx_desc_lim.nb_max
     237            0 :          << " align=" << dev_info.rx_desc_lim.nb_align;
     238            0 :   TLOG() << "Iface[" << iface << "] Tx Ring info:"
     239            0 :          << " min=" << dev_info.rx_desc_lim.nb_min << " max=" << dev_info.rx_desc_lim.nb_max
     240            0 :          << " align=" << dev_info.rx_desc_lim.nb_align;
     241              : 
     242            0 :   for (size_t j = 0; j < dev_info.nb_rx_queues; j++) {
     243              : 
     244            0 :     struct rte_eth_rxq_info queue_info;
     245            0 :     int count;
     246              : 
     247            0 :     retval = rte_eth_rx_queue_info_get(iface, j, &queue_info);
     248            0 :     if (retval != 0)
     249            0 :       continue;
     250              : 
     251            0 :     count = rte_eth_rx_queue_count(iface, j);
     252            0 :     TLOG() << "rx[" << j << "] descriptors=" << count << "/" << queue_info.nb_desc
     253            0 :            << " scattered=" << (queue_info.scattered_rx ? "yes" : "no")
     254            0 :            << " conf.drop_en=" << (queue_info.conf.rx_drop_en ? "yes" : "no")
     255            0 :            << " conf.rx_deferred_start=" << (queue_info.conf.rx_deferred_start ? "yes" : "no")
     256            0 :            << " rx_buf_size=" << queue_info.rx_buf_size;
     257              :   }
     258              : 
     259            0 :   return 0;
     260              : }
     261              : 
     262              : std::unique_ptr<rte_mempool>
     263            0 : get_mempool(const std::string& pool_name, int num_mbufs, int mbuf_cache_size, int data_room_size, int socket_id)
     264              : {
     265            0 :   TLOG() << "get_mempool with: NUM_MBUFS = " << num_mbufs << " | MBUF_CACHE_SIZE = " << mbuf_cache_size
     266            0 :          << " | data_room_size = " << data_room_size << " | SOCKET_ID = " << socket_id;
     267              : 
     268            0 :   struct rte_mempool* mbuf_pool;
     269            0 :   mbuf_pool = rte_pktmbuf_pool_create(pool_name.c_str(), num_mbufs, mbuf_cache_size, 0, data_room_size, socket_id);
     270              : 
     271            0 :   if (mbuf_pool == NULL) {
     272              :     // ers fatal
     273            0 :     rte_exit(EXIT_FAILURE, "ERROR: Cannot create rte_mempool!\n");
     274              :   }
     275            0 :   return std::unique_ptr<rte_mempool>(mbuf_pool);
     276              : }
     277              : 
     278              : std::vector<const char*>
     279            0 : construct_eal_argv(const std::vector<std::string>& std_argv)
     280              : {
     281            0 :   std::vector<const char*> vec_argv;
     282            0 :   for (int i = 0; i < std_argv.size(); i++) {
     283            0 :     vec_argv.insert(vec_argv.end(), std_argv[i].data());
     284              :   }
     285            0 :   return vec_argv;
     286            0 : }
     287              : 
     288              : void
     289            0 : init_eal(int argc, const char* argv[])
     290              : {
     291              : 
     292            0 :   std::stringstream ss;
     293            0 :   for (size_t i(0); i < argc; ++i) {
     294            0 :     ss << argv[i] << " ";
     295              :   }
     296            0 :   TLOG() << "EAL init arguments: " << ss.str();
     297              : 
     298              :   // Init EAL
     299            0 :   int ret = rte_eal_init(argc, (char**)argv);
     300            0 :   if (ret < 0) {
     301            0 :     rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
     302              :   }
     303            0 :   TLOG() << "EAL initialized with provided parameters.";
     304            0 : }
     305              : 
     306              : void
     307            0 : init_eal(const std::vector<std::string>& args)
     308              : {
     309              : 
     310            0 :   std::vector<const char*> eal_argv = ealutils::construct_eal_argv(args);
     311            0 :   const char** constructed_eal_argv = eal_argv.data();
     312            0 :   int constructed_eal_argc = args.size();
     313            0 :   ealutils::init_eal(constructed_eal_argc, constructed_eal_argv);
     314            0 : }
     315              : 
     316              : int
     317            0 : get_available_ifaces()
     318              : {
     319              :   // Check that there is an even number of interfaces to send/receive on
     320            0 :   unsigned nb_ifaces;
     321            0 :   nb_ifaces = rte_eth_dev_count_avail();
     322            0 :   TLOG() << "Available interfaces: " << nb_ifaces;
     323            0 :   return nb_ifaces;
     324              : }
     325              : 
     326              : int
     327            0 : wait_for_lcores()
     328              : {
     329            0 :   int lcore_id;
     330            0 :   int ret = 0;
     331            0 :   RTE_LCORE_FOREACH_WORKER(lcore_id)
     332              :   {
     333              :     // TLOG() << "Waiting for lcore[" << lcore_id << "] to finish packet processing.";
     334            0 :     ret = rte_eal_wait_lcore(lcore_id);
     335              :   }
     336            0 :   return ret;
     337              : }
     338              : 
     339              : void
     340            0 : finish_eal()
     341              : {
     342            0 :   rte_eal_cleanup();
     343            0 : }
     344              : 
     345              : } // namespace ealutils
     346              : } // namespace dpdklibs
     347              : } // namespace dunedaq
     348              : // #endif // DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
        

Generated by: LCOV version 2.0-1