DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
EALSetup.cpp
Go to the documentation of this file.
1
8// #ifndef DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
9// #define DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
10
11#include "logging/Logging.hpp"
12
13#include <boost/program_options/parsers.hpp>
14
15#include "dpdklibs/EALSetup.hpp"
16#include "dpdklibs/Issues.hpp"
17
18#include <rte_eal.h>
19#include <rte_ethdev.h>
20
21namespace dunedaq {
22namespace dpdklibs {
23namespace ealutils {
24
25#define NUM_MBUFS 8191
26#define MBUF_CACHE_SIZE 250
27
28#define PG_JUMBO_FRAME_LEN (9600 + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN)
29#ifndef RTE_JUMBO_ETHER_MTU
30#define RTE_JUMBO_ETHER_MTU (PG_JUMBO_FRAME_LEN - RTE_ETHER_HDR_LEN - RTE_ETHER_CRC_LEN) /*< Ethernet MTU. */
31#endif
32
33// static volatile uint8_t dpdk_quit_signal;
34
35static const struct rte_eth_conf iface_conf_default = {
36 .rxmode = {
37 .mtu = 9000,
38 .max_lro_pkt_size = 9000,
39 //.split_hdr_size = 0, // deprecated in dpdk@22.10
40 .offloads = (RTE_ETH_RX_OFFLOAD_TIMESTAMP
41 | RTE_ETH_RX_OFFLOAD_IPV4_CKSUM
42 | RTE_ETH_RX_OFFLOAD_UDP_CKSUM),
43 },
44
45 .txmode = {
46 .offloads = (RTE_ETH_TX_OFFLOAD_MULTI_SEGS),
47 },
48};
49
50
51std::string get_mac_addr_str(const rte_ether_addr& addr) {
52 std::stringstream macstr;
53 macstr << std::hex << static_cast<int>(addr.addr_bytes[0]) << ":" << static_cast<int>(addr.addr_bytes[1]) << ":" << static_cast<int>(addr.addr_bytes[2]) << ":" << static_cast<int>(addr.addr_bytes[3]) << ":" << static_cast<int>(addr.addr_bytes[4]) << ":" << static_cast<int>(addr.addr_bytes[5]) << std::dec;
54 return macstr.str();
55}
56
57
58// Modifies Ethernet device configuration to multi-queue RSS with offload
59void
60iface_conf_rss_mode(struct rte_eth_conf& iface_conf, bool mode, bool offload)
61{
62 if (mode) {
63 iface_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_RSS;
64 if (offload) {
65 iface_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
66 }
67 } else {
68 iface_conf.rxmode.mq_mode = RTE_ETH_MQ_RX_NONE;
69 }
70}
71
72// Enables RX in promiscuous mode for the Ethernet device.
73int
74iface_promiscuous_mode(std::uint16_t iface, bool mode)
75{
76 int retval = -1;
77 retval = rte_eth_promiscuous_get(iface);
78 TLOG() << "Before modification attempt, promiscuous mode is: " << retval;
79 if (mode) {
80 retval = rte_eth_promiscuous_enable(iface);
81 } else {
82 retval = rte_eth_promiscuous_disable(iface);
83 }
84 if (retval != 0) {
85 TLOG() << "Couldn't modify promiscuous mode of iface[" << iface << "]! Error code: " << retval;
86 }
87 retval = rte_eth_promiscuous_get(iface);
88 TLOG() << "New promiscuous mode of iface[" << iface << "] is: " << retval;
89 return retval;
90}
91
92
93
94int
95iface_init(uint16_t iface, uint16_t rx_rings, uint16_t tx_rings,
96 uint16_t rx_ring_size, uint16_t tx_ring_size,
97 std::map<int, std::unique_ptr<rte_mempool>>& mbuf_pool,
98 bool with_reset, bool with_mq_rss, bool check_link_status)
99{
100 struct rte_eth_conf iface_conf = iface_conf_default;
101 uint16_t nb_rxd = rx_ring_size;
102 uint16_t nb_txd = tx_ring_size;
103 int retval = -1;
104 uint16_t q;
105 struct rte_eth_dev_info dev_info;
106 struct rte_eth_txconf txconf;
107 struct rte_eth_link link;
108
109 // Get interface validity
110 if (!rte_eth_dev_is_valid_port(iface)) {
111 TLOG() << "Specified interface " << iface << " is not valid in EAL!";
112 throw InvalidEALPort(ERS_HERE, iface);
113 }
114
115 // Get interface info
116 if ((retval = rte_eth_dev_info_get(iface, &dev_info)) != 0) {
117 TLOG() << "Error during getting device (iface " << iface << ") retval: " << retval;
118 throw FailedToRetrieveInterfaceInfo(ERS_HERE, iface, retval);
119 }
120
121 TLOG() << "Iface " << iface << " RX Ring info :"
122 << " min " << dev_info.rx_desc_lim.nb_min
123 << " max " << dev_info.rx_desc_lim.nb_max
124 << " align " << dev_info.rx_desc_lim.nb_align
125 ;
126
127 // Carry out a reset of the interface
128 if (with_reset) {
129 if ((retval = rte_eth_dev_reset(iface)) != 0) {
130 throw FailedToResetInterface(ERS_HERE, iface, retval);
131 }
132 }
133
134 // Should we configure MQ RSS and offload?
135 if (with_mq_rss) {
136 iface_conf_rss_mode(iface_conf, true, true); // with_rss, with_offload
137 // RSS
138 if ((iface_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) != 0) {
139 TLOG() << "Ethdev port config prepared with RX RSS mq_mode!";
140 if ((iface_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH) != 0) {
141 TLOG() << "Ethdev port config prepared with RX RSS mq_mode with offloading is requested!";
142 }
143 }
144 }
145
146 TLOG() << "Configuring Iface " << iface << " rx rings: " << rx_rings <<", tx rings " << tx_rings;
147
148 // Configure the Ethernet interface
149 if ((retval = rte_eth_dev_configure(iface, rx_rings, tx_rings, &iface_conf)) != 0) {
150 throw FailedToConfigureInterface(ERS_HERE, iface, "Device Configuration", retval);
151 }
152
153 // Set MTU of interface
154 rte_eth_dev_set_mtu(iface, RTE_JUMBO_ETHER_MTU);
155 {
156 uint16_t mtu;
157 rte_eth_dev_get_mtu(iface, &mtu);
158 TLOG() << "Interface: " << iface << " MTU: " << mtu;
159 }
160
161 // // Adjust RX/TX ring sizes
162 // retval = rte_eth_dev_adjust_nb_rx_tx_desc(iface, &nb_rxd, &nb_txd);
163 // if (retval != 0)
164 // return retval;
165
166 if ((retval = rte_eth_dev_adjust_nb_rx_tx_desc(iface, &nb_rxd, &nb_txd)) != 0) {
167 throw FailedToConfigureInterface(ERS_HERE, iface, "Adjust tx/rx descriptors", retval);
168 }
169
170 // Allocate and set up RX queues for interface.
171 for (q = 0; q < rx_rings; q++) {
172 // retval = rte_eth_rx_queue_setup(iface, q, nb_rxd, rte_eth_dev_socket_id(iface), NULL, mbuf_pool[q].get());
173 if ((retval = rte_eth_rx_queue_setup(iface, q, nb_rxd, rte_eth_dev_socket_id(iface), NULL, mbuf_pool[q].get())) < 0) {
174 // return retval;
175 throw FailedToConfigureInterface(ERS_HERE, iface, "Rx queues setup", retval);
176 }
177 }
178
179 txconf = dev_info.default_txconf;
180 txconf.offloads = iface_conf.txmode.offloads;
181
182 // These values influenced by Sec. 8.4.4 of https://doc.dpdk.org/guides-1.8/prog_guide/poll_mode_drv.html
183 txconf.tx_rs_thresh = 32;
184 txconf.tx_free_thresh = 32;
185 txconf.tx_thresh.wthresh = 0;
186
187 // Allocate and set up TX queues for interface.
188 for (q = 0; q < tx_rings; q++) {
189 if ((retval = rte_eth_tx_queue_setup(iface, q, nb_txd, rte_eth_dev_socket_id(iface), &txconf)) < 0) {
190 throw FailedToConfigureInterface(ERS_HERE, iface, "Tx queues setup", retval);
191 }
192 }
193
194 // Start the Ethernet interface.
195 if ((retval = rte_eth_dev_start(iface)) < 0) {
196 throw FailedToConfigureInterface(ERS_HERE, iface, "MAC address retrival", retval);
197 }
198
199 if ((retval = rte_eth_link_get(iface, &link)) != 0) {
200 throw FailedToRetrieveLinkStatus(ERS_HERE, iface, retval);
201 }
202
203 TLOG() << "Link: speed=" << link.link_speed << " duplex=" << link.link_duplex << " autoneg=" << link.link_autoneg << " status=" << link.link_status;
204
205 if ( check_link_status && link.link_status == 0 ) {
206 throw LinkOffline(ERS_HERE, iface);
207 }
208
209 // Display the interface MAC address.
210 struct rte_ether_addr addr;
211 if ((retval = rte_eth_macaddr_get(iface, &addr)) == 0) {
212 TLOG() << "MAC address: " << get_mac_addr_str(addr);
213 } else {
214 throw FailedToConfigureInterface(ERS_HERE, iface, "MAC address retrival", retval);
215 }
216
217 // Get interface info
218 if ((retval = rte_eth_dev_info_get(iface, &dev_info)) != 0) {
219 TLOG() << "Error during getting device (iface " << iface << ") retval: " << retval;
220 throw FailedToConfigureInterface(ERS_HERE, iface, "Device information retrival", retval);
221 }
222
223 TLOG() << "Iface[" << iface << "] Rx Ring info:"
224 << " min=" << dev_info.rx_desc_lim.nb_min
225 << " max=" << dev_info.rx_desc_lim.nb_max
226 << " align=" << dev_info.rx_desc_lim.nb_align;
227 TLOG() << "Iface[" << iface << "] Tx Ring info:"
228 << " min=" << dev_info.rx_desc_lim.nb_min
229 << " max=" << dev_info.rx_desc_lim.nb_max
230 << " align=" << dev_info.rx_desc_lim.nb_align;
231
232 for (size_t j = 0; j < dev_info.nb_rx_queues; j++) {
233
234 struct rte_eth_rxq_info queue_info;
235 int count;
236
237 retval = rte_eth_rx_queue_info_get(iface, j, &queue_info);
238 if (retval != 0)
239 continue;
240
241 count = rte_eth_rx_queue_count(iface, j);
242 TLOG() << "rx[" << j << "] descriptors=" << count << "/" << queue_info.nb_desc
243 << " scattered=" << (queue_info.scattered_rx ? "yes" : "no")
244 << " conf.drop_en=" << (queue_info.conf.rx_drop_en ? "yes" : "no")
245 << " conf.rx_deferred_start=" << (queue_info.conf.rx_deferred_start ? "yes" : "no")
246 << " rx_buf_size=" << queue_info.rx_buf_size;
247 }
248
249 return 0;
250}
251
252std::unique_ptr<rte_mempool>
253get_mempool(const std::string& pool_name,
254 int num_mbufs, int mbuf_cache_size,
255 int data_room_size, int socket_id) {
256 TLOG() << "get_mempool with: NUM_MBUFS = " << num_mbufs
257 << " | MBUF_CACHE_SIZE = " << mbuf_cache_size
258 << " | data_room_size = " << data_room_size
259 << " | SOCKET_ID = " << socket_id;
260
261 struct rte_mempool *mbuf_pool;
262 mbuf_pool = rte_pktmbuf_pool_create(pool_name.c_str(), num_mbufs,
263 mbuf_cache_size, 0, data_room_size,
264 socket_id);
265
266 if (mbuf_pool == NULL) {
267 // ers fatal
268 rte_exit(EXIT_FAILURE, "ERROR: Cannot create rte_mempool!\n");
269 }
270 return std::unique_ptr<rte_mempool>(mbuf_pool);
271}
272
273std::vector<const char*>
274construct_eal_argv(const std::vector<std::string> &std_argv){
275 std::vector<const char*> vec_argv;
276 for (int i=0; i < std_argv.size() ; i++){
277 vec_argv.insert(vec_argv.end(), std_argv[i].data());
278 }
279 return vec_argv;
280}
281
282
283
284void
285init_eal(int argc, const char* argv[]) {
286
287 std::stringstream ss;
288 for( size_t i(0); i<argc; ++i) {
289 ss << argv[i] << " ";
290 }
291 TLOG() << "EAL init arguments: " << ss.str();
292
293 // Init EAL
294 int ret = rte_eal_init(argc, (char**)argv);
295 if (ret < 0) {
296 rte_exit(EXIT_FAILURE, "ERROR: EAL initialization failed.\n");
297 }
298 TLOG() << "EAL initialized with provided parameters.";
299}
300
301void
302init_eal( const std::vector<std::string>& args ) {
303
304 std::vector<const char*> eal_argv = ealutils::construct_eal_argv(args);
305 const char** constructed_eal_argv = eal_argv.data();
306 int constructed_eal_argc = args.size();
307 ealutils::init_eal(constructed_eal_argc, constructed_eal_argv);
308}
309
310int
312 // Check that there is an even number of interfaces to send/receive on
313 unsigned nb_ifaces;
314 nb_ifaces = rte_eth_dev_count_avail();
315 TLOG() << "Available interfaces: " << nb_ifaces;
316 return nb_ifaces;
317}
318
319int
321 int lcore_id;
322 int ret = 0;
323 RTE_LCORE_FOREACH_WORKER(lcore_id) {
324 //TLOG() << "Waiting for lcore[" << lcore_id << "] to finish packet processing.";
325 ret = rte_eal_wait_lcore(lcore_id);
326 }
327 return ret;
328}
329
331 rte_eal_cleanup();
332}
333
334} // namespace ealutils
335} // namespace dpdklibs
336} // namespace dunedaq
337// #endif // DPDKLIBS_INCLUDE_DPDKLIBS_EALSETUP_HPP_
338
#define ERS_HERE
#define RTE_JUMBO_ETHER_MTU
#define TLOG(...)
Definition macro.hpp:22
std::unique_ptr< rte_mempool > get_mempool(const std::string &pool_name, int num_mbufs=NUM_MBUFS, int mbuf_cache_size=MBUF_CACHE_SIZE, int data_room_size=9800, int socket_id=0)
Definition EALSetup.cpp:253
std::vector< const char * > construct_eal_argv(const std::vector< std::string > &std_argv)
Definition EALSetup.cpp:274
static const struct rte_eth_conf iface_conf_default
Definition EALSetup.cpp:35
void init_eal(int argc, const char *argv[])
Definition EALSetup.cpp:285
void iface_conf_rss_mode(struct rte_eth_conf &iface_conf, bool mode=false, bool offload=false)
Definition EALSetup.cpp:60
int iface_promiscuous_mode(std::uint16_t iface, bool mode=false)
Definition EALSetup.cpp:74
std::string get_mac_addr_str(const rte_ether_addr &addr)
Definition EALSetup.cpp:51
int iface_init(uint16_t iface, uint16_t rx_rings, uint16_t tx_rings, uint16_t rx_ring_size, uint16_t tx_ring_size, std::map< int, std::unique_ptr< rte_mempool > > &mbuf_pool, bool with_reset=false, bool with_mq_rss=false, bool check_link_status=false)
Definition EALSetup.cpp:95
Including Qt Headers.