Line data Source code
1 : /**
2 : * @file Utils_test.cxx
3 : *
4 : * Test various utility functions in this package
5 : *
6 : * This is part of the DUNE DAQ Application Framework, copyright 2020.
7 : * Licensing/copyright details are in the COPYING file that you should have
8 : * received with this code.
9 : */
10 :
11 : #include "dpdklibs/udp/Utils.hpp"
12 :
13 : #define BOOST_TEST_MODULE Utils_test // NOLINT
14 :
15 : #include "TRACE/trace.h"
16 : #include "boost/test/unit_test.hpp"
17 :
18 : #include <cstdio>
19 : #include <filesystem>
20 : #include <fstream>
21 : #include <limits>
22 : #include <map>
23 : #include <string>
24 : #include <unordered_map>
25 :
26 : using namespace dunedaq::dpdklibs;
27 :
28 : BOOST_AUTO_TEST_SUITE(Utils_test)
29 :
30 2 : BOOST_AUTO_TEST_CASE(GetEthernetPackets)
31 : {
32 :
33 1 : const std::string tmp_filename = std::tmpnam(nullptr);
34 :
35 : // Construct a fake ethernet packet where the only contents which
36 : // matter are the ether_type (sanity-checked in
37 : // udp::get_ethernet_packets) and ipv4_packet_length (used by
38 : // udp::get_ethernet_packets to determine the next packet). For the
39 : // IPv4 packet length, while two bytes are allocated in the IPv4
40 : // header to describe the size of the IPv4 packet, for the sake of
41 : // simplicity we're only using the lower byte.
42 :
43 1 : const uint8_t ipv4_packet_length = 28; // For the purposes of this test, do not make the length longer than 255!
44 1 : const uint8_t ipv4_packet_length_position = 17; // Comes after a 14-byte ethernet header and three bytes of IPv4 header
45 1 : const uint8_t ether_type = 0x08;
46 :
47 1 : std::vector<uint8_t> fake_ethernet_packet = {
48 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 : ether_type, 0x00,
51 : 0x00, 0x00,
52 : 0x00, ipv4_packet_length,
53 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56 1 : };
57 :
58 1 : BOOST_REQUIRE_EQUAL(fake_ethernet_packet.size(), ipv4_packet_length + sizeof(rte_ether_hdr)); // This is really a test-of-the-test
59 :
60 1 : std::ofstream tmpfile(tmp_filename);
61 1 : BOOST_REQUIRE(tmpfile.is_open());
62 :
63 43 : for (auto& byte : fake_ethernet_packet) {
64 42 : tmpfile << byte;
65 : }
66 1 : tmpfile.close();
67 :
68 1 : std::vector<char> buffervec;
69 1 : udp::add_file_contents_to_vector(tmp_filename, buffervec);
70 1 : BOOST_REQUIRE_EQUAL(fake_ethernet_packet.size(), buffervec.size());
71 :
72 1 : std::vector<std::pair<const void*, int>> packets = udp::get_ethernet_packets(buffervec);
73 :
74 1 : BOOST_REQUIRE_EQUAL(packets.size(), 1);
75 1 : BOOST_REQUIRE_EQUAL(packets[0].second, fake_ethernet_packet.size());
76 :
77 1 : std::vector<uint8_t> fake_ethernet_packet2 = fake_ethernet_packet;
78 1 : const uint8_t payload_size = 100; // Notice I'm careful not to make the IPv4 packet exceed 255 bytes here
79 1 : fake_ethernet_packet2.resize(fake_ethernet_packet2.size() + payload_size, 0xA);
80 1 : fake_ethernet_packet2.at(ipv4_packet_length_position) = fake_ethernet_packet2.at(ipv4_packet_length_position) + payload_size;
81 1 : BOOST_REQUIRE_EQUAL(ipv4_packet_length + payload_size, fake_ethernet_packet2.at(ipv4_packet_length_position));
82 :
83 1 : tmpfile.open(tmp_filename, std::ofstream::app);
84 1 : BOOST_REQUIRE(tmpfile.is_open());
85 :
86 143 : for (auto& byte : fake_ethernet_packet2) {
87 142 : tmpfile << byte;
88 : }
89 1 : tmpfile.close();
90 :
91 1 : buffervec.resize(0);
92 1 : udp::add_file_contents_to_vector(tmp_filename, buffervec);
93 1 : BOOST_REQUIRE_EQUAL(buffervec.size(), fake_ethernet_packet.size() + fake_ethernet_packet2.size());
94 :
95 1 : packets = udp::get_ethernet_packets(buffervec);
96 :
97 1 : BOOST_REQUIRE_EQUAL(packets.size(), 2);
98 1 : BOOST_REQUIRE_EQUAL(packets[0].second, fake_ethernet_packet.size());
99 1 : BOOST_REQUIRE_EQUAL(packets[1].second, fake_ethernet_packet2.size());
100 :
101 1 : BOOST_REQUIRE_EQUAL(buffervec.at( buffervec.size() - 1 ), 0xA);
102 :
103 : // Now some checks that get_ethernet_packets can catch when something goes wrong
104 :
105 1 : auto orig_ipv4_packet_size = buffervec.at(ipv4_packet_length_position);
106 1 : buffervec.at(ipv4_packet_length_position) = 0; // The first packet will now state a length of zero bytes, shorter than is allowed in the function (and in basic logic)
107 :
108 2 : BOOST_CHECK_THROW(udp::get_ethernet_packets(buffervec), dunedaq::dpdklibs::BadPacketHeaderIssue);
109 :
110 : // Restore the valid size of the packet, but now give the ethernet header an invalid ethertype
111 1 : buffervec.at(ipv4_packet_length_position) = orig_ipv4_packet_size;
112 1 : buffervec.at(6 + 6) = 0xAA; // 6 + 6 to account for the two 6-byte MAC addresses past which the ether type byte lives.
113 2 : BOOST_CHECK_THROW(udp::get_ethernet_packets(buffervec), dunedaq::dpdklibs::BadPacketHeaderIssue);
114 :
115 1 : buffervec.at(6 + 6) = ether_type;
116 1 : BOOST_CHECK_NO_THROW(udp::get_ethernet_packets(buffervec)); // Just a quick check that we got things to return to normal
117 :
118 1 : std::filesystem::remove(tmp_filename);
119 1 : }
120 :
121 : BOOST_AUTO_TEST_SUITE_END()
|