} void CCPortLatency::Delete(){ m_hist.Delete(); } void CCPortLatency::update_packet(rte_mbuf_t * m, int port_id){ uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); bool is_client_to_server=(port_id%2==0)?true:false; /* update mac addr dest/src 12 bytes */ memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(m_id),12); latency_header * h=(latency_header *)(p+m_payload_offset); h->magic = LATENCY_MAGIC | m_id ; h->time_stamp = os_get_hr_tick_64(); h->seq = m_tx_seq; m_tx_seq++; CLatencyPktMode *c_l_pkt_mode = m_parent->c_l_pkt_mode; c_l_pkt_mode->update_pkt(p + m_l4_offset, is_client_to_server, m_pkt_size - m_l4_offset, &m_icmp_tx_seq); } void CCPortLatency::DumpShortHeader(FILE *fd){ fprintf(fd," if| tx_ok , rx_ok , rx check ,error, latency (usec) , Jitter max window \n"); fprintf(fd," | , , , , average , max , (usec) \n"); fprintf(fd," ---------------------------------------------------------------------------------------------------------------- \n"); }
// return false if no counters changed since last run. true otherwise // s_json - flow statistics json // l_json - latency data json // baseline - If true, send flow statistics fields even if they were not changed since last run bool CFlowStatRuleMgr::dump_json(std::string & s_json, std::string & l_json, bool baseline) { rx_per_flow_t rx_stats[MAX_FLOW_STATS]; rx_per_flow_t rx_stats_payload[MAX_FLOW_STATS]; tx_per_flow_t tx_stats[MAX_FLOW_STATS]; tx_per_flow_t tx_stats_payload[MAX_FLOW_STATS_PAYLOAD]; rfc2544_info_t rfc2544_info[MAX_FLOW_STATS_PAYLOAD]; Json::FastWriter writer; Json::Value s_root; Json::Value l_root; s_root["name"] = "flow_stats"; s_root["type"] = 0; l_root["name"] = "latency_stats"; l_root["type"] = 0; if (baseline) { s_root["baseline"] = true; l_root["baseline"] = true; } Json::Value &s_data_section = s_root["data"]; Json::Value &l_data_section = l_root["data"]; s_data_section["ts"]["value"] = Json::Value::UInt64(os_get_hr_tick_64()); s_data_section["ts"]["freq"] = Json::Value::UInt64(os_get_hr_freq()); if (m_user_id_map.is_empty()) { s_json = writer.write(s_root); l_json = writer.write(l_root); return true; } m_api->get_rfc2544_info(rfc2544_info, 0, m_max_hw_id_payload, false); // read hw counters, and update for (uint8_t port = 0; port < m_num_ports; port++) { m_api->get_flow_stats(port, rx_stats, (void *)tx_stats, 0, m_max_hw_id, false, TrexPlatformApi::IF_STAT_IPV4_ID); for (int i = 0; i <= m_max_hw_id; i++) { if (rx_stats[i].get_pkts() != 0) { rx_per_flow_t rx_pkts = rx_stats[i]; CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i)); if (likely(p_user_id != NULL)) { if (p_user_id->get_rx_cntr(port) != rx_pkts) { p_user_id->set_rx_cntr(port, rx_pkts); p_user_id->set_need_to_send_rx(port); } } else { std::cerr << __METHOD_NAME__ << i << ":Could not count " << rx_pkts << " rx packets, on port " << (uint16_t)port << ", because no mapping was found." << std::endl; } } if (tx_stats[i].get_pkts() != 0) { tx_per_flow_t tx_pkts = tx_stats[i]; CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map.get_user_id(i)); if (likely(p_user_id != NULL)) { if (p_user_id->get_tx_cntr(port) != tx_pkts) { p_user_id->set_tx_cntr(port, tx_pkts); p_user_id->set_need_to_send_tx(port); } } else { std::cerr << __METHOD_NAME__ << i << ":Could not count " << tx_pkts << " tx packets on port " << (uint16_t)port << ", because no mapping was found." << std::endl; } } } // payload rules m_api->get_flow_stats(port, rx_stats_payload, (void *)tx_stats_payload, 0, m_max_hw_id_payload , false, TrexPlatformApi::IF_STAT_PAYLOAD); for (int i = 0; i <= m_max_hw_id_payload; i++) { if (rx_stats_payload[i].get_pkts() != 0) { rx_per_flow_t rx_pkts = rx_stats_payload[i]; CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map_payload.get_user_id(i)); if (likely(p_user_id != NULL)) { if (p_user_id->get_rx_cntr(port) != rx_pkts) { p_user_id->set_rx_cntr(port, rx_pkts); p_user_id->set_need_to_send_rx(port); } } else { std::cerr << __METHOD_NAME__ << i << ":Could not count " << rx_pkts << " rx payload packets, on port " << (uint16_t)port << ", because no mapping was found." << std::endl; } } if (tx_stats_payload[i].get_pkts() != 0) { tx_per_flow_t tx_pkts = tx_stats_payload[i]; CFlowStatUserIdInfo *p_user_id = m_user_id_map.find_user_id(m_hw_id_map_payload.get_user_id(i)); if (likely(p_user_id != NULL)) { if (p_user_id->get_tx_cntr(port) != tx_pkts) { p_user_id->set_tx_cntr(port, tx_pkts); p_user_id->set_need_to_send_tx(port); } } else { std::cerr << __METHOD_NAME__ << i << ":Could not count " << tx_pkts << " tx packets on port " << (uint16_t)port << ", because no mapping was found." << std::endl; } } } } // build json report flow_stat_user_id_map_it_t it; for (it = m_user_id_map.begin(); it != m_user_id_map.end(); it++) { bool send_empty = true; CFlowStatUserIdInfo *user_id_info = it->second; uint32_t user_id = it->first; std::string str_user_id = static_cast<std::ostringstream*>( &(std::ostringstream() << user_id) )->str(); if (! user_id_info->was_sent()) { s_data_section[str_user_id]["first_time"] = true; user_id_info->set_was_sent(true); send_empty = false; } for (uint8_t port = 0; port < m_num_ports; port++) { std::string str_port = static_cast<std::ostringstream*>( &(std::ostringstream() << int(port) ) )->str(); if (user_id_info->need_to_send_rx(port) || baseline) { user_id_info->set_no_need_to_send_rx(port); s_data_section[str_user_id]["rx_pkts"][str_port] = Json::Value::UInt64(user_id_info->get_rx_cntr(port).get_pkts()); if (m_cap & TrexPlatformApi::IF_STAT_RX_BYTES_COUNT) s_data_section[str_user_id]["rx_bytes"][str_port] = Json::Value::UInt64(user_id_info->get_rx_cntr(port).get_bytes()); send_empty = false; } if (user_id_info->need_to_send_tx(port) || baseline) { user_id_info->set_no_need_to_send_tx(port); s_data_section[str_user_id]["tx_pkts"][str_port] = Json::Value::UInt64(user_id_info->get_tx_cntr(port).get_pkts()); s_data_section[str_user_id]["tx_bytes"][str_port] = Json::Value::UInt64(user_id_info->get_tx_cntr(port).get_bytes()); send_empty = false; } } if (send_empty) { s_data_section[str_user_id] = Json::objectValue; } if (user_id_info->rfc2544_support()) { CFlowStatUserIdInfoPayload *user_id_info_p = (CFlowStatUserIdInfoPayload *)user_id_info; // payload object. Send also latency, jitter... Json::Value lat_hist; if (user_id_info->is_hw_id()) { // if mapped to hw_id, take info from what we just got from rx core uint16_t hw_id = user_id_info->get_hw_id(); rfc2544_info[hw_id].get_latency_json(lat_hist); user_id_info_p->set_seq_err_cnt(rfc2544_info[hw_id].get_seq_err_cnt()); user_id_info_p->set_ooo_cnt(rfc2544_info[hw_id].get_ooo_cnt()); user_id_info_p->set_dup_cnt(rfc2544_info[hw_id].get_dup_cnt()); user_id_info_p->set_seq_err_big_cnt(rfc2544_info[hw_id].get_seq_err_ev_big()); user_id_info_p->set_seq_err_low_cnt(rfc2544_info[hw_id].get_seq_err_ev_low()); l_data_section[str_user_id]["latency"]["h"] = lat_hist; l_data_section[str_user_id]["latency"]["last_max"] = rfc2544_info[hw_id].get_last_max_usec(); l_data_section[str_user_id]["latency"]["jitter"] = rfc2544_info[hw_id].get_jitter_usec(); } else { // Not mapped to hw_id. Get saved info. user_id_info_p->get_latency_json(lat_hist); l_data_section[str_user_id]["latency"]["h"] = lat_hist; l_data_section[str_user_id]["latency"]["last_max"] = 0; l_data_section[str_user_id]["latency"]["jitter"] = user_id_info_p->get_jitter_usec(); } //todo: add last 10 samples l_data_section[str_user_id]["err_cntrs"]["dropped"] = Json::Value::UInt64(user_id_info_p->get_seq_err_cnt()); l_data_section[str_user_id]["err_cntrs"]["out_of_order"] = Json::Value::UInt64(user_id_info_p->get_ooo_cnt()); l_data_section[str_user_id]["err_cntrs"]["dup"] = Json::Value::UInt64(user_id_info_p->get_dup_cnt()); l_data_section[str_user_id]["err_cntrs"]["seq_too_high"] = Json::Value::UInt64(user_id_info_p->get_seq_err_big_cnt()); l_data_section[str_user_id]["err_cntrs"]["seq_too_low"] = Json::Value::UInt64(user_id_info_p->get_seq_err_low_cnt()); } } s_json = writer.write(s_root); l_json = writer.write(l_root); // We always want to publish, even only the timestamp. return true; }