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