From 18fb75f82a5f01d9e85c7c72859cfe068bc4b58f Mon Sep 17 00:00:00 2001 From: Dimitar Krastev Date: Sun, 16 Jun 2024 02:19:32 +0300 Subject: [PATCH] Refactor of PfRingDeviceList internals. (#1445) * Explicitly deleted copy ctors on PfRingDeviceList. * Changed PfRingDeviceList to use vector of smart pointers to hold devices. * C cast -> Cpp cast * Refactored PfRingDeviceList to utilize DeviceUtils to fetch all devices. * Changed while-loop to for-loop * Wrapped pfring ptr into a smart pointer and added a custom deleter. * Refactored calcPfRingVersion into a local function to the translation unit. * Changed equality with empty string to empty() call. * Lint * Changed type to auto. * Replaced sprintf with std::snprintf. * Fixed documentation. * Minor fixes. * Changed readPfRingVersion to return empty string on error. * Changed raw array to std::array. --- Pcap++/header/PfRingDeviceList.h | 18 ++--- Pcap++/src/PfRingDeviceList.cpp | 117 ++++++++++++++++++------------- 2 files changed, 76 insertions(+), 59 deletions(-) diff --git a/Pcap++/header/PfRingDeviceList.h b/Pcap++/header/PfRingDeviceList.h index 48e43ddaa4..d800862c21 100644 --- a/Pcap++/header/PfRingDeviceList.h +++ b/Pcap++/header/PfRingDeviceList.h @@ -2,6 +2,7 @@ // GCOVR_EXCL_START +#include #include "PfRingDevice.h" /// @file @@ -21,18 +22,17 @@ namespace pcpp class PfRingDeviceList { private: - std::vector m_PfRingDeviceList; + std::vector> m_PfRingDeviceList; + std::vector m_PfRingDeviceListView; std::string m_PfRingVersion; PfRingDeviceList(); - // private copy c'tor - PfRingDeviceList(const PfRingDeviceList& other); - PfRingDeviceList& operator=(const PfRingDeviceList& other); - // private d'tor - ~PfRingDeviceList(); - - void calcPfRingVersion(void* ring); public: + PfRingDeviceList(const PfRingDeviceList&) = delete; + PfRingDeviceList(PfRingDeviceList&&) noexcept = delete; + PfRingDeviceList& operator=(const PfRingDeviceList&) = delete; + PfRingDeviceList& operator=(PfRingDeviceList&&) noexcept = delete; + /** * A static method that returns the singleton object for PfRingDeviceList * @return PfRingDeviceList singleton @@ -47,7 +47,7 @@ namespace pcpp * Return a list of all available PF_RING devices * @return a list of all available PF_RING devices */ - const std::vector& getPfRingDevicesList() const { return m_PfRingDeviceList; } + const std::vector& getPfRingDevicesList() const { return m_PfRingDeviceListView; } /** * Get a PF_RING device by name. The name is the Linux interface name which appears in ifconfig diff --git a/Pcap++/src/PfRingDeviceList.cpp b/Pcap++/src/PfRingDeviceList.cpp index 5a26b3f74f..e2f1489c48 100644 --- a/Pcap++/src/PfRingDeviceList.cpp +++ b/Pcap++/src/PfRingDeviceList.cpp @@ -4,14 +4,55 @@ #define LOG_MODULE PcapLogModulePfRingDevice +#include +#include #include "PfRingDeviceList.h" #include "SystemUtils.h" +#include "DeviceUtils.h" #include "Logger.h" #include "pcap.h" #include "pfring.h" namespace pcpp { + /// @cond PCPP_INTERNAL + + namespace + { + /** + * @class PfRingCloseDeleter + * A deleter that cleans up a pfring structure by calling pfring_close. + */ + struct PfRingCloseDeleter + { + void operator()(pfring* ptr) const { pfring_close(ptr); } + }; + + /** + * Reads the ring version of a PF_RING handle. + * @param[in] ring A PF_RING handle. + * @return A string representation of the ring version or empty string if the read fails. + */ + std::string readPfRingVersion(pfring* ring) + { + uint32_t version; + if (pfring_version(ring, &version) < 0) + { + PCPP_LOG_ERROR("Couldn't retrieve PF_RING version, pfring_version returned an error"); + return {}; + } + + std::array versionAsString; + std::snprintf(versionAsString.data(), versionAsString.size(), "PF_RING v.%u.%u.%u\n", + (version & 0xFFFF0000) >> 16, + (version & 0x0000FF00) >> 8, + version & 0x000000FF); + + return std::string(versionAsString.data()); + } + } + + /// @endcond PfRingDeviceList::PfRingDeviceList() { @@ -37,50 +78,46 @@ PfRingDeviceList::PfRingDeviceList() PCPP_LOG_DEBUG("PF_RING kernel module is loaded"); - pcap_if_t* interfaceList; - char errbuf[PCAP_ERRBUF_SIZE]; PCPP_LOG_DEBUG("PfRingDeviceList init: searching all interfaces on machine"); - int err = pcap_findalldevs(&interfaceList, errbuf); - if (err < 0) + try { - PCPP_LOG_ERROR("Error searching for PF_RING devices: " << errbuf); - } + auto interfaceList = internal::getAllLocalPcapDevices(); - pcap_if_t* currInterface = interfaceList; - while (currInterface != NULL) - { - uint32_t flags = PF_RING_PROMISC | PF_RING_DNA_SYMMETRIC_RSS; - pfring* ring = pfring_open(currInterface->name, 128, flags); - if (ring != NULL) + for (pcap_if_t* currInterface = interfaceList.get(); currInterface != nullptr; currInterface = currInterface->next) { - if (m_PfRingVersion == "") - calcPfRingVersion(ring); - pfring_close(ring); - PfRingDevice* newDev = new PfRingDevice(currInterface->name); - m_PfRingDeviceList.push_back(newDev); - PCPP_LOG_DEBUG("Found interface: " << currInterface->name); + uint32_t flags = PF_RING_PROMISC | PF_RING_DNA_SYMMETRIC_RSS; + auto ring = std::unique_ptr(pfring_open(currInterface->name, 128, flags)); + if (ring != nullptr) + { + if (m_PfRingVersion.empty()) + { + m_PfRingVersion = readPfRingVersion(ring.get()); + PCPP_LOG_DEBUG("PF_RING version is: " << m_PfRingVersion); + } + std::unique_ptr newDev = std::unique_ptr(new PfRingDevice(currInterface->name)); + m_PfRingDeviceList.push_back(std::move(newDev)); + PCPP_LOG_DEBUG("Found interface: " << currInterface->name); + } } - - currInterface = currInterface->next; + } + catch (const std::runtime_error& e) + { + PCPP_LOG_ERROR("PfRingDeviceList init error: " << e.what()); } PCPP_LOG_DEBUG("PfRingDeviceList init end"); - pcap_freealldevs(interfaceList); -} -PfRingDeviceList::~PfRingDeviceList() -{ - for(auto devIter : m_PfRingDeviceList) - { - delete devIter; - } + // Full update of all elements of the view vector to synchronize them with the main vector. + m_PfRingDeviceListView.resize(m_PfRingDeviceList.size()); + std::transform(m_PfRingDeviceList.begin(), m_PfRingDeviceList.end(), m_PfRingDeviceListView.begin(), + [](const std::unique_ptr& ptr) { return ptr.get(); }); } PfRingDevice* PfRingDeviceList::getPfRingDeviceByName(const std::string &devName) const { PCPP_LOG_DEBUG("Searching all live devices..."); auto devIter = std::find_if(m_PfRingDeviceList.begin(), m_PfRingDeviceList.end(), - [&devName](const PfRingDevice *dev) { return dev->getDeviceName() == devName; }); + [&devName](const std::unique_ptr& dev) { return dev->getDeviceName() == devName; }); if (devIter == m_PfRingDeviceList.end()) { @@ -88,27 +125,7 @@ PfRingDevice* PfRingDeviceList::getPfRingDeviceByName(const std::string &devName return nullptr; } - return *devIter; -} - -void PfRingDeviceList::calcPfRingVersion(void* ring) -{ - pfring* ringPtr = (pfring*)ring; - uint32_t version; - if (pfring_version(ringPtr, &version) < 0) - { - PCPP_LOG_ERROR("Couldn't retrieve PF_RING version, pfring_version returned an error"); - return; - } - - char versionAsString[25]; - sprintf(versionAsString, "PF_RING v.%u.%u.%u\n", - (version & 0xFFFF0000) >> 16, - (version & 0x0000FF00) >> 8, - version & 0x000000FF); - - PCPP_LOG_DEBUG("PF_RING version is: " << versionAsString); - m_PfRingVersion = std::string(versionAsString); + return devIter->get(); } } // namespace pcpp