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