Line data Source code
1 : /* Application will run until quit or killed. */
2 :
3 : #include "dpdklibs/EALSetup.hpp"
4 : #include "dpdklibs/RTEIfaceSetup.hpp"
5 : #include "logging/Logging.hpp"
6 : #include "dpdklibs/udp/PacketCtor.hpp"
7 : #include "dpdklibs/udp/Utils.hpp"
8 : #include "dpdklibs/arp/ARP.hpp"
9 : #include "dpdklibs/ipv4_addr.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 :
18 : #include <sstream>
19 : #include <stdint.h>
20 : #include <limits>
21 : #include <iomanip>
22 : #include <fstream>
23 : #include <csignal>
24 :
25 : using namespace dunedaq;
26 : using namespace dpdklibs;
27 : using namespace udp;
28 :
29 : namespace {
30 : constexpr int burst_size = 256;
31 :
32 : std::atomic<uint64_t> num_packets = 0;
33 : std::atomic<uint64_t> num_bytes = 0;
34 : std::atomic<uint64_t> num_errors = 0;
35 : std::atomic<uint64_t> num_missed = 0;
36 : std::atomic<uint64_t> num_udp_frames = 0;
37 : std::atomic<uint64_t> num_jumbo_frames = 0;
38 :
39 : } // namespace ""
40 :
41 : static int
42 0 : lcore_main(struct rte_mempool *mbuf_pool)
43 : {
44 0 : uint16_t iface = 0;
45 0 : TLOG() << "Launch lcore for interface: " << iface;
46 :
47 0 : struct rte_mbuf **tx_bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
48 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, tx_bufs, burst_size);
49 :
50 : // Reset internal ETH DEV stat counters.
51 0 : rte_eth_stats_reset(iface);
52 0 : rte_eth_xstats_reset(iface);
53 :
54 : //////////// RS FIXME -> Copy pasta DPDK Docs, of course the docs are super misleading....
55 0 : struct rte_eth_xstat_name *xstats_names;
56 0 : uint64_t *xstats_ids;
57 0 : uint64_t *values;
58 0 : int len, i;
59 :
60 : // Get number of stats
61 0 : len = rte_eth_xstats_get_names_by_id(iface, NULL, NULL, 0);
62 0 : if (len < 0) {
63 0 : printf("Cannot get xstats count\n");
64 : }
65 :
66 : // Get names of HW registered stat fields
67 0 : xstats_names = (rte_eth_xstat_name*)(malloc(sizeof(struct rte_eth_xstat_name) * len));
68 0 : if (xstats_names == NULL) {
69 0 : printf("Cannot allocate memory for xstat names\n");
70 : }
71 :
72 : // Retrieve xstats names, passing NULL for IDs to return all statistics
73 0 : if (len != rte_eth_xstats_get_names(iface, xstats_names, len)) {
74 0 : printf("Cannot get xstat names\n");
75 : }
76 :
77 : // Allocate value fields
78 0 : values = (uint64_t*)(malloc(sizeof(values) * len));
79 0 : if (values == NULL) {
80 0 : printf("Cannot allocate memory for xstats\n");
81 : }
82 :
83 : // Getting xstats values (this is that we call in a loop/get_info
84 0 : if (len != rte_eth_xstats_get_by_id(iface, NULL, values, len)) {
85 0 : printf("Cannot get xstat values\n");
86 : }
87 :
88 : // Print all xstats names and values to be amazed (WOW!)
89 0 : for (i = 0; i < len; i++) {
90 0 : TLOG() << "Name: " << xstats_names[i].name << " value: " << values[i];
91 : }
92 :
93 : /////////////// RS FIXME: Stats thread spawn. Passed with the scope of attrocities above...
94 0 : auto stats = std::thread([&]() {
95 :
96 : ///////////// RS FIXME: Simple PMD based stats monitoring is also possible
97 0 : struct rte_eth_stats iface_stats;
98 0 : while (true) {
99 : // RS: poll out dev stats. (SIMPLE MODE)
100 0 : rte_eth_stats_get(iface, &iface_stats);
101 0 : num_packets = (uint64_t)iface_stats.ipackets;
102 0 : num_bytes = (uint64_t)iface_stats.ibytes;
103 0 : num_missed = (uint64_t)iface_stats.imissed;
104 0 : num_errors = (uint64_t)iface_stats.ierrors;
105 0 : TLOG() << " Total packets: " << num_packets
106 0 : << " Total bytes: " << num_bytes
107 0 : << " Total missed: " << num_missed
108 0 : << " Total errors: " << num_errors
109 0 : << " Total UDP frames: " << num_udp_frames.exchange(0)
110 0 : << " Total JUMBO frames: " << num_jumbo_frames.exchange(0);
111 : // Queue based counters doesn't seem to work neither here neither in module... :((((((
112 0 : for( unsigned long i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++ ){
113 0 : TLOG() << "HW iface queue[" << i << "] received: " << (uint64_t)iface_stats.q_ipackets[i];
114 : }
115 :
116 : ////////////// RS FIXME: HW counter based stats monitoring. Fields initialized just before thread spawn.
117 0 : if (len != rte_eth_xstats_get_by_id(iface, NULL, values, len)) {
118 0 : TLOG() << "Cannot get xstat values!";
119 : } else {
120 0 : for (i = 0; i < len; i++) {
121 0 : TLOG() << "Name: " << xstats_names[i].name << " value: " << values[i];
122 : }
123 : }
124 0 : int reset_res = rte_eth_xstats_reset(iface);
125 0 : TLOG() << "Reset notification result: " << reset_res;
126 : ////////////// RS FIXME: HW counter based loop ends.
127 :
128 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
129 0 : }
130 0 : });
131 :
132 0 : struct rte_mbuf **bufs = (rte_mbuf**) malloc(sizeof(struct rte_mbuf*) * burst_size);
133 0 : rte_pktmbuf_alloc_bulk(mbuf_pool, bufs, burst_size);
134 :
135 :
136 :
137 : bool once = true; // one shot variable
138 0 : while (true) {
139 0 : const uint16_t nb_rx = rte_eth_rx_burst(iface, 0, bufs, burst_size);
140 0 : if (nb_rx != 0) {
141 0 : num_packets += nb_rx;
142 : // Iterate on burst packets
143 0 : for (int i_b=0; i_b<nb_rx; ++i_b) {
144 0 : num_bytes += bufs[i_b]->pkt_len;
145 :
146 : // Check for segmentation
147 0 : if (bufs[i_b]->nb_segs > 1) {
148 0 : TLOG() << "It appears a packet is spread across more than one receiving buffer;"
149 0 : << " there's currently no logic in this program to handle this";
150 : }
151 :
152 : // Check packet type
153 0 : auto pkt_type = bufs[i_b]->packet_type;
154 : //// Handle non IPV4 packets
155 0 : if (not RTE_ETH_IS_IPV4_HDR(pkt_type)) {
156 0 : TLOG() << "Non-Ethernet packet type: " << (unsigned)pkt_type;
157 0 : if (pkt_type == RTE_PTYPE_L2_ETHER_ARP) {
158 0 : TLOG() << "TODO: Handle ARP request!";
159 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
160 : //arp::pktgen_process_arp(bufs[i_b], 0, ip_addr_bin);
161 0 : } else if (pkt_type == RTE_PTYPE_L2_ETHER_LLDP) {
162 0 : TLOG() << "TODO: Handle LLDP packet!";
163 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
164 : } else {
165 0 : TLOG() << "Unidentified! Dumping...";
166 0 : rte_pktmbuf_dump(stdout, bufs[i_b], bufs[i_b]->pkt_len);
167 : }
168 0 : continue;
169 0 : }
170 :
171 : // Check if frame is UDP. Count them.
172 0 : if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
173 0 : ++num_udp_frames;
174 : }
175 :
176 : // Check for JUMBO frames (bigger than 1500 Bytes)
177 0 : if (bufs[i_b]->pkt_len > 1500) { // RS FIXME: do proper check on data length later
178 0 : ++num_jumbo_frames;
179 : }
180 :
181 : }
182 0 : rte_pktmbuf_free_bulk(bufs, nb_rx);
183 : }
184 : } // main loop
185 :
186 :
187 : return 0;
188 0 : }
189 :
190 : int
191 0 : main(int argc, char* argv[])
192 : {
193 0 : int ret = rte_eal_init(argc, argv);
194 0 : if (ret < 0) {
195 0 : rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
196 : }
197 :
198 : // Iface ID and its queue numbers
199 0 : int iface_id = 0;
200 0 : const uint16_t rx_qs = 5;
201 0 : const uint16_t tx_qs = 1;
202 0 : const uint16_t rx_ring_size = 1024;
203 0 : const uint16_t tx_ring_size = 1024;
204 : // Get pool
205 0 : std::map<int, std::unique_ptr<rte_mempool>> mbuf_pools;
206 0 : TLOG() << "Allocating pool";
207 0 : for (unsigned p_i = 0; p_i<rx_qs; ++p_i) {
208 0 : std::ostringstream ss;
209 0 : ss << "MBP-" << p_i;
210 0 : mbuf_pools[p_i] = ealutils::get_mempool(ss.str());
211 0 : }
212 :
213 : // Setup interface
214 0 : auto nb_ifaces = rte_eth_dev_count_avail();
215 0 : TLOG() << "# of available interfaces: " << nb_ifaces;
216 0 : TLOG() << "Initialize interface " << iface_id;
217 0 : TLOG() << " -> Iface MAC: " << ifaceutils::get_iface_mac_str(iface_id);
218 0 : TLOG() << " -> Iface PCI: " << ifaceutils::get_iface_pci_str(iface_id);
219 :
220 0 : ealutils::iface_init(iface_id, rx_qs, tx_qs, rx_ring_size, tx_ring_size, mbuf_pools, false, false);
221 0 : ealutils::iface_promiscuous_mode(iface_id, false); // should come from config
222 :
223 : // Launch lcores
224 0 : lcore_main(mbuf_pools[0].get());
225 :
226 : // Cleanup
227 : TLOG() << "EAL cleanup...";
228 : ealutils::wait_for_lcores();
229 : rte_eal_cleanup();
230 :
231 : return 0;
232 0 : }
|