-
Notifications
You must be signed in to change notification settings - Fork 728
Specify queue id as a configuration parameter #2009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 5 commits
c7b00f5
fe735fe
db23ec3
a0906cf
e6a1e9b
7ab1f01
a8d97bf
cb5e47e
16c0da9
3b8c2d5
ca25dcc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
|
@@ -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 | ||
|
|
@@ -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; | ||
|
|
@@ -100,6 +107,7 @@ namespace pcpp | |
| this->rxSize = rxSize; | ||
| this->txSize = txSize; | ||
| this->rxTxBatchSize = rxTxBatchSize; | ||
| this->queueId = queueId; | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -238,6 +246,24 @@ namespace pcpp | |
| /// @return Current device statistics | ||
| XdpDeviceStats getStatistics(); | ||
|
|
||
| /// @return Return queue identifier for underlying socket | ||
| uint32_t getQueueId() | ||
|
||
| { | ||
| 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 getNumQueues(const std::string& interfaceName, bool tx = false); | ||
|
|
||
| private: | ||
| class XdpUmem | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -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) | ||
| { | ||
|
|
@@ -429,6 +431,7 @@ namespace pcpp | |
| } | ||
|
|
||
| m_SocketInfo = socketInfo; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -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()) | ||
| { | ||
|
|
@@ -499,13 +503,21 @@ namespace pcpp | |
| return false; | ||
| } | ||
|
|
||
| unsigned int nhwqueues = getNumQueues(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; | ||
| } | ||
|
|
@@ -636,4 +648,36 @@ namespace pcpp | |
| return m_Stats; | ||
| } | ||
|
|
||
| uint32_t XdpDevice::getNumQueues(const std::string& iface, bool tx) | ||
| { | ||
| // returns number of hardware queues associated with the device | ||
| uint32_t rxtxqueues = 0; | ||
|
||
| 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; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Curious why the |
||
| 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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This const isn't used anywhere, should we remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove. I think at first I was simply setting a hard limit before I created a function that can detect it. If the function cannot detect it, it returns 0 which may not be desirable. Maybe it should return 1 if nothing else. That will be the identical behavior in the release version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the default number 1. So a qid of zero, the default, and as things worked before, will pass the test.