LCOV - code coverage report
Current view: top level - dpdklibs/src/wibeth - WIBEthPacketBuilder.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 97.6 % 41 40
Test Date: 2026-10-11 15:05:20 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /**
       2              :  * @file WIBEthPacketBuilder.cpp Implementation of the WIBEth packet builder.
       3              :  */
       4              : #include "dpdklibs/wibeth/WIBEthPacketBuilder.hpp"
       5              : 
       6              : #include "detdataformats/DAQEthHeader.hpp"
       7              : 
       8              : #include <rte_byteorder.h>
       9              : #include <rte_ether.h>
      10              : #include <rte_ip.h>
      11              : #include <rte_udp.h>
      12              : 
      13              : #include <arpa/inet.h>
      14              : #include <netinet/in.h>
      15              : 
      16              : #include <cstdint>
      17              : #include <cstring>
      18              : #include <stdexcept>
      19              : #include <string>
      20              : 
      21              : namespace dunedaq::dpdklibs::wibeth {
      22              : 
      23              : rte_be32_t
      24            8 : parse_ipv4_addr(const std::string& addr)
      25              : {
      26            8 :   in_addr parsed{};
      27            8 :   if (inet_pton(AF_INET, addr.c_str(), &parsed) != 1) {
      28            0 :     throw std::runtime_error("Invalid IPv4 address: " + addr);
      29              :   }
      30            8 :   return static_cast<rte_be32_t>(parsed.s_addr);
      31              : }
      32              : 
      33              : void
      34           16 : patch_daq_header(void* wibeth_frame, const HeaderPatch& patch)
      35              : {
      36              :   // The frame is at Ethernet offset 42, which does not satisfy the 8-byte
      37              :   // alignment of DAQEthHeader.  Patch an aligned local copy and copy it back
      38              :   // rather than writing 64-bit bitfields through an unaligned pointer.
      39           16 :   dunedaq::detdataformats::DAQEthHeader daq_header;
      40           16 :   std::memcpy(&daq_header, wibeth_frame, sizeof(daq_header));
      41           16 :   if (patch.set_det_id) {
      42           12 :     daq_header.det_id = patch.det_id;
      43              :   }
      44           16 :   if (patch.set_seq_id) {
      45           12 :     daq_header.seq_id = patch.seq_id % 4096;
      46              :   }
      47           16 :   if (patch.force_block_length) {
      48           15 :     daq_header.block_length = kWIBEthBlockLength;
      49              :   }
      50           16 :   std::memcpy(wibeth_frame, &daq_header, sizeof(daq_header));
      51           16 : }
      52              : 
      53              : void
      54           16 : construct_packet(void* ethernet_packet, const void* wibeth_frame, const PacketConfig& cfg, const HeaderPatch& patch)
      55              : {
      56              :   // Build the 42-byte Ethernet/IPv4/UDP header in a local object and memcpy it
      57              :   // into place.  The destination may have any alignment (mbuf data offset, test
      58              :   // buffer), so caller storage is never written through a typed pointer.
      59              :   // Value-initialization covers the whole object; the packed header type has no
      60              :   // padding.
      61           16 :   dunedaq::dpdklibs::udp::ipv4_udp_packet_hdr header{};
      62              : 
      63           16 :   header.eth_hdr.dst_addr = cfg.dst_mac;
      64           16 :   header.eth_hdr.src_addr = cfg.src_mac;
      65           16 :   header.eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
      66              : 
      67           16 :   header.ipv4_hdr.version_ihl = (4 << 4) | (kIPv4HeaderBytes / 4);
      68           16 :   header.ipv4_hdr.type_of_service = 0;
      69           16 :   header.ipv4_hdr.total_length = rte_cpu_to_be_16(static_cast<std::uint16_t>(kIPv4TotalBytes));
      70           16 :   header.ipv4_hdr.packet_id = rte_cpu_to_be_16(cfg.packet_id);
      71           16 :   header.ipv4_hdr.fragment_offset = rte_cpu_to_be_16(0);
      72           16 :   header.ipv4_hdr.time_to_live = 64;
      73           16 :   header.ipv4_hdr.next_proto_id = IPPROTO_UDP;
      74           16 :   header.ipv4_hdr.hdr_checksum = 0;
      75           16 :   header.ipv4_hdr.src_addr = cfg.src_ip;
      76           16 :   header.ipv4_hdr.dst_addr = cfg.dst_ip;
      77           16 :   header.ipv4_hdr.hdr_checksum = rte_ipv4_cksum(&header.ipv4_hdr);
      78              : 
      79           16 :   header.udp_hdr.src_port = rte_cpu_to_be_16(cfg.src_port);
      80           16 :   header.udp_hdr.dst_port = rte_cpu_to_be_16(cfg.dst_port);
      81           16 :   header.udp_hdr.dgram_len = rte_cpu_to_be_16(static_cast<std::uint16_t>(kUDPDatagramBytes));
      82           16 :   header.udp_hdr.dgram_cksum = 0;
      83              : 
      84           16 :   std::memcpy(ethernet_packet, &header, kPacketHeaderBytes);
      85              : 
      86           16 :   auto* frame = static_cast<std::uint8_t*>(ethernet_packet) + kPacketHeaderBytes;
      87           16 :   std::memcpy(frame, wibeth_frame, kWIBEthFrameBytes);
      88           16 :   patch_daq_header(frame, patch);
      89           16 : }
      90              : 
      91              : } // namespace dunedaq::dpdklibs::wibeth
        

Generated by: LCOV version 2.0-1