60IfaceWrapper::IfaceWrapper(
62 const appmodel::DPDKReceiver* receiver,
63 const std::vector<const appmodel::NWDetDataSender*>& nw_senders,
64 sid_to_source_map_t& sources,
70 auto net_device = receiver->get_uses()->cast<confmodel::NetworkDevice>();
72 m_iface_id = iface_id;
73 m_mac_addr = net_device->get_mac_address();
74 m_ip_addr = net_device->get_ip_address();
76 for(
const std::string& ip_addr : m_ip_addr) {
77 IpAddr ip_addr_struct(ip_addr);
79 ip_addr_struct.addr_bytes[0],
80 ip_addr_struct.addr_bytes[1],
81 ip_addr_struct.addr_bytes[2],
82 ip_addr_struct.addr_bytes[3]
87 auto iface_cfg = receiver->get_configuration();
89 m_with_flow = iface_cfg->get_flow_control();
90 m_prom_mode = iface_cfg->get_promiscuous_mode();;
91 m_mtu = iface_cfg->get_mtu();
92 m_rx_ring_size = iface_cfg->get_rx_ring_size();
93 m_tx_ring_size = iface_cfg->get_tx_ring_size();
94 m_num_mbufs = iface_cfg->get_num_bufs();
95 m_burst_size = iface_cfg->get_burst_size();
96 m_mbuf_cache_size = iface_cfg->get_mbuf_cache_size();
98 m_lcore_sleep_ns = iface_cfg->get_lcore_sleep_us() * 1000;
99 m_socket_id = rte_eth_dev_socket_id(m_iface_id);
101 m_iface_id_str = iface_cfg->UID();
105 for(
const auto* proc_res : iface_cfg->get_used_lcores()) {
106 m_rte_cores.insert(m_rte_cores.end(), proc_res->get_cpu_cores().begin(), proc_res->get_cpu_cores().end());
108 if(std::find(m_rte_cores.begin(), m_rte_cores.end(), rte_get_main_lcore())!=m_rte_cores.end()) {
109 TLOG() <<
"ERROR! Throw ERS error here that LCore=0 should not be used, as it's a control RTE core!";
110 throw std::runtime_error(std::string(
"ERROR! Throw ERS here that LCore=0 should not be used, as it's a control RTE core!"));
116 std::map<std::string, std::map<uint, uint>> ip_to_stream_src_groups;
118 for(
auto nw_sender : nw_senders ) {
119 auto sender_ni = nw_sender->get_uses();
121 std::string
tx_ip = sender_ni->get_ip_address().at(0);
123 for (
auto res : nw_sender->get_contains() ) {
125 auto det_stream = res->cast<confmodel::DetectorStream>();
126 uint32_t tx_geo_stream_id = det_stream->get_geo_id()->get_stream_id();
127 ip_to_stream_src_groups[
tx_ip][tx_geo_stream_id] = det_stream->get_source_id();
134 uint32_t core_idx(0), rx_q(0);
136 m_rx_qs.insert(rx_q);
137 m_arp_rx_queue = rx_q;
140 for(
const auto& [
tx_ip, strm_src] : ip_to_stream_src_groups) {
142 m_rx_qs.insert(rx_q);
143 m_num_frames_rxq[rx_q] = { 0 };
144 m_num_bytes_rxq[rx_q] = { 0 };
146 m_rx_core_map[m_rte_cores[core_idx]][rx_q] =
tx_ip;
147 m_stream_id_to_source_id[rx_q] = strm_src;
150 if ( ++core_idx == m_rte_cores.size()) {
156 for (
auto const& [lcore, rx_qs] : m_rx_core_map) {
157 TLOG() <<
"Lcore=" << lcore <<
" handles: ";
158 for (
auto const& [rx_q, src_ip] : rx_qs) {
159 TLOG() <<
" rx_q=" << rx_q <<
" src_ip=" << src_ip;
164 TLOG() <<
"Append TX_Q=0 for ARP responses.";
171IfaceWrapper::~IfaceWrapper()
175 struct rte_flow_error
error;
176 rte_flow_flush(m_iface_id, &
error);
185IfaceWrapper::allocate_mbufs()
187 TLOG() <<
"Allocating pools and mbufs for UDP, GARP, and ARP.";
190 for (
size_t i=0; i<m_rx_qs.size(); ++i) {
191 std::stringstream bufss;
192 bufss <<
"MBP-" << m_iface_id <<
'-' << i;
193 TLOG() <<
"Acquire pool with name=" << bufss.str() <<
" for iface_id=" << m_iface_id <<
" rxq=" << i;
194 m_mbuf_pools[i] =
ealutils::get_mempool(bufss.str(), m_num_mbufs, m_mbuf_cache_size, 16384, m_socket_id);
195 m_bufs[i] = (rte_mbuf**) malloc(
sizeof(
struct rte_mbuf*) * m_burst_size);
201 std::stringstream garpss;
202 garpss <<
"GARPMBP-" << m_iface_id;
203 TLOG() <<
"Acquire GARP pool with name=" << garpss.str() <<
" for iface_id=" << m_iface_id;
205 m_garp_bufs[0] = (rte_mbuf**) malloc(
sizeof(
struct rte_mbuf*) * m_burst_size);
206 rte_pktmbuf_alloc_bulk(m_garp_mbuf_pool.get(), m_garp_bufs[0], m_burst_size);
209 std::stringstream arpss;
210 arpss <<
"ARPMBP-" << m_iface_id;
211 TLOG() <<
"Acquire ARP pool with name=" << arpss.str() <<
" for iface_id=" << m_iface_id;
213 m_arp_bufs[0] = (rte_mbuf**) malloc(
sizeof(
struct rte_mbuf*) * m_burst_size);
214 rte_pktmbuf_alloc_bulk(m_arp_mbuf_pool.get(), m_arp_bufs[0], m_burst_size);
221IfaceWrapper::setup_interface()
223 TLOG() <<
"Initialize interface " << m_iface_id;
224 bool with_reset =
true, with_mq_mode =
true;
225 bool check_link_status =
false;
227 int retval =
ealutils::iface_init(m_iface_id, m_rx_qs.size(), m_tx_qs.size(), m_rx_ring_size, m_tx_ring_size, m_mbuf_pools, with_reset, with_mq_mode, check_link_status);
229 throw FailedToSetupInterface(
ERS_HERE, m_iface_id, retval);
238IfaceWrapper::setup_flow_steering()
241 TLOG() <<
"Configuring Flow steering rules for iface=" << m_iface_id;
242 struct rte_flow_error
error;
243 struct rte_flow *flow;
244 TLOG() <<
"Attempt to flush previous flow rules...";
245 rte_flow_flush(m_iface_id, &
error);
246#warning RS: FIXME -> Check for flow flush return!
248 TLOG() <<
"Create control flow rules (ARP) assinged to rxq=" << m_arp_rx_queue;
251 TLOG() <<
"ARP flow can't be created for " << m_arp_rx_queue
252 <<
" Error type: " << (unsigned)
error.type
253 <<
" Message: '" <<
error.message <<
"'";
254 ers::fatal(dunedaq::datahandlinglibs::InitializationError(
255 ERS_HERE,
"Couldn't create ARP flow API rules!"));
256 rte_exit(EXIT_FAILURE,
"error in creating ARP flow");
259 TLOG() <<
"Create flow rules for UDP RX.";
260 for (
auto const& [lcoreid, rxqs] : m_rx_core_map) {
261 for (
auto const& [rxqid, srcip] : rxqs) {
263 TLOG() <<
"Creating flow rule for src_ip=" << srcip <<
" assigned to rxq=" << rxqid;
264 size_t ind = 0, current_ind = 0;
265 std::vector<uint8_t> v;
266 for (
int i = 0; i < 4; ++i) {
267 v.push_back(std::stoi(srcip.substr(current_ind, srcip.size() - current_ind), &ind));
268 current_ind += ind + 1;
272 RTE_IPV4(v[0], v[1], v[2], v[3]), 0xffffffff, 0, 0, &
error);
275 TLOG() <<
"Flow can't be created for " << rxqid
276 <<
" Error type: " << (unsigned)
error.type
277 <<
" Message: '" <<
error.message <<
"'";
278 ers::fatal(dunedaq::datahandlinglibs::InitializationError(
279 ERS_HERE,
"Couldn't create Flow API rules!"));
280 rte_exit(EXIT_FAILURE,
"error in creating flow");
290IfaceWrapper::setup_xstats()
293 m_iface_xstats.setup(m_iface_id);
294 m_iface_xstats.reset_counters();
302 for (
auto const& [rx_q, _] : m_num_frames_rxq ) {
303 m_num_frames_rxq[rx_q] = { 0 };
304 m_num_bytes_rxq[rx_q] = { 0 };
305 m_num_full_bursts[rx_q] = { 0 };
306 m_max_burst_size[rx_q] = { 0 };
309 m_lcore_enable_flow.store(
false);
310 m_lcore_quit_signal.store(
false);
311 TLOG() <<
"Interface id=" << m_iface_id <<
" Launching GARP thread with garp_func...";
312 m_garp_thread = std::thread(&IfaceWrapper::garp_func,
this);
314 TLOG() <<
"Interface id=" << m_iface_id <<
" starting ARP LCore processor:";
315 m_arp_thread = std::thread(&IfaceWrapper::IfaceWrapper::arp_response_runner,
this,
nullptr);
318 TLOG() <<
"Interface id=" << m_iface_id <<
" starting LCore processors:";
319 for (
auto const& [lcoreid, _] : m_rx_core_map) {
320 int ret = rte_eal_remote_launch((
int (*)(
void*))(&IfaceWrapper::rx_runner),
this, lcoreid);
321 TLOG() <<
" -> LCore[" << lcoreid <<
"] launched with return code=" <<
ret <<
" " << (
ret < 0 ? rte_strerror(-
ret) :
"");
329 m_lcore_enable_flow.store(
false);
330 m_lcore_quit_signal.store(
true);
332 if (m_garp_thread.joinable()) {
333 m_garp_thread.join();
335 TLOG() <<
"GARP thread is not joinable!";
338 if (m_arp_thread.joinable()) {
341 TLOG() <<
"ARP thread is not joinable!";
356IfaceWrapper::generate_opmon_data() {
359 m_iface_xstats.poll();
362 s.set_ipackets( m_iface_xstats.m_eth_stats.ipackets );
363 s.set_opackets( m_iface_xstats.m_eth_stats.opackets );
364 s.set_ibytes( m_iface_xstats.m_eth_stats.ibytes );
365 s.set_obytes( m_iface_xstats.m_eth_stats.obytes );
366 s.set_imissed( m_iface_xstats.m_eth_stats.imissed );
367 s.set_ierrors( m_iface_xstats.m_eth_stats.ierrors );
368 s.set_oerrors( m_iface_xstats.m_eth_stats.oerrors );
369 s.set_rx_nombuf( m_iface_xstats.m_eth_stats.rx_nombuf );
370 publish( std::move(
s) );
372 if(m_iface_xstats.m_eth_stats.imissed > 0){
373 ers::warning(PacketErrors(
ERS_HERE, m_iface_id_str,
"missed", m_iface_xstats.m_eth_stats.imissed));
375 if(m_iface_xstats.m_eth_stats.ierrors > 0){
376 ers::warning(PacketErrors(
ERS_HERE, m_iface_id_str,
"dropped", m_iface_xstats.m_eth_stats.ierrors));
380 opmon::EthXStatsInfo xinfos;
381 opmon::EthXStatsErrors xerrs;
382 std::map<std::string, opmon::QueueEthXStats> xq;
384 for (
int i = 0; i < m_iface_xstats.m_len; ++i) {
386 std::string name(m_iface_xstats.m_xstats_names[i].name);
389 static std::regex queue_regex(R
"((rx|tx)_q(\d+)_([^_]+))");
392 if ( std::regex_match(name,
match, queue_regex) ) {
393 auto queue_name =
match[1].str() +
'-' +
match[2].str();
394 auto & entry = xq[queue_name];
403 google::protobuf::Message * metric_p =
nullptr;
404 static std::regex err_regex(R
"(.+error.*)");
405 if ( std::regex_match( name, err_regex ) ) metric_p = & xerrs;
406 else metric_p = & xinfos;
417 m_iface_xstats.reset_counters();
420 publish( std::move(xinfos) );
421 publish( std::move(xerrs) );
422 for (
auto [
id, stat] : xq ) {
423 publish( std::move(stat), {{
"queue",
id}} );
426 for(
const auto& [src_rx_q,_] : m_num_frames_rxq) {
428 i.set_packets_received( m_num_frames_rxq[src_rx_q].load() );
429 i.set_bytes_received( m_num_bytes_rxq[src_rx_q].load() );
430 i.set_full_rx_burst( m_num_full_bursts[src_rx_q].load() );
431 i.set_max_burst_size( m_max_burst_size[src_rx_q].exchange(0) );
433 publish( std::move(i), {{
"queue", std::to_string(src_rx_q)}} );
439IfaceWrapper::garp_func()
441 TLOG() <<
"Launching GARP sender...";
442 while(m_run_marker.load()) {
443 for(
const auto& ip_addr_bin : m_ip_addr_bin ) {
447 std::this_thread::sleep_for(std::chrono::seconds(1));
449 TLOG() <<
"GARP function joins.";
454IfaceWrapper::handle_eth_payload(
int src_rx_q,
char*
payload, std::size_t
size)
458 auto src_id = m_stream_id_to_source_id[src_rx_q][(unsigned)daq_header->stream_id];
460 if (
auto src_it = m_sources.find(
src_id); src_it != m_sources.end()) {
466 if (m_num_unexid_frames.count(
src_id) == 0) {
467 m_num_unexid_frames[
src_id] = 0;
469 m_num_unexid_frames[
src_id]++;
@ TLVL_ENTER_EXIT_METHODS
Base class for any user define issue.
std::atomic< bool > run_marker
Global atomic for process lifetime.
#define TLVL_ENTER_EXIT_METHODS
#define TLOG_DEBUG(lvl,...)
dunedaq::conffwk::relationship_t match(T const &, T const &)
void pktgen_send_garp(struct rte_mbuf *m, uint32_t port_id, rte_be32_t binary_ip_address)
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)
int iface_promiscuous_mode(std::uint16_t iface, bool mode=false)
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)
rte_be32_t ip_address_dotdecimal_to_binary(std::uint8_t byte1, std::uint8_t byte2, std::uint8_t byte3, std::uint8_t byte4)
struct rte_flow * generate_ipv4_flow(uint16_t port_id, uint16_t rx_q, uint32_t src_ip, uint32_t src_mask, uint32_t dest_ip, uint32_t dest_mask, struct rte_flow_error *error)
struct rte_flow * generate_arp_flow(uint16_t port_id, uint16_t rx_q, struct rte_flow_error *error)
void set_value(google::protobuf::Message &m, const std::string &name, T value)
FELIX Initialization std::string initerror FELIX queue timed std::string queuename Unexpected chunk size
void warning(const Issue &issue)
void fatal(const Issue &issue)
Factory couldn t std::string alg_name Invalid configuration error