Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Pcap++/header/XdpDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
/// @
namespace pcpp
{
#define XDP_MAX_RXTX_QUEUES 16

/// @class XdpDevice
/// A class wrapping the main functionality of using AF_XDP (XSK) sockets
/// which are optimized for high performance packet processing.
Expand Down Expand Up @@ -76,6 +78,10 @@ namespace pcpp
/// The max number of packets to be received or sent in one batch
uint16_t rxTxBatchSize;

/// The queue identifier for the underlying socket. This value should be less than the number
/// of hardware queues supported by the device
uint16_t queueId;

/// A c'tor for this struct. Each parameter has a default value described below.
/// @param[in] attachMode AF_XDP operation mode. The default value is auto mode
/// @param[in] umemNumFrames Number of UMEM frames to allocate. The default value is 4096
Expand All @@ -87,10 +93,11 @@ namespace pcpp
/// @param[in] txSize The size of the TX ring used by the AF_XDP socket. The default value is 2048
/// @param[in] rxTxBatchSize The max number of packets to be received or sent in one batch. The default
/// value is 64
/// @param[in] queueId The hardware queue id of the underlying socket. The default value is 0
explicit XdpDeviceConfiguration(AttachMode attachMode = AutoMode, uint16_t umemNumFrames = 0,
uint16_t umemFrameSize = 0, uint32_t fillRingSize = 0,
uint32_t completionRingSize = 0, uint32_t rxSize = 0, uint32_t txSize = 0,
uint16_t rxTxBatchSize = 0)
uint16_t rxTxBatchSize = 0, uint32_t queueId = 0)
{
this->attachMode = attachMode;
this->umemNumFrames = umemNumFrames;
Expand All @@ -100,6 +107,7 @@ namespace pcpp
this->rxSize = rxSize;
this->txSize = txSize;
this->rxTxBatchSize = rxTxBatchSize;
this->queueId = queueId;
}
};

Expand Down Expand Up @@ -238,6 +246,24 @@ namespace pcpp
/// @return Current device statistics
XdpDeviceStats getStatistics();

/// @return Return queue identifier for underlying socket
uint32_t getQueueId() const
{
if(m_Config)
{
return m_Config->queueId;

}

return 0;
}

/// Get number of RX or TX hardware queues for device
/// @param[in] interfaceName The interface name to use to detect hardware queues
/// @param[in] tx If true, return TX queues, otherwise RX. Default is false
/// @return The number of hardware queues associated with the device.
static uint32_t numQueues(const std::string& interfaceName, bool tx = false);

private:
class XdpUmem
{
Expand Down
50 changes: 47 additions & 3 deletions Pcap++/src/XdpDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#include <net/if.h>
#include <sys/mman.h>
#include <unistd.h>
#include <dirent.h>
#include <vector>
#include <functional>
#include <algorithm>
#include <regex>
#include <poll.h>

namespace pcpp
Expand Down Expand Up @@ -403,8 +405,8 @@ namespace pcpp
auto umemInfo = static_cast<xsk_umem_info*>(m_Umem->getInfo());

struct xsk_socket_config xskConfig;
xskConfig.rx_size = m_Config->txSize;
xskConfig.tx_size = m_Config->rxSize;
xskConfig.rx_size = m_Config->rxSize;
xskConfig.tx_size = m_Config->txSize;
xskConfig.libbpf_flags = 0;
xskConfig.xdp_flags = 0;
xskConfig.bind_flags = 0;
Expand All @@ -419,7 +421,7 @@ namespace pcpp
xskConfig.xdp_flags = XDP_FLAGS_DRV_MODE;
}

int ret = xsk_socket__create(&socketInfo->xsk, m_InterfaceName.c_str(), 0, umemInfo->umem, &socketInfo->rx,
int ret = xsk_socket__create(&socketInfo->xsk, m_InterfaceName.c_str(), m_Config->queueId, umemInfo->umem, &socketInfo->rx,
&socketInfo->tx, &xskConfig);
if (ret)
{
Expand All @@ -429,6 +431,7 @@ namespace pcpp
}

m_SocketInfo = socketInfo;

return true;
}

Expand All @@ -449,6 +452,7 @@ namespace pcpp
uint32_t rxSize = config.rxSize ? config.rxSize : XSK_RING_CONS__DEFAULT_NUM_DESCS;
uint32_t txSize = config.txSize ? config.txSize : XSK_RING_PROD__DEFAULT_NUM_DESCS;
uint32_t batchSize = config.rxTxBatchSize ? config.rxTxBatchSize : DEFAULT_BATCH_SIZE;
uint32_t qId = config.queueId; // default is zero

if (frameSize != getpagesize())
{
Expand Down Expand Up @@ -499,13 +503,21 @@ namespace pcpp
return false;
}

unsigned int nhwqueues = numQueues(m_InterfaceName);
if (qId >= nhwqueues)
{
PCPP_LOG_ERROR("Queue Id (" << qId << ") must be less than the number hardware queues (" << nhwqueues << ") of device");
return false;
}

config.umemNumFrames = numFrames;
config.umemFrameSize = frameSize;
config.fillRingSize = fillRingSize;
config.completionRingSize = completionRingSize;
config.rxSize = rxSize;
config.txSize = txSize;
config.rxTxBatchSize = batchSize;
config.queueId = qId;

return true;
}
Expand Down Expand Up @@ -636,4 +648,36 @@ namespace pcpp
return m_Stats;
}

uint32_t XdpDevice::numQueues(const std::string& iface, bool tx)
{
// returns number of hardware queues associated with the device
uint32_t rxtxqueues = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we rename this to numQueues?

std::string prefix = tx ? "tx-" : "rx-";
std::string path = "/sys/class/net/" + iface + "/queues/";
DIR *dir = opendir(path.c_str());

if(dir)
{
std::regex rxtx_regex("^" + prefix + "[0-9]+$");

struct dirent* entry;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Curious why the struct dirent*? Can't we just do dirent*?

while((entry = readdir(dir)) != nullptr)
{
if(std::regex_match(entry->d_name, rxtx_regex))
{
rxtxqueues++;
}
}

closedir(dir);
}

else
{
PCPP_LOG_ERROR("Error getting number of hardware queues from " << iface);
}

return rxtxqueues;
}

} // namespace pcpp
Loading