-
Notifications
You must be signed in to change notification settings - Fork 734
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 10 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,14 @@ namespace pcpp | |
| /// The max number of packets to be received or sent in one batch | ||
| uint16_t rxTxBatchSize; | ||
|
|
||
| /// This parameter specifies the amount of space designated for prepending data to the packet in the frame. | ||
| /// NOTE: the headroom size should be less than the frame size | ||
| uint16_t frameHeadroomSize; | ||
|
|
||
| /// 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,19 +97,24 @@ 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] frameHeadroomSize Space for prepending to packets. The default value is 0 | ||
| /// @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, uint16_t frameHeadroomSize = 0, | ||
| uint32_t queueId = 0) | ||
| { | ||
| this->attachMode = attachMode; | ||
| this->umemNumFrames = umemNumFrames; | ||
| this->umemFrameSize = umemFrameSize; | ||
| this->frameHeadroomSize = frameHeadroomSize; | ||
| this->fillRingSize = fillRingSize; | ||
| this->completionRingSize = completionRingSize; | ||
| this->rxSize = rxSize; | ||
| this->txSize = txSize; | ||
| this->rxTxBatchSize = rxTxBatchSize; | ||
| this->queueId = queueId; | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -238,11 +253,28 @@ 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 | ||
| { | ||
| public: | ||
| explicit XdpUmem(uint16_t numFrames, uint16_t frameSize, uint32_t fillRingSize, | ||
| explicit XdpUmem(uint16_t numFrames, uint16_t frameSize, uint16_t frameHeadroomSize, uint32_t fillRingSize, | ||
| uint32_t completionRingSize); | ||
|
|
||
| virtual ~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 | ||
|
|
@@ -36,10 +38,11 @@ namespace pcpp | |
| #define DEFAULT_FILL_RING_SIZE (XSK_RING_PROD__DEFAULT_NUM_DESCS * 2) | ||
| #define DEFAULT_COMPLETION_RING_SIZE XSK_RING_PROD__DEFAULT_NUM_DESCS | ||
| #define DEFAULT_BATCH_SIZE 64 | ||
| #define DEFAULT_FRAME_HEADROOM_SIZE XSK_UMEM__DEFAULT_FRAME_HEADROOM | ||
| #define IS_POWER_OF_TWO(num) (num && ((num & (num - 1)) == 0)) | ||
|
|
||
| XdpDevice::XdpUmem::XdpUmem(uint16_t numFrames, uint16_t frameSize, uint32_t fillRingSize, | ||
| uint32_t completionRingSize) | ||
| XdpDevice::XdpUmem::XdpUmem(uint16_t numFrames, uint16_t frameSize, uint16_t frameHeadroomSize, | ||
| uint32_t fillRingSize, uint32_t completionRingSize) | ||
| { | ||
| size_t bufferSize = numFrames * frameSize; | ||
|
|
||
|
|
@@ -51,7 +54,7 @@ namespace pcpp | |
| struct xsk_umem_config cfg = { .fill_size = fillRingSize, | ||
| .comp_size = completionRingSize, | ||
| .frame_size = frameSize, | ||
| .frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM, | ||
| .frame_headroom = frameHeadroomSize, | ||
| .flags = 0 }; | ||
|
|
||
| struct xsk_umem_info* umem = new xsk_umem_info; | ||
|
|
@@ -403,8 +406,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; | ||
|
Comment on lines
+410
to
+411
Owner
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. This was already fixed in #2030
Contributor
Author
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. Will that be a problem if I leave it like this? A merge issue? |
||
| xskConfig.libbpf_flags = 0; | ||
| xskConfig.xdp_flags = 0; | ||
| xskConfig.bind_flags = 0; | ||
|
|
@@ -419,8 +422,8 @@ 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, | ||
| &socketInfo->tx, &xskConfig); | ||
| int ret = xsk_socket__create(&socketInfo->xsk, m_InterfaceName.c_str(), m_Config->queueId, umemInfo->umem, | ||
| &socketInfo->rx, &socketInfo->tx, &xskConfig); | ||
| if (ret) | ||
| { | ||
| PCPP_LOG_ERROR("xsk_socket__create returned an error: " << ret); | ||
|
|
@@ -429,26 +432,29 @@ namespace pcpp | |
| } | ||
|
|
||
| m_SocketInfo = socketInfo; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool XdpDevice::initUmem() | ||
| { | ||
| m_Umem = new XdpUmem(m_Config->umemNumFrames, m_Config->umemFrameSize, m_Config->fillRingSize, | ||
| m_Config->completionRingSize); | ||
| m_Umem = new XdpUmem(m_Config->umemNumFrames, m_Config->umemFrameSize, m_Config->frameHeadroomSize, | ||
| m_Config->fillRingSize, m_Config->completionRingSize); | ||
| return true; | ||
| } | ||
|
|
||
| bool XdpDevice::populateConfigDefaults(XdpDeviceConfiguration& config) const | ||
| { | ||
| uint16_t numFrames = config.umemNumFrames ? config.umemNumFrames : DEFAULT_UMEM_NUM_FRAMES; | ||
| uint16_t frameSize = config.umemFrameSize ? config.umemFrameSize : getpagesize(); | ||
| uint16_t frameHeadroomSize = config.frameHeadroomSize ? config.frameHeadroomSize : DEFAULT_FRAME_HEADROOM_SIZE; | ||
| uint32_t fillRingSize = config.fillRingSize ? config.fillRingSize : DEFAULT_FILL_RING_SIZE; | ||
| uint32_t completionRingSize = | ||
| config.completionRingSize ? config.completionRingSize : DEFAULT_COMPLETION_RING_SIZE; | ||
| 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()) | ||
| { | ||
|
|
@@ -463,6 +469,12 @@ namespace pcpp | |
| return false; | ||
| } | ||
|
|
||
| if (frameHeadroomSize > frameSize) | ||
| { | ||
| PCPP_LOG_ERROR("Frame headroom size must be less than the frame size"); | ||
| return false; | ||
| } | ||
|
|
||
| if (fillRingSize > numFrames) | ||
| { | ||
| PCPP_LOG_ERROR("Fill ring size (" << fillRingSize | ||
|
|
@@ -499,13 +511,23 @@ 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.frameHeadroomSize = frameHeadroomSize; | ||
| config.fillRingSize = fillRingSize; | ||
| config.completionRingSize = completionRingSize; | ||
| config.rxSize = rxSize; | ||
| config.txSize = txSize; | ||
| config.rxTxBatchSize = batchSize; | ||
| config.queueId = qId; | ||
|
|
||
| return true; | ||
| } | ||
|
|
@@ -636,4 +658,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; | ||
|
||
| 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.