Line data Source code
1 : /**
2 : * @file Utils.cpp UDP related utility functions' implementations
3 : *
4 : * This is part of the DUNE DAQ , copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 : #include "dpdklibs/udp/Utils.hpp"
9 :
10 : #include "detdataformats/DAQEthHeader.hpp"
11 : #include "logging/Logging.hpp"
12 : #include "datahandlinglibs/DataHandlingIssues.hpp"
13 :
14 : #include <algorithm>
15 : #include <cstring>
16 : #include <fstream>
17 : #include <iomanip>
18 : #include <iterator>
19 : #include <sstream>
20 : #include <string>
21 : #include <utility>
22 : #include <vector>
23 :
24 : namespace dunedaq {
25 : namespace dpdklibs {
26 : namespace udp {
27 :
28 : std::uint16_t
29 0 : get_payload_size_udp_hdr(struct rte_udp_hdr* udp_hdr)
30 : {
31 0 : return rte_be_to_cpu_16(udp_hdr->dgram_len) - sizeof(struct rte_udp_hdr);
32 : }
33 :
34 : std::uint16_t
35 0 : get_payload_size(struct ipv4_udp_packet_hdr* ipv4_udp_hdr)
36 : {
37 0 : return rte_be_to_cpu_16(ipv4_udp_hdr->udp_hdr.dgram_len) - sizeof(struct rte_udp_hdr);
38 : }
39 :
40 : rte_be32_t
41 0 : ip_address_dotdecimal_to_binary(std::uint8_t byte1, std::uint8_t byte2, std::uint8_t byte3, std::uint8_t byte4)
42 : {
43 0 : rte_le32_t ip_address = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
44 0 : return rte_cpu_to_be_32(ip_address);
45 : }
46 :
47 : struct ipaddr
48 0 : ip_address_binary_to_dotdecimal(rte_le32_t binary_ipv4_address)
49 : {
50 0 : struct ipaddr addr;
51 0 : memcpy(&addr, &binary_ipv4_address, sizeof(rte_le32_t));
52 0 : return addr;
53 : }
54 :
55 : std::string
56 0 : get_ipv4_decimal_addr_str(struct ipaddr ipv4_address)
57 : {
58 0 : std::ostringstream ostrs;
59 0 : ostrs << (unsigned)ipv4_address.addr_bytes[3] << '.' << (unsigned)ipv4_address.addr_bytes[2] << '.' << (unsigned)ipv4_address.addr_bytes[1] << '.' << (unsigned)ipv4_address.addr_bytes[0];
60 0 : return ostrs.str();
61 : /*printf("%i.%i.%i.%i",
62 : ipv4_address.addr_bytes[3],
63 : ipv4_address.addr_bytes[2],
64 : ipv4_address.addr_bytes[1],
65 : ipv4_address.addr_bytes[0]);
66 : */
67 0 : }
68 :
69 : char*
70 0 : get_udp_payload(const rte_mbuf* mbuf)
71 : {
72 0 : struct ipv4_udp_packet_hdr* udp_packet = rte_pktmbuf_mtod(mbuf, struct ipv4_udp_packet_hdr*);
73 : // dump_udp_header(udp_packet);
74 : // uint16_t payload_size = get_payload_size(udp_packet);
75 0 : char* payload = (char*)(udp_packet + 1);
76 0 : return payload;
77 :
78 : /*
79 : if (dump_mode == 10) {
80 : return payload;
81 : }
82 :
83 : if (dump_mode == 0 || dump_mode == 3) {
84 : printf("UDP Payload size: %i\n", payload_size);
85 : uint byte;
86 : for (byte = 0; byte < payload_size; byte++) {
87 : printf("%02x ", *(payload + byte) & 0xFF);
88 : //printf("%s", (payload + byte));
89 : }
90 : printf("\n");
91 : }
92 :
93 : if (dump_mode == 1 || dump_mode == 3) {
94 : printf("%s\n", payload);
95 : }
96 : return payload;
97 : */
98 : }
99 :
100 : inline void
101 0 : hex_digits_to_stream(std::ostringstream& ostrs, int value, char separator = ':', char fill = '0', int digits = 2)
102 : {
103 0 : ostrs << std::setfill(fill) << std::setw(digits) << std::hex << value << std::dec << separator;
104 0 : }
105 :
106 : std::string
107 : // dump_udp_header(struct ipv4_udp_packet_hdr * pkt)
108 0 : get_udp_header_str(struct rte_mbuf* mbuf)
109 : {
110 0 : struct ipv4_udp_packet_hdr* pkt = rte_pktmbuf_mtod(mbuf, struct ipv4_udp_packet_hdr*);
111 0 : std::ostringstream ostrs;
112 0 : ostrs << "\n------ start of packet ----- \n";
113 0 : ostrs << "dst mac addr: ";
114 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[0]);
115 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[1]);
116 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[2]);
117 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[3]);
118 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[4]);
119 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.dst_addr.addr_bytes[5], '\n');
120 0 : ostrs << "src mac addr: ";
121 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[0]);
122 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[1]);
123 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[2]);
124 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[3]);
125 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[4]);
126 0 : hex_digits_to_stream(ostrs, (int)pkt->eth_hdr.src_addr.addr_bytes[5], '\n');
127 0 : ostrs << "ethtype: " << (unsigned)pkt->eth_hdr.ether_type << '\n';
128 :
129 0 : ostrs << "------ IP header ----- \n";
130 0 : ostrs << "ipv4 version: " << (unsigned)pkt->ipv4_hdr.version_ihl << '\n';
131 0 : ostrs << "ipv4 type_of_service: " << (unsigned)pkt->ipv4_hdr.type_of_service << '\n';
132 0 : ostrs << "ipv4 total lenght: " << (unsigned)rte_be_to_cpu_16(pkt->ipv4_hdr.total_length) << '\n';
133 0 : ostrs << "ipv4 packet_id: " << (unsigned)pkt->ipv4_hdr.packet_id << '\n';
134 0 : ostrs << "ipv4 fragment_offset: " << (unsigned)pkt->ipv4_hdr.fragment_offset << '\n';
135 0 : ostrs << "ipv4 time_to_live: " << (unsigned)pkt->ipv4_hdr.time_to_live << '\n';
136 0 : ostrs << "ipv4 next_proto_id: " << (unsigned)pkt->ipv4_hdr.next_proto_id << '\n';
137 0 : ostrs << "ipv4 checksum: " << (unsigned)rte_be_to_cpu_16(pkt->ipv4_hdr.hdr_checksum) << '\n';
138 0 : std::string srcaddr = get_ipv4_decimal_addr_str(ip_address_binary_to_dotdecimal(rte_be_to_cpu_32(pkt->ipv4_hdr.src_addr)));
139 0 : std::string dstaddr = get_ipv4_decimal_addr_str(ip_address_binary_to_dotdecimal(rte_be_to_cpu_32(pkt->ipv4_hdr.dst_addr)));
140 0 : ostrs << "src_addr: " << srcaddr << '\n';
141 0 : ostrs << "dst_addr: " << dstaddr << '\n';
142 :
143 0 : ostrs << "------ UDP header ----- \n";
144 0 : ostrs << "UDP src_port: " << (unsigned)rte_be_to_cpu_16(pkt->udp_hdr.src_port) << '\n';
145 0 : ostrs << "UDP dst_port: " << (unsigned)rte_be_to_cpu_16(pkt->udp_hdr.dst_port) << '\n';
146 0 : ostrs << "UDP len: " << (unsigned)rte_be_to_cpu_16(pkt->udp_hdr.dgram_len) << '\n';
147 0 : ostrs << "UDP checksum: " << (unsigned)rte_be_to_cpu_16(pkt->udp_hdr.dgram_cksum) << '\n';
148 :
149 0 : return ostrs.str();
150 0 : }
151 :
152 : std::string
153 0 : get_udp_packet_str(struct rte_mbuf* mbuf)
154 : {
155 0 : struct ipv4_udp_packet_hdr* pkt = rte_pktmbuf_mtod(mbuf, struct ipv4_udp_packet_hdr*);
156 0 : char* payload = (char*)(pkt);
157 0 : std::ostringstream ostrs;
158 : std::uint8_t byte;
159 0 : for (byte = 0; byte < rte_be_to_cpu_16(pkt->udp_hdr.dgram_len); byte++) {
160 0 : hex_digits_to_stream(ostrs, (unsigned)(*(payload + byte)), ' ');
161 : // printf("%02x ", *(payload + byte) & 0xFF);
162 : // printf("%s", (payload + byte));
163 : }
164 0 : return ostrs.str();
165 0 : }
166 :
167 : void
168 2 : add_file_contents_to_vector(const std::string& filename, std::vector<char>& buffervec)
169 : {
170 :
171 2 : char byte = 0x0;
172 :
173 2 : std::ifstream packetfile;
174 2 : packetfile.open(filename, std::ios::binary);
175 :
176 2 : if (!packetfile) {
177 0 : throw ::dunedaq::datahandlinglibs::CannotOpenFile(ERS_HERE, filename);
178 : }
179 :
180 228 : while (packetfile.get(byte)) {
181 226 : buffervec.push_back(byte);
182 : }
183 :
184 2 : packetfile.close();
185 2 : }
186 :
187 : std::vector<std::pair<const void*, int>>
188 5 : get_ethernet_packets(const std::vector<char>& buffervec)
189 : {
190 :
191 5 : std::vector<std::pair<const void*, int>> ethernet_packets;
192 5 : const std::vector<uint16_t> allowed_ethertypes{ 0x0800, 0x0806 };
193 :
194 10 : for (int byte_index = 0; byte_index < buffervec.size();) {
195 7 : const auto buf_ptr = &buffervec.at(byte_index);
196 7 : auto hdr = reinterpret_cast<const ipv4_udp_packet_hdr*>(buf_ptr);
197 :
198 : // A sanity check
199 7 : bool match = false;
200 9 : for (auto allowed_ethertype : allowed_ethertypes) {
201 8 : if (hdr->eth_hdr.ether_type == rte_be_to_cpu_16(allowed_ethertype)) {
202 : match = true;
203 : break;
204 : }
205 : }
206 :
207 7 : if (!match) {
208 1 : std::stringstream msgstr;
209 1 : msgstr << "Ether type in ethernet header (value " << std::hex << rte_be_to_cpu_16(hdr->eth_hdr.ether_type) << std::dec << ") either unknown or unsupported";
210 1 : throw dunedaq::dpdklibs::BadPacketHeaderIssue(ERS_HERE, msgstr.str());
211 1 : }
212 :
213 6 : int ipv4_packet_size = rte_be_to_cpu_16(hdr->ipv4_hdr.total_length);
214 6 : constexpr int min_packet_size = sizeof(rte_ipv4_hdr) + sizeof(rte_udp_hdr);
215 6 : constexpr int max_packet_size = 10000;
216 :
217 6 : if (ipv4_packet_size < min_packet_size || ipv4_packet_size > max_packet_size) {
218 1 : std::stringstream msgstr;
219 1 : msgstr << "Calculated IPv4 packet size of " << ipv4_packet_size << " bytes is out of the required range of (" << min_packet_size << ", " << max_packet_size << ") bytes";
220 1 : throw dunedaq::dpdklibs::BadPacketHeaderIssue(ERS_HERE, msgstr.str());
221 1 : }
222 :
223 5 : int ethernet_packet_size = sizeof(rte_ether_hdr) + ipv4_packet_size;
224 5 : ethernet_packets.emplace_back(std::pair<const void*, int>{ buf_ptr, ethernet_packet_size });
225 5 : byte_index += ethernet_packet_size;
226 : }
227 :
228 3 : return ethernet_packets;
229 7 : }
230 :
231 : void
232 0 : set_daqethheader_test_values(detdataformats::DAQEthHeader& daqethheader_obj) noexcept
233 : {
234 0 : daqethheader_obj.version = 0;
235 0 : daqethheader_obj.det_id = 1;
236 0 : daqethheader_obj.crate_id = 2;
237 0 : daqethheader_obj.slot_id = 3;
238 0 : daqethheader_obj.stream_id = 4;
239 0 : daqethheader_obj.reserved = 5;
240 0 : daqethheader_obj.seq_id = 6;
241 0 : daqethheader_obj.block_length = 7;
242 0 : daqethheader_obj.timestamp = 8;
243 0 : }
244 :
245 : std::string
246 0 : get_rte_mbuf_str(const rte_mbuf* mbuf) noexcept
247 : {
248 0 : std::stringstream ss;
249 :
250 0 : ss << "\nrte_mbuf info:";
251 0 : ss << "\npkt_len: " << mbuf->pkt_len;
252 0 : ss << "\ndata_len: " << mbuf->data_len;
253 0 : ss << "\nBuffer address: " << std::hex << mbuf->buf_addr;
254 0 : ss << "\nRef count: " << std::dec << rte_mbuf_refcnt_read(mbuf);
255 0 : ss << "\nport: " << mbuf->port;
256 0 : ss << "\nol_flags: " << std::hex << mbuf->ol_flags;
257 0 : ss << "\npacket_type: " << std::dec << mbuf->packet_type;
258 0 : ss << "\nl2 type: " << static_cast<int>(mbuf->l2_type);
259 0 : ss << "\nl3 type: " << static_cast<int>(mbuf->l3_type);
260 0 : ss << "\nl4 type: " << static_cast<int>(mbuf->l4_type);
261 0 : ss << "\ntunnel type: " << static_cast<int>(mbuf->tun_type);
262 0 : ss << "\nInner l2 type: " << static_cast<int>(mbuf->inner_l2_type);
263 0 : ss << "\nInner l3 type: " << static_cast<int>(mbuf->inner_l3_type);
264 0 : ss << "\nInner l4 type: " << static_cast<int>(mbuf->inner_l4_type);
265 0 : ss << "\nbuf_len: " << mbuf->buf_len;
266 0 : ss << "\nl2_len: " << mbuf->l2_len;
267 0 : ss << "\nl3_len: " << mbuf->l3_len;
268 0 : ss << "\nl4_len: " << mbuf->l4_len;
269 0 : ss << "\nouter_l2_len: " << mbuf->outer_l2_len;
270 0 : ss << "\nouter_l3_len: " << mbuf->outer_l3_len;
271 0 : ss << std::dec;
272 :
273 0 : return ss.str();
274 0 : }
275 :
276 : std::string
277 0 : get_opmon_string(const StreamUID& sid)
278 : {
279 0 : std::stringstream opmonstr;
280 0 : opmonstr << "det" << sid.det_id << "_crt" << sid.crate_id << "_slt" << sid.slot_id << "_str" << sid.stream_id;
281 0 : return opmonstr.str();
282 0 : }
283 :
284 : } // namespace udp
285 : } // namespace dpdklibs
286 : } // namespace dunedaq
|