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