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

Generated by: LCOV version 2.0-1