DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
WIBEthPacketBuilder.cpp
Go to the documentation of this file.
1
5
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
22
23rte_be32_t
24parse_ipv4_addr(const std::string& addr)
25{
26 in_addr parsed{};
27 if (inet_pton(AF_INET, addr.c_str(), &parsed) != 1) {
28 throw std::runtime_error("Invalid IPv4 address: " + addr);
29 }
30 return static_cast<rte_be32_t>(parsed.s_addr);
31}
32
33void
34patch_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.
40 std::memcpy(&daq_header, wibeth_frame, sizeof(daq_header));
41 if (patch.set_det_id) {
42 daq_header.det_id = patch.det_id;
43 }
44 if (patch.set_seq_id) {
45 daq_header.seq_id = patch.seq_id % 4096;
46 }
47 if (patch.force_block_length) {
49 }
50 std::memcpy(wibeth_frame, &daq_header, sizeof(daq_header));
51}
52
53void
54construct_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.
62
63 header.eth_hdr.dst_addr = cfg.dst_mac;
64 header.eth_hdr.src_addr = cfg.src_mac;
65 header.eth_hdr.ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
66
67 header.ipv4_hdr.version_ihl = (4 << 4) | (kIPv4HeaderBytes / 4);
68 header.ipv4_hdr.type_of_service = 0;
69 header.ipv4_hdr.total_length = rte_cpu_to_be_16(static_cast<std::uint16_t>(kIPv4TotalBytes));
70 header.ipv4_hdr.packet_id = rte_cpu_to_be_16(cfg.packet_id);
71 header.ipv4_hdr.fragment_offset = rte_cpu_to_be_16(0);
72 header.ipv4_hdr.time_to_live = 64;
73 header.ipv4_hdr.next_proto_id = IPPROTO_UDP;
74 header.ipv4_hdr.hdr_checksum = 0;
75 header.ipv4_hdr.src_addr = cfg.src_ip;
76 header.ipv4_hdr.dst_addr = cfg.dst_ip;
77 header.ipv4_hdr.hdr_checksum = rte_ipv4_cksum(&header.ipv4_hdr);
78
79 header.udp_hdr.src_port = rte_cpu_to_be_16(cfg.src_port);
80 header.udp_hdr.dst_port = rte_cpu_to_be_16(cfg.dst_port);
81 header.udp_hdr.dgram_len = rte_cpu_to_be_16(static_cast<std::uint16_t>(kUDPDatagramBytes));
82 header.udp_hdr.dgram_cksum = 0;
83
84 std::memcpy(ethernet_packet, &header, kPacketHeaderBytes);
85
86 auto* frame = static_cast<std::uint8_t*>(ethernet_packet) + kPacketHeaderBytes;
87 std::memcpy(frame, wibeth_frame, kWIBEthFrameBytes);
88 patch_daq_header(frame, patch);
89}
90
91} // namespace dunedaq::dpdklibs::wibeth
constexpr std::size_t kWIBEthFrameBytes
void construct_packet(void *ethernet_packet, const void *wibeth_frame, const PacketConfig &cfg, const HeaderPatch &patch={})
constexpr std::size_t kPacketHeaderBytes
void patch_daq_header(void *wibeth_frame, const HeaderPatch &patch)
constexpr std::size_t kIPv4HeaderBytes
rte_be32_t parse_ipv4_addr(const std::string &addr)
constexpr std::size_t kIPv4TotalBytes
constexpr std::uint16_t kWIBEthBlockLength
constexpr std::size_t kUDPDatagramBytes
DAQEthHeader is a versioned and unified structure for every FE electronics.