Line data Source code
1 : /* Application will run until quit or killed. */
2 :
3 : #include "dpdklibs/EALSetup.hpp"
4 : #include "dpdklibs/arp/ARP.hpp"
5 : #include "dpdklibs/ipv4_addr.hpp"
6 : #include "dpdklibs/udp/PacketCtor.hpp"
7 : #include "dpdklibs/udp/Utils.hpp"
8 : #include "logging/Logging.hpp"
9 :
10 : #include <inttypes.h>
11 : #include <rte_cycles.h>
12 : #include <rte_eal.h>
13 : #include <rte_ethdev.h>
14 : #include <rte_lcore.h>
15 : #include <rte_mbuf.h>
16 :
17 : #include <csignal>
18 : #include <fstream>
19 : #include <iomanip>
20 : #include <limits>
21 : #include <sstream>
22 : #include <stdint.h>
23 :
24 : #include "CLI/App.hpp"
25 : #include "CLI/Config.hpp"
26 : #include "CLI/Formatter.hpp"
27 :
28 : #include <fmt/core.h>
29 : #include <fmt/ranges.h>
30 :
31 : #include <regex>
32 :
33 : using namespace dunedaq;
34 : using namespace dpdklibs;
35 : using namespace udp;
36 :
37 : namespace {
38 : constexpr int burst_size = 256;
39 :
40 : std::atomic<int> num_packets = 0;
41 : std::atomic<int> num_bytes = 0;
42 : std::atomic<int64_t> total_packets = 0;
43 : std::atomic<int64_t> failed_packets = 0;
44 :
45 : std::atomic<int64_t> garps_sent = 0;
46 :
47 : } // namespace ""
48 :
49 : static int
50 0 : lcore_main(struct rte_mempool* mbuf_pool, const std::vector<std::string>& ip_addr_strs)
51 : {
52 0 : uint16_t iface = 0;
53 0 : TLOG() << "Launch lcore for interface: " << iface;
54 :
55 : // IP for ARP
56 : // std::vector<std::string> ip_addr_strs = {
57 : // "10.73.139.26",
58 : // "10.73.139.27"
59 : // };
60 :
61 0 : std::vector<rte_be32_t> ip_addr_bin_vector;
62 0 : for (const auto& ip_addr_str : ip_addr_strs) {
63 0 : TLOG() << "IP address for ARP responses: " << ip_addr_str;
64 0 : IpAddr ip_addr(ip_addr_str);
65 0 : rte_be32_t ip_addr_bin = ip_address_dotdecimal_to_binary(
66 0 : ip_addr.addr_bytes[3], ip_addr.addr_bytes[2], ip_addr.addr_bytes[1], ip_addr.addr_bytes[0]);
67 0 : ip_addr_bin_vector.push_back(ip_addr_bin);
68 : }
69 :
70 0 : struct rte_mbuf** tx_bufs = (rte_mbuf**)malloc(sizeof(struct rte_mbuf*) * burst_size);
71 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, tx_bufs, burst_size);
72 :
73 0 : auto garp = std::thread([&]() {
74 0 : while (true) {
75 0 : TLOG() << "Packets/s: " << num_packets << " Bytes/s: " << num_bytes << " Total packets: " << total_packets
76 0 : << " Failed packets: " << failed_packets;
77 0 : num_packets.exchange(0);
78 0 : num_bytes.exchange(0);
79 :
80 0 : for (const auto& ip_addr_bin : ip_addr_bin_vector) {
81 0 : arp::pktgen_send_garp(tx_bufs[0], iface, ip_addr_bin);
82 0 : ++garps_sent;
83 : }
84 :
85 0 : std::this_thread::sleep_for(
86 0 : std::chrono::seconds(1)); // If we sample for anything other than 1s, the rate calculation will need to change
87 0 : }
88 0 : });
89 :
90 0 : struct rte_mbuf** bufs = (rte_mbuf**)malloc(sizeof(struct rte_mbuf*) * burst_size);
91 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, bufs, burst_size);
92 :
93 : bool once = true; // one shot variable
94 0 : while (true) {
95 0 : const uint16_t nb_rx = rte_eth_rx_burst(iface, 0, bufs, burst_size);
96 0 : if (nb_rx != 0) {
97 0 : num_packets += nb_rx;
98 : // Iterate on burst packets
99 0 : for (int i_b = 0; i_b < nb_rx; ++i_b) {
100 0 : num_bytes += bufs[i_b]->pkt_len;
101 :
102 : // Check for segmentation
103 0 : if (bufs[i_b]->nb_segs > 1) {
104 0 : TLOG() << "It appears a packet is spread across more than one receiving buffer;"
105 0 : << " there's currently no logic in this program to handle this";
106 : }
107 :
108 : // Check packet type
109 0 : auto pkt_type = bufs[i_b]->packet_type;
110 : //// Handle non IPV4 packets
111 0 : if (not RTE_ETH_IS_IPV4_HDR(pkt_type)) {
112 0 : TLOG() << "Non-Ethernet packet type: " << (unsigned)pkt_type;
113 0 : if (pkt_type == RTE_PTYPE_L2_ETHER_ARP) {
114 0 : TLOG() << "TODO: Handle ARP request!";
115 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
116 : // arp::pktgen_process_arp(bufs[i_b], 0, ip_addr_bin);
117 0 : } else if (pkt_type == RTE_PTYPE_L2_ETHER_LLDP) {
118 0 : TLOG() << "TODO: Handle LLDP packet!";
119 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
120 : } else {
121 0 : TLOG() << "Unidentified! Dumping...";
122 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
123 : }
124 0 : continue;
125 0 : }
126 : }
127 0 : rte_pktmbuf_free_bulk(bufs, nb_rx);
128 : }
129 : } // main loop
130 :
131 : return 0;
132 0 : }
133 :
134 : int
135 0 : main(int argc, char* argv[])
136 : {
137 :
138 0 : std::vector<std::string> ip_addresses;
139 0 : std::vector<std::string> pcie_addresses;
140 :
141 0 : CLI::App app{ "test_garp" };
142 0 : app.add_option("-i", ip_addresses, "IP Addresses");
143 0 : app.add_option("-p", pcie_addresses, "PCIE Addresses");
144 0 : CLI11_PARSE(app, argc, argv);
145 :
146 0 : fmt::print("ips : {}\n", fmt::join(ip_addresses, " | "));
147 0 : fmt::print("pcies : {}\n", fmt::join(pcie_addresses, " | "));
148 :
149 0 : std::regex re_ipv4("[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}");
150 0 : std::regex re_pcie("^0{0,4}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}.[0-9]$");
151 :
152 0 : fmt::print("IP addresses\n");
153 0 : bool all_ip_ok = true;
154 0 : for (const auto& ip : ip_addresses) {
155 0 : bool ip_ok = std::regex_match(ip, re_ipv4);
156 0 : fmt::print("- {} {}\n", ip, ip_ok);
157 0 : all_ip_ok &= ip_ok;
158 : }
159 :
160 0 : fmt::print("PCIE addresses\n");
161 0 : bool all_pcie_ok = true;
162 0 : for (const auto& pcie : pcie_addresses) {
163 0 : bool pcie_ok = std::regex_match(pcie, re_pcie);
164 0 : fmt::print("- {} {}\n", pcie, pcie_ok);
165 0 : all_pcie_ok &= pcie_ok;
166 : }
167 :
168 0 : if (!all_ip_ok or !all_pcie_ok) {
169 0 : return -1;
170 : }
171 :
172 0 : std::vector<std::string> eal_args;
173 0 : eal_args.push_back("dpdklibds_test_garp");
174 0 : for (const auto& pcie : pcie_addresses) {
175 0 : eal_args.push_back("-a");
176 0 : eal_args.push_back(pcie);
177 : }
178 :
179 0 : dunedaq::dpdklibs::ealutils::init_eal(eal_args);
180 :
181 : // Iface ID and its queue numbers
182 0 : int iface_id = 0;
183 0 : const uint16_t rx_qs = 1;
184 0 : const uint16_t tx_qs = 1;
185 0 : const uint16_t rx_ring_size = 2048;
186 0 : const uint16_t tx_ring_size = 2048;
187 : // Get pool
188 0 : std::map<int, std::unique_ptr<rte_mempool>> mbuf_pools;
189 0 : TLOG() << "Allocating pool";
190 0 : for (unsigned p_i = 0; p_i < rx_qs; ++p_i) {
191 0 : std::ostringstream ss;
192 0 : ss << "MBP-" << p_i;
193 0 : mbuf_pools[p_i] = ealutils::get_mempool(ss.str());
194 0 : }
195 :
196 : // Setup interface
197 0 : auto nb_ifaces = rte_eth_dev_count_avail();
198 0 : TLOG() << "# of available interfaces: " << nb_ifaces;
199 0 : TLOG() << "Initialize interface " << iface_id;
200 0 : ealutils::iface_init(iface_id, rx_qs, tx_qs, rx_ring_size, tx_ring_size, mbuf_pools);
201 0 : ealutils::iface_promiscuous_mode(iface_id, true); // should come from config
202 :
203 : // Launch lcores
204 0 : lcore_main(mbuf_pools[0].get(), ip_addresses);
205 :
206 : // Cleanup
207 : TLOG() << "EAL cleanup...";
208 : ealutils::wait_for_lcores();
209 : rte_eal_cleanup();
210 :
211 : return 0;
212 0 : }
|