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