Skip to content

Commit

Permalink
Refactor of PfRingDeviceList internals. (#1445)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
Dimi1010 authored Jun 15, 2024
1 parent 09261f0 commit 18fb75f
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 59 deletions.
18 changes: 9 additions & 9 deletions Pcap++/header/PfRingDeviceList.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// GCOVR_EXCL_START

#include <memory>
#include "PfRingDevice.h"

/// @file
Expand All @@ -21,18 +22,17 @@ namespace pcpp
class PfRingDeviceList
{
private:
std::vector<PfRingDevice*> m_PfRingDeviceList;
std::vector<std::unique_ptr<PfRingDevice>> m_PfRingDeviceList;
std::vector<PfRingDevice*> 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
Expand All @@ -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<PfRingDevice*>& getPfRingDevicesList() const { return m_PfRingDeviceList; }
const std::vector<PfRingDevice*>& getPfRingDevicesList() const { return m_PfRingDeviceListView; }

/**
* Get a PF_RING device by name. The name is the Linux interface name which appears in ifconfig
Expand Down
117 changes: 67 additions & 50 deletions Pcap++/src/PfRingDeviceList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,55 @@

#define LOG_MODULE PcapLogModulePfRingDevice

#include <cstdio>
#include <array>
#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<char, 25> 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()
{
Expand All @@ -37,78 +78,54 @@ 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, PfRingCloseDeleter>(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<PfRingDevice> newDev = std::unique_ptr<PfRingDevice>(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<PfRingDevice>& 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<PfRingDevice>& dev) { return dev->getDeviceName() == devName; });

if (devIter == m_PfRingDeviceList.end())
{
PCPP_LOG_DEBUG("Found no PF_RING devices with name '" << 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
Expand Down

0 comments on commit 18fb75f

Please sign in to comment.