LCOV - code coverage report
Current view: top level - dpdklibs/test/apps - test_dpdk_stats.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 106 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 20 0

            Line data    Source code
       1              : /* Application will run until quit or killed. */
       2              : 
       3              : #include "dpdklibs/EALSetup.hpp"
       4              : #include "dpdklibs/RTEIfaceSetup.hpp"
       5              : #include "logging/Logging.hpp"
       6              : #include "dpdklibs/udp/PacketCtor.hpp"
       7              : #include "dpdklibs/udp/Utils.hpp"
       8              : #include "dpdklibs/arp/ARP.hpp"
       9              : #include "dpdklibs/ipv4_addr.hpp"
      10              : 
      11              : #include <inttypes.h>
      12              : #include <rte_cycles.h>
      13              : #include <rte_eal.h>
      14              : #include <rte_ethdev.h>
      15              : #include <rte_lcore.h>
      16              : #include <rte_mbuf.h>
      17              : 
      18              : #include <sstream>
      19              : #include <stdint.h>
      20              : #include <limits>
      21              : #include <iomanip>
      22              : #include <fstream>
      23              : #include <csignal>
      24              : 
      25              : using namespace dunedaq;
      26              : using namespace dpdklibs;
      27              : using namespace udp;
      28              : 
      29              : namespace {
      30              :   constexpr int burst_size = 256;
      31              : 
      32              :   std::atomic<uint64_t> num_packets = 0;
      33              :   std::atomic<uint64_t> num_bytes = 0;
      34              :   std::atomic<uint64_t> num_errors = 0;
      35              :   std::atomic<uint64_t> num_missed = 0; 
      36              :   std::atomic<uint64_t> num_udp_frames = 0;
      37              :   std::atomic<uint64_t> num_jumbo_frames = 0;
      38              : 
      39              : } // namespace ""
      40              : 
      41              : static int
      42            0 : lcore_main(struct rte_mempool *mbuf_pool)
      43              : {
      44            0 :   uint16_t iface = 0;
      45            0 :   TLOG() << "Launch lcore for interface: " << iface;
      46              : 
      47            0 :   struct rte_mbuf **tx_bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
      48            0 :   rte_pktmbuf_alloc_bulk(mbuf_pool, tx_bufs, burst_size);
      49              : 
      50              :   // Reset internal ETH DEV stat counters.
      51            0 :   rte_eth_stats_reset(iface);
      52            0 :   rte_eth_xstats_reset(iface);
      53              : 
      54              : //////////// RS FIXME -> Copy pasta DPDK Docs, of course the docs are super misleading....
      55            0 :     struct rte_eth_xstat_name *xstats_names;
      56            0 :     uint64_t *xstats_ids;
      57            0 :     uint64_t *values;
      58            0 :     int len, i;
      59              : 
      60              :     // Get number of stats
      61            0 :     len = rte_eth_xstats_get_names_by_id(iface, NULL, NULL, 0);
      62            0 :     if (len < 0) {
      63            0 :         printf("Cannot get xstats count\n");
      64              :     }
      65              : 
      66              :     // Get names of HW registered stat fields
      67            0 :     xstats_names = (rte_eth_xstat_name*)(malloc(sizeof(struct rte_eth_xstat_name) * len));
      68            0 :     if (xstats_names == NULL) {
      69            0 :         printf("Cannot allocate memory for xstat names\n");
      70              :     }
      71              : 
      72              :     // Retrieve xstats names, passing NULL for IDs to return all statistics
      73            0 :     if (len != rte_eth_xstats_get_names(iface, xstats_names, len)) {
      74            0 :         printf("Cannot get xstat names\n");
      75              :     }
      76              : 
      77              :     // Allocate value fields
      78            0 :     values = (uint64_t*)(malloc(sizeof(values) * len));
      79            0 :     if (values == NULL) {
      80            0 :         printf("Cannot allocate memory for xstats\n");
      81              :     }
      82              : 
      83              :     // Getting xstats values (this is that we call in a loop/get_info
      84            0 :     if (len != rte_eth_xstats_get_by_id(iface, NULL, values, len)) {
      85            0 :         printf("Cannot get xstat values\n");
      86              :     }
      87              : 
      88              :     // Print all xstats names and values to be amazed (WOW!)
      89            0 :     for (i = 0; i < len; i++) {
      90            0 :       TLOG() << "Name: " << xstats_names[i].name << " value: " << values[i];
      91              :     }
      92              : 
      93              : /////////////// RS FIXME: Stats thread spawn. Passed with the scope of attrocities above...
      94            0 :   auto stats = std::thread([&]() {
      95              : 
      96              : ///////////// RS FIXME: Simple PMD based stats monitoring is also possible
      97            0 :     struct rte_eth_stats iface_stats;
      98            0 :     while (true) {
      99              :       // RS: poll out dev stats. (SIMPLE MODE)
     100            0 :       rte_eth_stats_get(iface, &iface_stats);
     101            0 :       num_packets = (uint64_t)iface_stats.ipackets;
     102            0 :       num_bytes = (uint64_t)iface_stats.ibytes;
     103            0 :       num_missed = (uint64_t)iface_stats.imissed;
     104            0 :       num_errors = (uint64_t)iface_stats.ierrors;
     105            0 :       TLOG() << " Total packets: " << num_packets
     106            0 :              << " Total bytes: " << num_bytes
     107            0 :              << " Total missed: " << num_missed
     108            0 :              << " Total errors: " << num_errors
     109            0 :              << " Total UDP frames: " << num_udp_frames.exchange(0)
     110            0 :              << " Total JUMBO frames: " << num_jumbo_frames.exchange(0);
     111              :       // Queue based counters doesn't seem to work neither here neither in module... :((((((
     112            0 :       for( unsigned long i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++ ){
     113            0 :         TLOG() << "HW iface queue[" << i << "] received: " << (uint64_t)iface_stats.q_ipackets[i];
     114              :       }
     115              : 
     116              : ////////////// RS FIXME: HW counter based stats monitoring. Fields initialized just before thread spawn.
     117            0 :       if (len != rte_eth_xstats_get_by_id(iface, NULL, values, len)) {
     118            0 :         TLOG() << "Cannot get xstat values!";
     119              :       } else {
     120            0 :         for (i = 0; i < len; i++) {
     121            0 :           TLOG() << "Name: " << xstats_names[i].name << " value: " << values[i];
     122              :         }
     123              :       }
     124            0 :       int reset_res = rte_eth_xstats_reset(iface);
     125            0 :       TLOG() << "Reset notification result: " << reset_res; 
     126              : ////////////// RS FIXME: HW counter based loop ends.
     127              : 
     128            0 :       std::this_thread::sleep_for(std::chrono::seconds(1)); // If we sample for anything other than 1s, the rate calculation will need to change
     129            0 :     }
     130            0 :   });
     131              : 
     132            0 :   struct rte_mbuf **bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
     133            0 :   rte_pktmbuf_alloc_bulk(mbuf_pool, bufs, burst_size);
     134              : 
     135              :   
     136              : 
     137              :   bool once = true; // one shot variable
     138            0 :   while (true) {
     139            0 :     const uint16_t nb_rx = rte_eth_rx_burst(iface, 0, bufs, burst_size);
     140            0 :     if (nb_rx != 0) {
     141            0 :       num_packets += nb_rx;
     142              :       // Iterate on burst packets
     143            0 :       for (int i_b=0; i_b<nb_rx; ++i_b) {
     144            0 :         num_bytes += bufs[i_b]->pkt_len;
     145              : 
     146              :         // Check for segmentation
     147            0 :         if (bufs[i_b]->nb_segs > 1) {
     148            0 :             TLOG() << "It appears a packet is spread across more than one receiving buffer;"
     149            0 :                    << " there's currently no logic in this program to handle this";
     150              :         }
     151              : 
     152              :         // Check packet type
     153            0 :         auto pkt_type = bufs[i_b]->packet_type;
     154              :         //// Handle non IPV4 packets
     155            0 :         if (not RTE_ETH_IS_IPV4_HDR(pkt_type)) {
     156            0 :           TLOG() << "Non-Ethernet packet type: " << (unsigned)pkt_type;
     157            0 :           if (pkt_type == RTE_PTYPE_L2_ETHER_ARP) {
     158            0 :             TLOG() << "TODO: Handle ARP request!";
     159            0 :             rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     160              :             //arp::pktgen_process_arp(bufs[i_b], 0, ip_addr_bin);
     161            0 :           } else if (pkt_type == RTE_PTYPE_L2_ETHER_LLDP) {
     162            0 :             TLOG() << "TODO: Handle LLDP packet!";
     163            0 :             rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     164              :           } else {
     165            0 :             TLOG() << "Unidentified! Dumping...";
     166            0 :             rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     167              :           }
     168            0 :           continue;
     169            0 :         }
     170              : 
     171              :         // Check if frame is UDP. Count them.
     172            0 :         if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
     173            0 :           ++num_udp_frames;
     174              :         }
     175              : 
     176              :         // Check for JUMBO frames (bigger than 1500 Bytes)
     177            0 :         if (bufs[i_b]->pkt_len > 1500) { // RS FIXME: do proper check on data length later 
     178            0 :           ++num_jumbo_frames;
     179              :         }
     180              : 
     181              :       }
     182            0 :       rte_pktmbuf_free_bulk(bufs, nb_rx);
     183              :     }
     184              :   } // main loop
     185              : 
     186              : 
     187              :   return 0;
     188            0 : }
     189              : 
     190              : int
     191            0 : main(int argc, char* argv[])
     192              : {  
     193            0 :   int ret = rte_eal_init(argc, argv);
     194            0 :   if (ret < 0) {
     195            0 :     rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
     196              :   }
     197              : 
     198              :   // Iface ID and its queue numbers
     199            0 :   int iface_id = 0;
     200            0 :   const uint16_t rx_qs = 5;
     201            0 :   const uint16_t tx_qs = 1;
     202            0 :   const uint16_t rx_ring_size = 1024;
     203            0 :   const uint16_t tx_ring_size = 1024;
     204              :   // Get pool
     205            0 :   std::map<int, std::unique_ptr<rte_mempool>> mbuf_pools;
     206            0 :   TLOG() << "Allocating pool";
     207            0 :   for (unsigned p_i = 0; p_i<rx_qs; ++p_i) {
     208            0 :     std::ostringstream ss;
     209            0 :     ss << "MBP-" << p_i;
     210            0 :     mbuf_pools[p_i] = ealutils::get_mempool(ss.str());
     211            0 :   }
     212              : 
     213              :   // Setup interface
     214            0 :   auto nb_ifaces = rte_eth_dev_count_avail();
     215            0 :   TLOG() << "# of available interfaces: " << nb_ifaces;
     216            0 :   TLOG() << "Initialize interface " << iface_id;
     217            0 :   TLOG() << "  -> Iface MAC: " << ifaceutils::get_iface_mac_str(iface_id);
     218            0 :   TLOG() << "  -> Iface PCI: " << ifaceutils::get_iface_pci_str(iface_id);
     219              : 
     220            0 :   ealutils::iface_init(iface_id, rx_qs, tx_qs, rx_ring_size, tx_ring_size, mbuf_pools, false, false);
     221            0 :   ealutils::iface_promiscuous_mode(iface_id, false); // should come from config
     222              : 
     223              :   // Launch lcores
     224            0 :   lcore_main(mbuf_pools[0].get());
     225              : 
     226              :   // Cleanup
     227              :   TLOG() << "EAL cleanup...";
     228              :   ealutils::wait_for_lcores();
     229              :   rte_eal_cleanup();
     230              :   
     231              :   return 0;
     232            0 : }
        

Generated by: LCOV version 2.0-1