Line data Source code
1 : /* Application will run until quit or killed. */
2 :
3 : #include "dpdklibs/EALSetup.hpp"
4 : #include "dpdklibs/FlowControl.hpp"
5 : #include "dpdklibs/arp/ARP.hpp"
6 : #include "dpdklibs/ipv4_addr.hpp"
7 : #include "dpdklibs/udp/PacketCtor.hpp"
8 : #include "dpdklibs/udp/Utils.hpp"
9 : #include "logging/Logging.hpp"
10 :
11 : #include <inttypes.h>
12 : #include <rte_arp.h>
13 : #include <rte_cycles.h>
14 : #include <rte_eal.h>
15 : #include <rte_ethdev.h>
16 : #include <rte_lcore.h>
17 : #include <rte_mbuf.h>
18 :
19 : #include <csignal>
20 : #include <fstream>
21 : #include <iomanip>
22 : #include <limits>
23 : #include <sstream>
24 : #include <stdint.h>
25 :
26 : #include "CLI/App.hpp"
27 : #include "CLI/Config.hpp"
28 : #include "CLI/Formatter.hpp"
29 :
30 : #include <fmt/core.h>
31 : #include <fmt/ranges.h>
32 :
33 : #include <regex>
34 :
35 : using namespace dunedaq;
36 : using namespace dpdklibs;
37 : using namespace udp;
38 :
39 : namespace {
40 : constexpr int burst_size = 256;
41 :
42 : std::atomic<int> num_packets = 0;
43 : std::atomic<int> num_bytes = 0;
44 : std::atomic<int64_t> total_packets = 0;
45 : std::atomic<int64_t> failed_packets = 0;
46 :
47 : std::atomic<int64_t> garps_sent = 0;
48 :
49 : } // namespace ""
50 :
51 : void
52 0 : print_arp(struct rte_mbuf* mbuf)
53 : {
54 0 : struct rte_ether_hdr* eth_hdr;
55 0 : struct rte_arp_hdr* arp_hdr;
56 :
57 : // Get Ethernet header
58 0 : eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
59 :
60 : // Check for ARP packet
61 0 : if (eth_hdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
62 : // ARP header is directly after Ethernet header
63 0 : arp_hdr = (struct rte_arp_hdr*)(eth_hdr + 1);
64 :
65 : // Convert IPs from network to host byte order
66 0 : uint32_t sender_ip = rte_be_to_cpu_32(arp_hdr->arp_data.arp_sip);
67 0 : uint32_t target_ip = rte_be_to_cpu_32(arp_hdr->arp_data.arp_tip);
68 :
69 0 : printf("ARP Sender MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
70 0 : arp_hdr->arp_data.arp_sha.addr_bytes[0],
71 0 : arp_hdr->arp_data.arp_sha.addr_bytes[1],
72 0 : arp_hdr->arp_data.arp_sha.addr_bytes[2],
73 0 : arp_hdr->arp_data.arp_sha.addr_bytes[3],
74 0 : arp_hdr->arp_data.arp_sha.addr_bytes[4],
75 0 : arp_hdr->arp_data.arp_sha.addr_bytes[5]);
76 :
77 0 : printf("ARP Sender IP: %u.%u.%u.%u\n",
78 : (sender_ip >> 24) & 0xFF,
79 0 : (sender_ip >> 16) & 0xFF,
80 0 : (sender_ip >> 8) & 0xFF,
81 : sender_ip & 0xFF);
82 :
83 0 : printf("ARP Target IP: %u.%u.%u.%u\n",
84 : (target_ip >> 24) & 0xFF,
85 0 : (target_ip >> 16) & 0xFF,
86 0 : (target_ip >> 8) & 0xFF,
87 : target_ip & 0xFF);
88 : }
89 0 : }
90 :
91 : static int
92 0 : lcore_main(struct rte_mempool* mbuf_pool, std::string ip_addr_str)
93 : {
94 0 : uint16_t iface = 0;
95 0 : TLOG() << "Launch lcore for interface: " << iface;
96 :
97 : // IP for ARP
98 : // std::string ip_addr_str{"10.73.32.129"};
99 0 : TLOG() << "IP address for ARP responses: " << ip_addr_str;
100 0 : IpAddr ip_addr(ip_addr_str);
101 0 : rte_be32_t ip_addr_bin = ip_address_dotdecimal_to_binary(
102 0 : ip_addr.addr_bytes[0], ip_addr.addr_bytes[1], ip_addr.addr_bytes[2], ip_addr.addr_bytes[3]);
103 :
104 0 : struct rte_mbuf** tx_bufs = (rte_mbuf**)malloc(sizeof(struct rte_mbuf*) * burst_size);
105 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, tx_bufs, burst_size);
106 :
107 0 : auto stats = std::thread([&]() {
108 0 : while (true) {
109 0 : TLOG() << "Packets/s: " << num_packets << " Bytes/s: " << num_bytes << " Total packets: " << total_packets
110 0 : << " Failed packets: " << failed_packets;
111 0 : num_packets.exchange(0);
112 0 : num_bytes.exchange(0);
113 :
114 : // arp::pktgen_send_garp(tx_bufs[0], iface, ip_addr_bin);
115 : //++garps_sent;
116 :
117 0 : std::this_thread::sleep_for(
118 0 : std::chrono::seconds(1)); // If we sample for anything other than 1s, the rate calculation will need to change
119 0 : }
120 0 : });
121 :
122 0 : struct rte_mbuf** bufs = (rte_mbuf**)malloc(sizeof(struct rte_mbuf*) * burst_size);
123 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, bufs, burst_size);
124 :
125 : bool once = true; // one shot variable
126 0 : while (true) {
127 0 : const uint16_t nb_rx = rte_eth_rx_burst(iface, 0, bufs, burst_size);
128 0 : if (nb_rx != 0) {
129 0 : num_packets += nb_rx;
130 : // Iterate on burst packets
131 0 : for (int i_b = 0; i_b < nb_rx; ++i_b) {
132 0 : num_bytes += bufs[i_b]->pkt_len;
133 :
134 : // Check for segmentation
135 0 : if (bufs[i_b]->nb_segs > 1) {
136 0 : TLOG() << "It appears a packet is spread across more than one receiving buffer;"
137 0 : << " there's currently no logic in this program to handle this";
138 : }
139 :
140 : // Check packet type
141 0 : auto pkt_type = bufs[i_b]->packet_type;
142 : //// Handle non IPV4 packets
143 0 : if (not RTE_ETH_IS_IPV4_HDR(pkt_type)) {
144 0 : TLOG() << "Non-Ethernet packet type: " << (unsigned)pkt_type;
145 0 : if (pkt_type == RTE_PTYPE_L2_ETHER_ARP) {
146 0 : TLOG() << "ARP request detected!";
147 :
148 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
149 : // print_arp(bufs[i_b]);
150 :
151 0 : arp::pktgen_process_arp(bufs[i_b], 0, ip_addr_bin);
152 0 : } else if (pkt_type == RTE_PTYPE_L2_ETHER_LLDP) {
153 0 : TLOG() << "TODO: Handle LLDP packet!";
154 : // rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
155 : } else {
156 0 : TLOG() << "Unidentified! Dumping...";
157 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
158 : }
159 0 : continue;
160 0 : }
161 : }
162 0 : rte_pktmbuf_free_bulk(bufs, nb_rx);
163 : }
164 : } // main loop
165 :
166 : return 0;
167 0 : }
168 :
169 : int
170 0 : main(int argc, char* argv[])
171 : {
172 :
173 0 : uint16_t iface_id = 0;
174 0 : std::string ip_address;
175 0 : std::vector<std::string> pcie_addresses;
176 :
177 0 : CLI::App app{ "test arp responses" };
178 0 : app.add_option("-a,--ip-address", ip_address, "IP Addresses");
179 0 : app.add_option("-m,--pcie-mask", pcie_addresses, "PCIE Addresses device mask");
180 0 : app.add_option("-i,--iface", iface_id, "Interface to init");
181 :
182 0 : CLI11_PARSE(app, argc, argv);
183 :
184 : // Validate arguments
185 0 : fmt::print("ip : {}\n", ip_address);
186 0 : fmt::print("pcies : {}\n", fmt::join(pcie_addresses, " | "));
187 :
188 0 : std::regex re_ipv4("[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}");
189 0 : std::regex re_pcie("^0{0,4}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}.[0-9]$");
190 :
191 : // bool all_ip_ok = true;
192 : // for( const auto& ip: garp_ip_addresses) {
193 : // bool ip_ok = std::regex_match(ip, re_ipv4);
194 : // fmt::print("- {} {}\n", ip, ip_ok);
195 : // all_ip_ok &= ip_ok;
196 : // }
197 :
198 0 : bool ip_ok = std::regex_match(ip_address, re_ipv4);
199 0 : fmt::print("IP address {} {}\n", ip_address, ip_ok);
200 :
201 0 : fmt::print("PCIE addresses\n");
202 0 : bool all_pcie_ok = true;
203 0 : for (const auto& pcie : pcie_addresses) {
204 0 : bool pcie_ok = std::regex_match(pcie, re_pcie);
205 0 : fmt::print("- {} {}\n", pcie, pcie_ok);
206 0 : all_pcie_ok &= pcie_ok;
207 : }
208 :
209 0 : if (!ip_ok or !all_pcie_ok) {
210 : return -1;
211 : }
212 :
213 0 : std::vector<std::string> eal_args;
214 0 : eal_args.push_back("dpdklibds_test_garp");
215 0 : for (const auto& pcie : pcie_addresses) {
216 0 : eal_args.push_back("-a");
217 0 : eal_args.push_back(pcie);
218 : }
219 0 : dunedaq::dpdklibs::ealutils::init_eal(eal_args);
220 :
221 0 : auto n_ifaces = rte_eth_dev_count_avail();
222 0 : fmt::print("# of available ifaces: {}\n", n_ifaces);
223 0 : if (n_ifaces == 0) {
224 0 : std::cout << "WARNING: no available ifaces. exiting...\n";
225 0 : rte_eal_cleanup();
226 : return 1;
227 : }
228 :
229 : // int ret = rte_eal_init(argc, argv);
230 : // if (ret < 0) {
231 : // rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
232 : // }
233 :
234 : // Iface ID and its queue numbers
235 0 : const uint16_t rx_qs = 1;
236 0 : const uint16_t tx_qs = 1;
237 0 : const uint16_t rx_ring_size = 1024;
238 0 : const uint16_t tx_ring_size = 1024;
239 : // Get pool
240 0 : std::map<int, std::unique_ptr<rte_mempool>> mbuf_pools;
241 0 : TLOG() << "Allocating pool";
242 0 : for (unsigned p_i = 0; p_i < rx_qs; ++p_i) {
243 0 : std::ostringstream ss;
244 0 : ss << "MBP-" << p_i;
245 0 : mbuf_pools[p_i] = ealutils::get_mempool(ss.str());
246 0 : }
247 :
248 : // Setup interface
249 0 : auto nb_ifaces = rte_eth_dev_count_avail();
250 0 : TLOG() << "# of available interfaces: " << nb_ifaces;
251 0 : TLOG() << "Initialize interface " << iface_id;
252 0 : ealutils::iface_init(iface_id, rx_qs, tx_qs, rx_ring_size, tx_ring_size, mbuf_pools);
253 0 : ealutils::iface_promiscuous_mode(iface_id, true); // should come from config
254 :
255 : // Flow steering setup
256 0 : TLOG() << "Configuring Flow steering rules for iface=" << iface_id;
257 0 : struct rte_flow_error error;
258 0 : struct rte_flow* flow;
259 0 : TLOG() << "Attempt to flush previous flow rules...";
260 0 : rte_flow_flush(iface_id, &error);
261 0 : TLOG() << "Create control flow rules (ARP).";
262 :
263 0 : flow = generate_arp_flow(iface_id, 0, &error);
264 0 : if (not flow) { // ers::fatal
265 0 : TLOG() << "Flow can't be created for ARP queue=0"
266 0 : << " Error type: " << (unsigned)error.type << " Message: " << error.message;
267 0 : return 1;
268 : }
269 :
270 : // Launch lcores
271 0 : lcore_main(mbuf_pools[0].get(), ip_address);
272 :
273 : // Cleanup
274 : TLOG() << "EAL cleanup...";
275 : ealutils::wait_for_lcores();
276 : rte_eal_cleanup();
277 :
278 : return 0;
279 0 : }
|