From 868116efa893bb4c0c007b05f4381dc889349c93 Mon Sep 17 00:00:00 2001 From: "Liu, An-Chi" Date: Wed, 27 Dec 2023 17:53:16 +0900 Subject: [PATCH 1/2] Use `std::function` for live device callbacks (#1273) --- Pcap++/header/PcapLiveDevice.h | 18 +++--- Pcap++/src/PcapLiveDevice.cpp | 10 +-- Tests/Pcap++Test/TestDefinition.h | 2 + Tests/Pcap++Test/Tests/LiveDeviceTests.cpp | 72 ++++++++++++++++++++++ Tests/Pcap++Test/main.cpp | 2 + 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/Pcap++/header/PcapLiveDevice.h b/Pcap++/header/PcapLiveDevice.h index f957dc450c..2336cd1941 100644 --- a/Pcap++/header/PcapLiveDevice.h +++ b/Pcap++/header/PcapLiveDevice.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "IpAddress.h" #include "Packet.h" @@ -29,32 +30,29 @@ namespace pcpp class PcapLiveDevice; /** - * @typedef OnPacketArrivesCallback * A callback that is called when a packet is captured by PcapLiveDevice - * @param[in] pPacket A pointer to the raw packet - * @param[in] pDevice A pointer to the PcapLiveDevice instance + * @param[in] packet A pointer to the raw packet + * @param[in] device A pointer to the PcapLiveDevice instance * @param[in] userCookie A pointer to the object put by the user when packet capturing stared */ - typedef void (*OnPacketArrivesCallback)(RawPacket* pPacket, PcapLiveDevice* pDevice, void* userCookie); + using OnPacketArrivesCallback = std::function; /** - * @typedef OnPacketArrivesStopBlocking * A callback that is called when a packet is captured by PcapLiveDevice - * @param[in] pPacket A pointer to the raw packet - * @param[in] pDevice A pointer to the PcapLiveDevice instance + * @param[in] packet A pointer to the raw packet + * @param[in] device A pointer to the PcapLiveDevice instance * @param[in] userCookie A pointer to the object put by the user when packet capturing stared * @return True when main thread should stop blocking or false otherwise */ - typedef bool (*OnPacketArrivesStopBlocking)(RawPacket* pPacket, PcapLiveDevice* pDevice, void* userCookie); + using OnPacketArrivesStopBlocking = std::function; /** - * @typedef OnStatsUpdateCallback * A callback that is called periodically for stats collection if user asked to start packet capturing with periodic stats collection * @param[in] stats A reference to the most updated stats * @param[in] userCookie A pointer to the object put by the user when packet capturing stared */ - typedef void (*OnStatsUpdateCallback)(IPcapDevice::PcapStats& stats, void* userCookie); + using OnStatsUpdateCallback = std::function; // for internal use only typedef void* (*ThreadStart)(void*); diff --git a/Pcap++/src/PcapLiveDevice.cpp b/Pcap++/src/PcapLiveDevice.cpp index c90f39001f..4a79ff41c3 100644 --- a/Pcap++/src/PcapLiveDevice.cpp +++ b/Pcap++/src/PcapLiveDevice.cpp @@ -426,12 +426,12 @@ PcapLiveDevice* PcapLiveDevice::clone() bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie) { - return startCapture(onPacketArrives, onPacketArrivesUserCookie, 0, nullptr, nullptr); + return startCapture(std::move(onPacketArrives), onPacketArrivesUserCookie, 0, nullptr, nullptr); } bool PcapLiveDevice::startCapture(int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie) { - return startCapture(nullptr, nullptr, intervalInSecondsToUpdateStats, onStatsUpdate, onStatsUpdateUserCookie); + return startCapture(nullptr, nullptr, intervalInSecondsToUpdateStats, std::move(onStatsUpdate), onStatsUpdateUserCookie); } bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* onPacketArrivesUserCookie, int intervalInSecondsToUpdateStats, OnStatsUpdateCallback onStatsUpdate, void* onStatsUpdateUserCookie) @@ -451,7 +451,7 @@ bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* m_IntervalToUpdateStats = intervalInSecondsToUpdateStats; m_CaptureCallbackMode = true; - m_cbOnPacketArrives = onPacketArrives; + m_cbOnPacketArrives = std::move(onPacketArrives); m_cbOnPacketArrivesUserCookie = onPacketArrivesUserCookie; m_CaptureThread = std::thread(&pcpp::PcapLiveDevice::captureThreadMain, this); @@ -460,7 +460,7 @@ bool PcapLiveDevice::startCapture(OnPacketArrivesCallback onPacketArrives, void* if (onStatsUpdate != nullptr && intervalInSecondsToUpdateStats > 0) { - m_cbOnStatsUpdate = onStatsUpdate; + m_cbOnStatsUpdate = std::move(onStatsUpdate); m_cbOnStatsUpdateUserCookie = onStatsUpdateUserCookie; m_StatsThread = std::thread(&pcpp::PcapLiveDevice::statsThreadMain, this); m_StatsThreadStarted = true; @@ -515,7 +515,7 @@ int PcapLiveDevice::startCaptureBlockingMode(OnPacketArrivesStopBlocking onPacke m_cbOnPacketArrivesUserCookie = nullptr; m_cbOnStatsUpdateUserCookie = nullptr; - m_cbOnPacketArrivesBlockingMode = onPacketArrives; + m_cbOnPacketArrivesBlockingMode = std::move(onPacketArrives); m_cbOnPacketArrivesBlockingModeUserCookie = userCookie; m_CaptureThreadStarted = true; diff --git a/Tests/Pcap++Test/TestDefinition.h b/Tests/Pcap++Test/TestDefinition.h index cc03d8d744..ce6fade0a3 100644 --- a/Tests/Pcap++Test/TestDefinition.h +++ b/Tests/Pcap++Test/TestDefinition.h @@ -36,6 +36,8 @@ PTF_TEST_CASE(TestPcapLiveDeviceClone); PTF_TEST_CASE(TestPcapLiveDeviceNoNetworking); PTF_TEST_CASE(TestPcapLiveDeviceStatsMode); PTF_TEST_CASE(TestPcapLiveDeviceBlockingMode); +PTF_TEST_CASE(TestPcapLiveDeviceWithLambda); +PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeWithLambda); PTF_TEST_CASE(TestPcapLiveDeviceSpecialCfg); PTF_TEST_CASE(TestWinPcapLiveDevice); PTF_TEST_CASE(TestSendPacket); diff --git a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp index c2bb2be257..c0309f33f2 100644 --- a/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp +++ b/Tests/Pcap++Test/Tests/LiveDeviceTests.cpp @@ -477,6 +477,78 @@ PTF_TEST_CASE(TestPcapLiveDeviceBlockingMode) } // TestPcapLiveDeviceBlockingMode +PTF_TEST_CASE(TestPcapLiveDeviceWithLambda) +{ + pcpp::PcapLiveDevice* liveDev = nullptr; + pcpp::IPv4Address ipToSearch(PcapTestGlobalArgs.ipToSendReceivePackets.c_str()); + liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(ipToSearch); + PTF_ASSERT_NOT_NULL(liveDev); + PTF_ASSERT_GREATER_THAN(liveDev->getMtu(), 0); + PTF_ASSERT_TRUE(liveDev->open()); + DeviceTeardown devTeardown(liveDev); + int packetCount = 0; + int numOfTimeStatsWereInvoked = 0; + + auto packetArrivesLambda = [](pcpp::RawPacket* rawPacket, pcpp::PcapLiveDevice* pDevice, void* userCookie) + { + (*(int*)userCookie)++; + }; + + auto statsUpdateLambda = [](pcpp::IPcapDevice::PcapStats& stats, void* userCookie) + { + (*(int*)userCookie)++; + }; + + PTF_ASSERT_TRUE(liveDev->startCapture(packetArrivesLambda , (void*)&packetCount, 1, statsUpdateLambda, (void*)&numOfTimeStatsWereInvoked)); + int totalSleepTime = 0; + while (totalSleepTime <= 20) + { + pcpp::multiPlatformSleep(2); + totalSleepTime += 2; + if (packetCount > 0) + break; + } + + PTF_PRINT_VERBOSE("Total sleep time: " << totalSleepTime << " secs"); + + liveDev->stopCapture(); + PTF_ASSERT_GREATER_THAN(packetCount, 0); + PTF_ASSERT_GREATER_OR_EQUAL_THAN(numOfTimeStatsWereInvoked, totalSleepTime-2); +} // TestPcapLiveDeviceWithLambda + + + +PTF_TEST_CASE(TestPcapLiveDeviceBlockingModeWithLambda) +{ + auto packetArrivesBlockingModeNoTimeoutLambda = []( + pcpp::RawPacket *rawPacket, pcpp::PcapLiveDevice *dev, void *userCookie) + { + int *packetCount = (int *)userCookie; + if ((*packetCount) == 5) + return true; + + (*packetCount)++; + return false; + }; + + // open device + pcpp::PcapLiveDevice* liveDev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(PcapTestGlobalArgs.ipToSendReceivePackets.c_str()); + PTF_ASSERT_NOT_NULL(liveDev); + PTF_ASSERT_TRUE(liveDev->open()); + DeviceTeardown devTeardown(liveDev); + + int packetCount = 0; + PTF_ASSERT_EQUAL(liveDev->startCaptureBlockingMode(packetArrivesBlockingModeNoTimeoutLambda, &packetCount, 30), 1); + PTF_ASSERT_EQUAL(packetCount, 5); + + liveDev->close(); + + // a negative test + pcpp::Logger::getInstance().suppressLogs(); + PTF_ASSERT_FALSE(liveDev->startCapture(packetArrives, &packetCount)); + pcpp::Logger::getInstance().enableLogs(); +} // TestPcapLiveDeviceBlockingModeWithLambda + PTF_TEST_CASE(TestPcapLiveDeviceSpecialCfg) diff --git a/Tests/Pcap++Test/main.cpp b/Tests/Pcap++Test/main.cpp index a4af1391c3..b1a5904266 100644 --- a/Tests/Pcap++Test/main.cpp +++ b/Tests/Pcap++Test/main.cpp @@ -229,6 +229,8 @@ int main(int argc, char* argv[]) PTF_RUN_TEST(TestPcapLiveDeviceNoNetworking, "no_network;live_device"); PTF_RUN_TEST(TestPcapLiveDeviceStatsMode, "live_device"); PTF_RUN_TEST(TestPcapLiveDeviceBlockingMode, "live_device"); + PTF_RUN_TEST(TestPcapLiveDeviceWithLambda, "live_device"); + PTF_RUN_TEST(TestPcapLiveDeviceBlockingModeWithLambda, "live_device"); PTF_RUN_TEST(TestPcapLiveDeviceSpecialCfg, "live_device"); PTF_RUN_TEST(TestWinPcapLiveDevice, "live_device;winpcap"); PTF_RUN_TEST(TestSendPacket, "live_device;send"); From 96987d2026fafbbfd45ceadf495dab6df91abe5f Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 27 Dec 2023 08:34:22 -0800 Subject: [PATCH 2/2] DPDK filter traffic example app improvements (#1271) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * - Make stats more readable - Add DNS and TLS to stats - Minor fixes * Change worker config to convention --------- Co-authored-by: Clément Péron --- .../AppWorkerThread.h | 20 +- Examples/DpdkExample-FilterTraffic/Common.h | 172 +++++++----------- Examples/DpdkExample-FilterTraffic/main.cpp | 82 ++++++--- 3 files changed, 139 insertions(+), 135 deletions(-) diff --git a/Examples/DpdkExample-FilterTraffic/AppWorkerThread.h b/Examples/DpdkExample-FilterTraffic/AppWorkerThread.h index 059a108b56..d465418bfb 100644 --- a/Examples/DpdkExample-FilterTraffic/AppWorkerThread.h +++ b/Examples/DpdkExample-FilterTraffic/AppWorkerThread.h @@ -46,14 +46,14 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread { m_CoreId = coreId; m_Stop = false; - m_Stats.WorkerId = coreId; - pcpp::DpdkDevice* sendPacketsTo = m_WorkerConfig.SendPacketsTo; + m_Stats.workerId = coreId; + pcpp::DpdkDevice* sendPacketsTo = m_WorkerConfig.sendPacketsTo; pcpp::PcapFileWriterDevice* pcapWriter = NULL; // if needed, create the pcap file writer which all matched packets will be written into - if (m_WorkerConfig.WriteMatchedPacketsToFile) + if (m_WorkerConfig.writeMatchedPacketsToFile) { - pcapWriter = new pcpp::PcapFileWriterDevice(m_WorkerConfig.PathToWritePackets.c_str()); + pcapWriter = new pcpp::PcapFileWriterDevice(m_WorkerConfig.pathToWritePackets.c_str()); if (!pcapWriter->open()) { EXIT_WITH_ERROR("Couldn't open pcap writer device"); @@ -61,7 +61,7 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread } // if no DPDK devices were assigned to this worker/core don't enter the main loop and exit - if (m_WorkerConfig.InDataCfg.size() == 0) + if (m_WorkerConfig.inDataCfg.size() == 0) { return true; } @@ -74,7 +74,7 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread while (!m_Stop) { // go over all DPDK devices configured for this worker/core - for (const auto &iter : m_WorkerConfig.InDataCfg) + for (const auto &iter : m_WorkerConfig.inDataCfg) { // for each DPDK device go over all RX queues configured for this worker/core for (const auto &iter2 : iter.second) @@ -92,7 +92,7 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread // collect packet statistics m_Stats.collectStats(parsedPacket); - bool packetMatched = false; + bool packetMatched; // hash the packet by 5-tuple and look in the flow table to see whether this packet belongs to an existing or new flow uint32_t hash = pcpp::hash5Tuple(&parsedPacket); @@ -114,11 +114,11 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread //collect stats if (parsedPacket.isPacketOfType(pcpp::TCP)) { - m_Stats.MatchedTcpFlows++; + m_Stats.matchedTcpFlows++; } else if (parsedPacket.isPacketOfType(pcpp::UDP)) { - m_Stats.MatchedUdpFlows++; + m_Stats.matchedUdpFlows++; } } @@ -138,7 +138,7 @@ class AppWorkerThread : public pcpp::DpdkWorkerThread pcapWriter->writePacket(*packetArr[i]); } - m_Stats.MatchedPackets++; + m_Stats.matchedPackets++; } } } diff --git a/Examples/DpdkExample-FilterTraffic/Common.h b/Examples/DpdkExample-FilterTraffic/Common.h index 113d73aeb6..d3c882e96b 100644 --- a/Examples/DpdkExample-FilterTraffic/Common.h +++ b/Examples/DpdkExample-FilterTraffic/Common.h @@ -40,15 +40,14 @@ typedef std::map > InputDataConfig; */ struct AppWorkerConfig { - uint32_t CoreId; - InputDataConfig InDataCfg; - pcpp::DpdkDevice* SendPacketsTo; - bool WriteMatchedPacketsToFile; - std::string PathToWritePackets; - - AppWorkerConfig() : CoreId(MAX_NUM_OF_CORES+1), SendPacketsTo(NULL), WriteMatchedPacketsToFile(false), PathToWritePackets("") - { - } + uint32_t coreId; + InputDataConfig inDataCfg; + pcpp::DpdkDevice* sendPacketsTo; + bool writeMatchedPacketsToFile; + std::string pathToWritePackets; + + AppWorkerConfig() : coreId(MAX_NUM_OF_CORES+1), sendPacketsTo(nullptr), + writeMatchedPacketsToFile(false), pathToWritePackets("") {} }; @@ -58,115 +57,84 @@ struct AppWorkerConfig struct PacketStats { public: - uint8_t WorkerId; - - int PacketCount; - int EthCount; - int ArpCount; - int Ip4Count; - int Ip6Count; - int TcpCount; - int UdpCount; - int HttpCount; - - int MatchedTcpFlows; - int MatchedUdpFlows; - int MatchedPackets; - - PacketStats() : WorkerId(MAX_NUM_OF_CORES+1), PacketCount(0), EthCount(0), ArpCount(0), Ip4Count(0), Ip6Count(0), TcpCount(0), UdpCount(0), HttpCount(0), MatchedTcpFlows(0), MatchedUdpFlows(0), MatchedPackets(0) {} + uint8_t workerId; + + int packetCount; + int ethCount; + int arpCount; + int ipv4Count; + int ipv6Count; + int tcpCount; + int udpCount; + int httpCount; + int dnsCount; + int tlsCount; + + int matchedTcpFlows; + int matchedUdpFlows; + int matchedPackets; + + PacketStats() : workerId(MAX_NUM_OF_CORES+1), packetCount(0), ethCount(0), arpCount(0), ipv4Count(0), ipv6Count(0), + tcpCount(0), udpCount(0), httpCount(0), dnsCount(0), tlsCount(0), + matchedTcpFlows(0), matchedUdpFlows(0), matchedPackets(0) {} void collectStats(pcpp::Packet& packet) { - PacketCount++; + packetCount++; if (packet.isPacketOfType(pcpp::Ethernet)) - EthCount++; + ethCount++; if (packet.isPacketOfType(pcpp::ARP)) - ArpCount++; + arpCount++; if (packet.isPacketOfType(pcpp::IPv4)) - Ip4Count++; + ipv4Count++; if (packet.isPacketOfType(pcpp::IPv6)) - Ip6Count++; + ipv6Count++; if (packet.isPacketOfType(pcpp::TCP)) - TcpCount++; + tcpCount++; if (packet.isPacketOfType(pcpp::UDP)) - UdpCount++; + udpCount++; if (packet.isPacketOfType(pcpp::HTTP)) - HttpCount++; + httpCount++; + if (packet.isPacketOfType(pcpp::DNS)) + dnsCount++; + if (packet.isPacketOfType(pcpp::SSL)) + tlsCount++; } void collectStats(const PacketStats& stats) { - PacketCount += stats.PacketCount; - EthCount += stats.EthCount; - ArpCount += stats.ArpCount; - Ip4Count += stats.Ip4Count; - Ip6Count += stats.Ip6Count; - TcpCount += stats.TcpCount; - UdpCount += stats.UdpCount; - HttpCount += stats.HttpCount; - - MatchedTcpFlows += stats.MatchedTcpFlows; - MatchedUdpFlows += stats.MatchedUdpFlows; - MatchedPackets += stats.MatchedPackets; + packetCount += stats.packetCount; + ethCount += stats.ethCount; + arpCount += stats.arpCount; + ipv4Count += stats.ipv4Count; + ipv6Count += stats.ipv6Count; + tcpCount += stats.tcpCount; + udpCount += stats.udpCount; + httpCount += stats.httpCount; + dnsCount += stats.dnsCount; + tlsCount += stats.tlsCount; + + matchedTcpFlows += stats.matchedTcpFlows; + matchedUdpFlows += stats.matchedUdpFlows; + matchedPackets += stats.matchedPackets; } - void clear() { WorkerId = MAX_NUM_OF_CORES+1; PacketCount = 0; EthCount = 0; ArpCount = 0; Ip4Count = 0; Ip6Count = 0; TcpCount = 0; UdpCount = 0; HttpCount = 0; MatchedTcpFlows = 0; MatchedUdpFlows = 0; MatchedPackets = 0; } - - std::string getStatValuesAsString(const std::string &delimiter) + void clear() { - std::stringstream values; - if (WorkerId == MAX_NUM_OF_CORES+1) - values << "Total" << delimiter; - else - values << (int)WorkerId << delimiter; - values << PacketCount << delimiter; - values << EthCount << delimiter; - values << ArpCount << delimiter; - values << Ip4Count << delimiter; - values << Ip6Count << delimiter; - values << TcpCount << delimiter; - values << UdpCount << delimiter; - values << HttpCount << delimiter; - values << MatchedTcpFlows << delimiter; - values << MatchedUdpFlows << delimiter; - values << MatchedPackets; - - return values.str(); - } - - static void getStatsColumns(std::vector& columnNames, std::vector& columnWidths) - { - columnNames.clear(); - columnWidths.clear(); - - static const int narrowColumnWidth = 11; - static const int wideColumnWidth = 18; - - columnNames.push_back("Core ID"); - columnNames.push_back("Packet Cnt"); - columnNames.push_back("Eth Cnt"); - columnNames.push_back("ARP Cnt"); - columnNames.push_back("IPv4 Cnt"); - columnNames.push_back("IPv6 Cnt"); - columnNames.push_back("TCP Cnt"); - columnNames.push_back("UDP Cnt"); - columnNames.push_back("HTTP Cnt"); - columnNames.push_back("Matched TCP Flows"); - columnNames.push_back("Matched UDP Flows"); - columnNames.push_back("Matched Packets"); - - columnWidths.push_back(7); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(narrowColumnWidth); - columnWidths.push_back(wideColumnWidth); - columnWidths.push_back(wideColumnWidth); - columnWidths.push_back(wideColumnWidth); - + workerId = MAX_NUM_OF_CORES+1; + packetCount = 0; + ethCount = 0; + arpCount = 0; + ipv4Count = 0; + ipv6Count = 0; + tcpCount = 0; + udpCount = 0; + httpCount = 0; + dnsCount = 0; + tlsCount = 0; + + matchedTcpFlows = 0; + matchedUdpFlows = 0; + matchedPackets = 0; } }; diff --git a/Examples/DpdkExample-FilterTraffic/main.cpp b/Examples/DpdkExample-FilterTraffic/main.cpp index bbeacce543..83f2f6ab5f 100644 --- a/Examples/DpdkExample-FilterTraffic/main.cpp +++ b/Examples/DpdkExample-FilterTraffic/main.cpp @@ -23,7 +23,6 @@ #include "AppWorkerThread.h" #include "DpdkDeviceList.h" -#include "IPv4Layer.h" #include "TcpLayer.h" #include "UdpLayer.h" #include "SystemUtils.h" @@ -32,13 +31,10 @@ #include #include -#include #include -#include #include #include #include -#include #include @@ -179,31 +175,31 @@ void prepareCoreConfiguration(std::vector& dpdkDevicesToUse, for (const auto &core : coresToUse) { std::cout << "Using core " << (int)core.Id << std::endl; - workerConfigArr[i].CoreId = core.Id; - workerConfigArr[i].WriteMatchedPacketsToFile = writePacketsToDisk; + workerConfigArr[i].coreId = core.Id; + workerConfigArr[i].writeMatchedPacketsToFile = writePacketsToDisk; std::stringstream packetFileName; - packetFileName << packetFilePath << "Core" << workerConfigArr[i].CoreId << ".pcap"; - workerConfigArr[i].PathToWritePackets = packetFileName.str(); + packetFileName << packetFilePath << "Core" << workerConfigArr[i].coreId << ".pcap"; + workerConfigArr[i].pathToWritePackets = packetFileName.str(); - workerConfigArr[i].SendPacketsTo = sendPacketsTo; + workerConfigArr[i].sendPacketsTo = sendPacketsTo; for (int rxQIndex = 0; rxQIndex < numOfRxQueuesPerCore; rxQIndex++) { if (pairVecIter == deviceAndRxQVec.end()) break; - workerConfigArr[i].InDataCfg[pairVecIter->first].push_back(pairVecIter->second); + workerConfigArr[i].inDataCfg[pairVecIter->first].push_back(pairVecIter->second); ++pairVecIter; } if (rxQueuesRemainder > 0 && (pairVecIter != deviceAndRxQVec.end())) { - workerConfigArr[i].InDataCfg[pairVecIter->first].push_back(pairVecIter->second); + workerConfigArr[i].inDataCfg[pairVecIter->first].push_back(pairVecIter->second); ++pairVecIter; rxQueuesRemainder--; } // print configuration for core std::cout << " Core configuration:" << std::endl; - for (const auto &iter2 : workerConfigArr[i].InDataCfg) + for (const auto &iter2 : workerConfigArr[i].inDataCfg) { std::cout << " DPDK device#" << iter2.first->getDeviceId() << ": "; for (const auto &iter3 : iter2.second) @@ -212,7 +208,7 @@ void prepareCoreConfiguration(std::vector& dpdkDevicesToUse, } std::cout << std::endl; } - if (workerConfigArr[i].InDataCfg.size() == 0) + if (workerConfigArr[i].inDataCfg.size() == 0) { std::cout << " None" << std::endl; } @@ -229,6 +225,34 @@ struct FilterTrafficArgs FilterTrafficArgs() : shouldStop(false), workerThreadsVector(NULL) {} }; + +/** + * Print thread stats in a table + */ +void printStats(const PacketStats& threadStats, const std::string& columnName) +{ + std::vector columnNames = {columnName, "Count"}; + std::vector columnsWidths = {21, 10}; + pcpp::TablePrinter printer(columnNames, columnsWidths); + + printer.printRow("Eth count|" + std::to_string(threadStats.ethCount), '|'); + printer.printRow("ARP count|" + std::to_string(threadStats.arpCount), '|'); + printer.printRow("IPv4 count|" + std::to_string(threadStats.ipv4Count), '|'); + printer.printRow("IPv6 count|" + std::to_string(threadStats.ipv6Count), '|'); + printer.printRow("TCP count|" + std::to_string(threadStats.tcpCount), '|'); + printer.printRow("UDP count|" + std::to_string(threadStats.udpCount), '|'); + printer.printRow("HTTP count|" + std::to_string(threadStats.httpCount), '|'); + printer.printRow("DNS count|" + std::to_string(threadStats.dnsCount), '|'); + printer.printRow("TLS count|" + std::to_string(threadStats.tlsCount), '|'); + printer.printSeparator(); + printer.printRow("Matched TCP flows|" + std::to_string(threadStats.matchedTcpFlows), '|'); + printer.printRow("Matched UDP flows|" + std::to_string(threadStats.matchedUdpFlows), '|'); + printer.printSeparator(); + printer.printRow("Matched packet count|" + std::to_string(threadStats.matchedPackets), '|'); + printer.printRow("Total packet count|" + std::to_string(threadStats.packetCount), '|'); +} + + /** * The callback to be called when application is terminated by ctrl-c. Do cleanup and print summary stats */ @@ -241,25 +265,37 @@ void onApplicationInterrupted(void* cookie) // stop worker threads pcpp::DpdkDeviceList::getInstance().stopDpdkWorkerThreads(); - // create table printer - std::vector columnNames; - std::vector columnWidths; - PacketStats::getStatsColumns(columnNames, columnWidths); - pcpp::TablePrinter printer(columnNames, columnWidths); - // print final stats for every worker thread plus sum of all threads and free worker threads memory PacketStats aggregatedStats; + std::vector threadStatsVec; for (const auto &iter : *(args->workerThreadsVector)) { AppWorkerThread* thread = (AppWorkerThread*)(iter); PacketStats threadStats = thread->getStats(); aggregatedStats.collectStats(threadStats); - printer.printRow(threadStats.getStatValuesAsString("|"), '|'); + threadStatsVec.push_back(threadStats); delete thread; } - printer.printSeparator(); - printer.printRow(aggregatedStats.getStatValuesAsString("|"), '|'); + // print stats for every worker threads + for (auto threadStats : threadStatsVec) + { + // no need to print table if no packets were received + if (threadStats.packetCount == 0) + { + std::cout << "Core #" << std::to_string(threadStats.workerId) << " - no packets received" << std::endl; + continue; + } + + printStats(threadStats, "Core #" + std::to_string(threadStats.workerId) + " Stat"); + std::cout << std::endl; + } + + // print aggregated stats if packets were received + if (aggregatedStats.packetCount != 0) + { + printStats(aggregatedStats, "Aggregated Stats"); + } args->shouldStop = true; } @@ -284,7 +320,7 @@ int main(int argc, char* argv[]) int sendPacketsToPort = -1; int optionIndex = 0; - int opt = 0; + int opt; uint32_t mBufPoolSize = DEFAULT_MBUF_POOL_SIZE;