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

            Line data    Source code
       1              : /* Application will run until quit or killed. */
       2              : 
       3              : #include "dpdklibs/EALSetup.hpp"
       4              : #include "logging/Logging.hpp"
       5              : #include "dpdklibs/udp/PacketCtor.hpp"
       6              : #include "dpdklibs/udp/Utils.hpp"
       7              : #include "dpdklibs/arp/ARP.hpp"
       8              : #include "dpdklibs/ipv4_addr.hpp"
       9              : #include "dpdklibs/FlowControl.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              : #include <rte_arp.h>
      18              : 
      19              : #include <sstream>
      20              : #include <stdint.h>
      21              : #include <limits>
      22              : #include <iomanip>
      23              : #include <fstream>
      24              : #include <csignal>
      25              : 
      26              : #include "CLI/App.hpp"
      27              : #include "CLI/Config.hpp"
      28              : #include "CLI/Formatter.hpp"
      29              : 
      30              : #include <fmt/core.h>
      31              : #include <fmt/ranges.h>
      32              : 
      33              : #include <regex>
      34              : 
      35              : using namespace dunedaq;
      36              : using namespace dpdklibs;
      37              : using namespace udp;
      38              : 
      39              : namespace {
      40              :   constexpr int burst_size = 256;
      41              : 
      42              :   std::atomic<int> num_packets = 0;
      43              :   std::atomic<int> num_bytes = 0;
      44              :   std::atomic<int64_t> total_packets = 0;
      45              :   std::atomic<int64_t> failed_packets = 0;
      46              : 
      47              :   std::atomic<int64_t> garps_sent = 0;
      48              : 
      49              : } // namespace ""
      50              : 
      51            0 : void print_arp(struct rte_mbuf *mbuf) {
      52            0 :   struct rte_ether_hdr *eth_hdr;
      53            0 :   struct rte_arp_hdr *arp_hdr;
      54              : 
      55              :   // Get Ethernet header
      56            0 :   eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *);
      57              : 
      58              :   // Check for ARP packet
      59            0 :   if (eth_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
      60              :       // ARP header is directly after Ethernet header
      61            0 :       arp_hdr = (struct rte_arp_hdr *)(eth_hdr + 1);
      62              : 
      63              :       // Convert IPs from network to host byte order
      64            0 :       uint32_t sender_ip = rte_be_to_cpu_32(arp_hdr->arp_data.arp_sip);
      65            0 :       uint32_t target_ip = rte_be_to_cpu_32(arp_hdr->arp_data.arp_tip);
      66              : 
      67            0 :       printf("ARP Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
      68            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[0],
      69            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[1],
      70            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[2],
      71            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[3],
      72            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[4],
      73            0 :              arp_hdr->arp_data.arp_sha.addr_bytes[5]);
      74              : 
      75            0 :       printf("ARP Sender IP: %u.%u.%u.%u\n",
      76              :              (sender_ip >> 24) & 0xFF,
      77            0 :              (sender_ip >> 16) & 0xFF,
      78            0 :              (sender_ip >> 8) & 0xFF,
      79              :              sender_ip & 0xFF);
      80              : 
      81            0 :       printf("ARP Target IP: %u.%u.%u.%u\n",
      82              :              (target_ip >> 24) & 0xFF,
      83            0 :              (target_ip >> 16) & 0xFF,
      84            0 :              (target_ip >> 8) & 0xFF,
      85              :              target_ip & 0xFF);
      86              :   }
      87            0 : }
      88              : 
      89              : 
      90              : static int
      91            0 : lcore_main(struct rte_mempool *mbuf_pool, std::string ip_addr_str)
      92              : {
      93            0 :   uint16_t iface = 0;
      94            0 :   TLOG() << "Launch lcore for interface: " << iface;
      95              : 
      96              :   // IP for ARP
      97              :   // std::string ip_addr_str{"10.73.32.129"};
      98            0 :   TLOG() << "IP address for ARP responses: " << ip_addr_str;
      99            0 :   IpAddr ip_addr(ip_addr_str);
     100            0 :   rte_be32_t ip_addr_bin = ip_address_dotdecimal_to_binary(
     101            0 :     ip_addr.addr_bytes[0],
     102            0 :     ip_addr.addr_bytes[1],
     103            0 :     ip_addr.addr_bytes[2],
     104            0 :     ip_addr.addr_bytes[3]
     105              :   );
     106              : 
     107            0 :   struct rte_mbuf **tx_bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
     108            0 :   rte_pktmbuf_alloc_bulk(mbuf_pool, tx_bufs, burst_size);
     109              : 
     110            0 :   auto stats = std::thread([&]() {
     111            0 :     while (true) {
     112            0 :       TLOG() << "Packets/s: " << num_packets << " Bytes/s: " << num_bytes << " Total packets: " << total_packets << " Failed packets: " << failed_packets;
     113            0 :       num_packets.exchange(0);
     114            0 :       num_bytes.exchange(0);
     115              : 
     116              :       //arp::pktgen_send_garp(tx_bufs[0], iface, ip_addr_bin);
     117              :       //++garps_sent;
     118              : 
     119            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
     120            0 :     }
     121            0 :   });
     122              : 
     123            0 :   struct rte_mbuf **bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
     124            0 :   rte_pktmbuf_alloc_bulk(mbuf_pool, bufs, burst_size);
     125              : 
     126              :   bool once = true; // one shot variable
     127            0 :   while (true) {
     128            0 :     const uint16_t nb_rx = rte_eth_rx_burst(iface, 0, bufs, burst_size);
     129            0 :     if (nb_rx != 0) {
     130            0 :       num_packets += nb_rx;
     131              :       // Iterate on burst packets
     132            0 :       for (int i_b=0; i_b<nb_rx; ++i_b) {
     133            0 :         num_bytes += bufs[i_b]->pkt_len;
     134              : 
     135              :         // Check for segmentation
     136            0 :         if (bufs[i_b]->nb_segs > 1) {
     137            0 :             TLOG() << "It appears a packet is spread across more than one receiving buffer;"
     138            0 :                    << " there's currently no logic in this program to handle this";
     139              :         }
     140              : 
     141              :         // Check packet type
     142            0 :         auto pkt_type = bufs[i_b]->packet_type;
     143              :         //// Handle non IPV4 packets
     144            0 :         if (not RTE_ETH_IS_IPV4_HDR(pkt_type)) {
     145            0 :           TLOG() << "Non-Ethernet packet type: " << (unsigned)pkt_type;
     146            0 :           if (pkt_type == RTE_PTYPE_L2_ETHER_ARP) {
     147            0 :             TLOG() << "ARP request detected!";
     148              :             
     149            0 :             rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     150              :             // print_arp(bufs[i_b]);
     151              : 
     152              : 
     153              : 
     154              : 
     155            0 :             arp::pktgen_process_arp(bufs[i_b], 0, ip_addr_bin);
     156            0 :           } else if (pkt_type == RTE_PTYPE_L2_ETHER_LLDP) {
     157            0 :             TLOG() << "TODO: Handle LLDP packet!";
     158              :             //rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     159              :           } else {
     160            0 :             TLOG() << "Unidentified! Dumping...";
     161            0 :             rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
     162              :           }
     163            0 :           continue;
     164            0 :         }
     165              :       }
     166            0 :       rte_pktmbuf_free_bulk(bufs, nb_rx);
     167              :     }
     168              :   } // main loop
     169              : 
     170              : 
     171              :   return 0;
     172            0 : }
     173              : 
     174              : int
     175            0 : main(int argc, char* argv[])
     176              : {  
     177              : 
     178            0 :   uint16_t iface_id = 0;
     179            0 :   std::string ip_address;
     180            0 :   std::vector<std::string> pcie_addresses;
     181              : 
     182            0 :   CLI::App app{"test arp responses"};
     183            0 :   app.add_option("-a,--ip-address", ip_address, "IP Addresses");
     184            0 :   app.add_option("-m,--pcie-mask", pcie_addresses, "PCIE Addresses device mask");
     185            0 :   app.add_option("-i,--iface", iface_id, "Interface to init");
     186              : 
     187            0 :   CLI11_PARSE(app, argc, argv);
     188              : 
     189              :   // Validate arguments
     190            0 :   fmt::print("ip      : {}\n", ip_address);
     191            0 :   fmt::print("pcies   : {}\n", fmt::join(pcie_addresses," | "));
     192              : 
     193            0 :   std::regex re_ipv4("[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}");
     194            0 :   std::regex re_pcie("^0{0,4}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}.[0-9]$");
     195              : 
     196              :   // bool all_ip_ok = true;
     197              :   // for( const auto& ip: garp_ip_addresses) {
     198              :   //     bool ip_ok = std::regex_match(ip, re_ipv4);
     199              :   //     fmt::print("- {} {}\n", ip, ip_ok);
     200              :   //     all_ip_ok &= ip_ok;
     201              :   // }
     202              : 
     203            0 :   bool ip_ok = std::regex_match(ip_address, re_ipv4);
     204            0 :   fmt::print("IP address {} {}\n", ip_address, ip_ok);
     205              : 
     206              : 
     207            0 :   fmt::print("PCIE addresses\n");
     208            0 :   bool all_pcie_ok = true;
     209            0 :   for( const auto& pcie: pcie_addresses) {
     210            0 :       bool pcie_ok = std::regex_match(pcie, re_pcie);
     211            0 :       fmt::print("- {} {}\n", pcie, pcie_ok);
     212            0 :       all_pcie_ok &= pcie_ok;
     213              :   }
     214              : 
     215            0 :   if (!ip_ok or !all_pcie_ok) {
     216              :       return -1;
     217              :   }
     218              : 
     219            0 :   std::vector<std::string> eal_args;
     220            0 :   eal_args.push_back("dpdklibds_test_garp");
     221            0 :   for( const auto& pcie: pcie_addresses) {
     222            0 :       eal_args.push_back("-a");
     223            0 :       eal_args.push_back(pcie);
     224              :   }
     225            0 :   dunedaq::dpdklibs::ealutils::init_eal(eal_args);
     226              : 
     227            0 :   auto n_ifaces = rte_eth_dev_count_avail();
     228            0 :   fmt::print("# of available ifaces: {}\n", n_ifaces);
     229            0 :   if (n_ifaces == 0){
     230            0 :       std::cout << "WARNING: no available ifaces. exiting...\n";
     231            0 :       rte_eal_cleanup();
     232              :       return 1;
     233              :   }
     234              : 
     235              :   // int ret = rte_eal_init(argc, argv);
     236              :   // if (ret < 0) {
     237              :   //   rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
     238              :   // }
     239              : 
     240              :   // Iface ID and its queue numbers
     241            0 :   const uint16_t rx_qs = 1;
     242            0 :   const uint16_t tx_qs = 1;
     243            0 :   const uint16_t rx_ring_size = 1024;
     244            0 :   const uint16_t tx_ring_size = 1024;
     245              :   // Get pool
     246            0 :   std::map<int, std::unique_ptr<rte_mempool>> mbuf_pools;
     247            0 :   TLOG() << "Allocating pool";
     248            0 :   for (unsigned p_i = 0; p_i<rx_qs; ++p_i) {
     249            0 :     std::ostringstream ss;
     250            0 :     ss << "MBP-" << p_i;
     251            0 :     mbuf_pools[p_i] = ealutils::get_mempool(ss.str());
     252            0 :   }
     253              : 
     254              :   // Setup interface
     255            0 :   auto nb_ifaces = rte_eth_dev_count_avail();
     256            0 :   TLOG() << "# of available interfaces: " << nb_ifaces;
     257            0 :   TLOG() << "Initialize interface " << iface_id;
     258            0 :   ealutils::iface_init(iface_id, rx_qs, tx_qs, rx_ring_size, tx_ring_size, mbuf_pools);
     259            0 :   ealutils::iface_promiscuous_mode(iface_id, true); // should come from config
     260              : 
     261              :   // Flow steering setup
     262            0 :   TLOG() << "Configuring Flow steering rules for iface=" << iface_id;
     263            0 :   struct rte_flow_error error;
     264            0 :   struct rte_flow *flow;
     265            0 :   TLOG() << "Attempt to flush previous flow rules...";
     266            0 :   rte_flow_flush(iface_id, &error);
     267            0 :   TLOG() << "Create control flow rules (ARP).";
     268              : 
     269            0 :   flow = generate_arp_flow(iface_id, 0, &error);
     270            0 :   if (not flow) { // ers::fatal
     271            0 :     TLOG() << "Flow can't be created for ARP queue=0"
     272            0 :            << " Error type: " << (unsigned)error.type
     273            0 :            << " Message: " << error.message;
     274            0 :     return 1;
     275              :   }
     276              : 
     277              :   // Launch lcores
     278            0 :   lcore_main(mbuf_pools[0].get(), ip_address);
     279              : 
     280              :   // Cleanup
     281              :   TLOG() << "EAL cleanup...";
     282              :   ealutils::wait_for_lcores();
     283              :   rte_eal_cleanup();
     284              :   
     285              :   return 0;
     286            0 : }
        

Generated by: LCOV version 2.0-1