Skip to content

Commit 3c9ae44

Browse files
committed
Dpdk: Add DPDK telemetry
1 parent 816a7cd commit 3c9ae44

File tree

5 files changed

+278
-0
lines changed

5 files changed

+278
-0
lines changed

Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ ipfixprobe_input_src+=\
182182
input/dpdk/dpdkDevice.cpp \
183183
input/dpdk/dpdkPortTelemetry.hpp \
184184
input/dpdk/dpdkPortTelemetry.cpp \
185+
input/dpdk/dpdkTelemetry.hpp \
186+
input/dpdk/dpdkTelemetry.cpp \
185187
input/dpdk.cpp \
186188
input/dpdk.h \
187189
input/dpdk-ring.cpp \

input/dpdk.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ void DpdkReader::configure_telemetry_dirs(
242242

243243
telemetry::FileOps statsOps = {[=]() { return get_queue_telemetry(); }, nullptr};
244244
register_file(queues_dir, "input-stats", statsOps);
245+
246+
m_dpdkTelemetry = std::make_unique<DpdkTelemetry>(plugin_dir);
245247
}
246248

247249
void DpdkReader::init(const char* params)

input/dpdk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "dpdk/dpdkDevice.hpp"
3434
#include "dpdk/dpdkPortTelemetry.hpp"
35+
#include "dpdk/dpdkTelemetry.hpp"
3536

3637
#include <ipfixprobe/input.hpp>
3738
#include <ipfixprobe/utils.hpp>
@@ -228,6 +229,7 @@ class DpdkReader : public InputPlugin {
228229
telemetry::Content get_port_telemetry(uint16_t portNumber);
229230

230231
std::vector<DpdkPortTelemetry> m_portsTelemetry;
232+
std::unique_ptr<DpdkTelemetry> m_dpdkTelemetry;
231233

232234
struct DpdkRxStats {
233235
uint64_t receivedPackets;

input/dpdk/dpdkTelemetry.cpp

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/**
2+
* \file
3+
* \brief Implementation of DpdkTelemetry class and helper functions for rings and mempools
4+
* information retrieval.
5+
* \author Pavel Siska <[email protected]>
6+
* \date 2024
7+
*/
8+
/*
9+
* Copyright (C) 2024 CESNET
10+
*
11+
* LICENSE TERMS
12+
*
13+
* Redistribution and use in source and binary forms, with or without
14+
* modification, are permitted provided that the following conditions
15+
* are met:
16+
* 1. Redistributions of source code must retain the above copyright
17+
* notice, this list of conditions and the following disclaimer.
18+
* 2. Redistributions in binary form must reproduce the above copyright
19+
* notice, this list of conditions and the following disclaimer in
20+
* the documentation and/or other materials provided with the
21+
* distribution.
22+
* 3. Neither the name of the Company nor the names of its contributors
23+
* may be used to endorse or promote products derived from this
24+
* software without specific prior written permission.
25+
*/
26+
27+
#include "dpdkTelemetry.hpp"
28+
29+
#include <stdexcept>
30+
#include <string>
31+
32+
#include <rte_eal_memconfig.h>
33+
#include <rte_mempool.h>
34+
#include <rte_ring.h>
35+
#include <rte_tailq.h>
36+
37+
namespace ipxp {
38+
39+
static void createRingsInfo(struct rte_ring* ring, void* arg)
40+
{
41+
std::string& buffer = *reinterpret_cast<std::string*>(arg);
42+
unsigned int count;
43+
unsigned int freeCount;
44+
unsigned int size;
45+
unsigned int capacity;
46+
int isFull;
47+
int isEmpty;
48+
49+
count = rte_ring_count(ring);
50+
freeCount = rte_ring_free_count(ring);
51+
size = rte_ring_get_size(ring);
52+
capacity = rte_ring_get_capacity(ring);
53+
isFull = rte_ring_full(ring);
54+
isEmpty = rte_ring_empty(ring);
55+
56+
if (buffer.empty()) {
57+
buffer += "name ";
58+
buffer += "flags ";
59+
buffer += "usedCount ";
60+
buffer += "freeCount ";
61+
buffer += "size ";
62+
buffer += "capacity ";
63+
buffer += "status";
64+
buffer += "\n";
65+
}
66+
67+
buffer += std::string(ring->name) + " ";
68+
buffer += std::to_string(ring->flags) + " ";
69+
buffer += std::to_string(count) + " ";
70+
buffer += std::to_string(freeCount) + " ";
71+
buffer += std::to_string(size) + " ";
72+
buffer += std::to_string(capacity) + " ";
73+
buffer += isFull == 1 ? "full" : isEmpty == 1 ? "empty" : "inUse";
74+
buffer += "\n";
75+
}
76+
77+
static void ringsWalk(void (*fnc)(struct rte_ring*, void* ctx), void* arg)
78+
{
79+
TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
80+
struct rte_ring_list* rings;
81+
struct rte_tailq_entry* entry;
82+
83+
rte_mcfg_tailq_read_lock();
84+
85+
rings = RTE_TAILQ_LOOKUP(RTE_TAILQ_RING_NAME, rte_ring_list);
86+
if (rings == nullptr) {
87+
rte_mcfg_tailq_read_unlock();
88+
throw std::runtime_error("RTE_TAILQ_LOOKUP(" RTE_TAILQ_RING_NAME ") failed");
89+
}
90+
91+
try {
92+
TAILQ_FOREACH(entry, rings, next)
93+
{
94+
fnc((struct rte_ring*) entry->data, arg);
95+
}
96+
} catch (...) {
97+
rte_mcfg_tailq_read_unlock();
98+
throw;
99+
}
100+
101+
rte_mcfg_tailq_read_unlock();
102+
}
103+
104+
static void createMempoolsInfo(struct rte_mempool* mempool, std::string& buffer)
105+
{
106+
const rte_mempool_ops* ops = rte_mempool_get_ops(mempool->ops_index);
107+
const unsigned int avail = rte_mempool_avail_count(mempool);
108+
const unsigned int inUse = rte_mempool_in_use_count(mempool);
109+
const int isFull = rte_mempool_full(mempool);
110+
const int isEmpty = rte_mempool_empty(mempool);
111+
const uint64_t totalSize = static_cast<uint64_t>(mempool->populated_size)
112+
* static_cast<uint64_t>((mempool->elt_size + mempool->header_size + mempool->trailer_size));
113+
114+
if (buffer.empty()) {
115+
buffer += "name ";
116+
buffer += "socketID ";
117+
buffer += "flags ";
118+
buffer += "poolID ";
119+
buffer += "size ";
120+
buffer += "cacheSize ";
121+
buffer += "elementSize ";
122+
buffer += "headerSize ";
123+
buffer += "trailerSize ";
124+
buffer += "totalSize ";
125+
buffer += "availableCount ";
126+
buffer += "usedCount ";
127+
buffer += "status ";
128+
buffer += "Ops";
129+
buffer += "\n";
130+
}
131+
132+
buffer += std::string(mempool->name) + " ";
133+
buffer += std::to_string(mempool->socket_id) + " ";
134+
buffer += std::to_string(mempool->flags) + " ";
135+
buffer += std::to_string(mempool->pool_id) + " ";
136+
buffer += std::to_string(mempool->size) + " ";
137+
buffer += std::to_string(mempool->cache_size) + " ";
138+
buffer += std::to_string(mempool->elt_size) + " ";
139+
buffer += std::to_string(mempool->header_size) + " ";
140+
buffer += std::to_string(mempool->trailer_size) + " ";
141+
buffer += std::to_string(totalSize) + " ";
142+
buffer += std::to_string(avail) + " ";
143+
buffer += std::to_string(inUse) + " ";
144+
buffer += (isFull == 1 ? "full " : isEmpty == 1 ? "empty " : "inUse ");
145+
buffer += (ops != nullptr ? std::string(ops->name) : "(none)");
146+
buffer += "\n";
147+
}
148+
149+
static std::string getMempoolsInfo()
150+
{
151+
struct Walker {
152+
std::string buffer;
153+
std::exception_ptr exc = nullptr;
154+
void operator()(rte_mempool* pool)
155+
{
156+
if (exc != nullptr) {
157+
return;
158+
}
159+
try {
160+
createMempoolsInfo(pool, buffer);
161+
} catch (...) {
162+
exc = std::current_exception();
163+
}
164+
}
165+
};
166+
Walker walker;
167+
168+
rte_mempool_walk(
169+
[](rte_mempool* pool, void* arg) { (*reinterpret_cast<Walker*>(arg))(pool); },
170+
&walker);
171+
if (walker.exc != nullptr) {
172+
std::rethrow_exception(walker.exc);
173+
}
174+
return walker.buffer;
175+
}
176+
177+
static std::string getRingsInfo()
178+
{
179+
std::string buffer;
180+
ringsWalk(&createRingsInfo, &buffer);
181+
return buffer;
182+
}
183+
184+
struct AppFsFile {
185+
std::string name;
186+
telemetry::FileOps ops;
187+
};
188+
189+
static std::vector<AppFsFile> getAppFsFiles()
190+
{
191+
std::vector<AppFsFile> files = {
192+
{
193+
.name = "mempools",
194+
.ops = {
195+
.read = []() { return getMempoolsInfo(); },
196+
},
197+
},
198+
{
199+
.name = "rings",
200+
.ops = {
201+
.read = []() { return getRingsInfo(); },
202+
},
203+
},
204+
};
205+
return files;
206+
}
207+
208+
DpdkTelemetry::DpdkTelemetry(const std::shared_ptr<telemetry::Directory>& dpdkDir)
209+
{
210+
for (auto [name, ops] : getAppFsFiles()) {
211+
auto file = dpdkDir->addFile(name, ops);
212+
m_holder.add(file);
213+
}
214+
}
215+
216+
} // namespace ct

input/dpdk/dpdkTelemetry.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* \file
3+
* \brief Class for managing DPDK telemetry
4+
* \author Pavel Siska <[email protected]>
5+
* \date 2024
6+
*/
7+
/*
8+
* Copyright (C) 2024 CESNET
9+
*
10+
* LICENSE TERMS
11+
*
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions
14+
* are met:
15+
* 1. Redistributions of source code must retain the above copyright
16+
* notice, this list of conditions and the following disclaimer.
17+
* 2. Redistributions in binary form must reproduce the above copyright
18+
* notice, this list of conditions and the following disclaimer in
19+
* the documentation and/or other materials provided with the
20+
* distribution.
21+
* 3. Neither the name of the Company nor the names of its contributors
22+
* may be used to endorse or promote products derived from this
23+
* software without specific prior written permission.
24+
*/
25+
26+
#pragma once
27+
28+
#include <memory>
29+
30+
#include <telemetry.hpp>
31+
32+
namespace ipxp {
33+
34+
/**
35+
* @brief Class for managing DPDK telemetry
36+
*
37+
* This class handles the integration of DPDK telemetry data (rings, mempools) into the telemetry
38+
* directory.
39+
*/
40+
class DpdkTelemetry {
41+
public:
42+
/**
43+
* @brief Constructor for DpdkTelemetry
44+
*
45+
* Initializes the DPDK telemetry manager and adds files representing DPDK rings and mempools to
46+
* the provided telemetry directory.
47+
*
48+
* @param dpdkDir Pointer to the telemetry directory where files will be added.
49+
*/
50+
DpdkTelemetry(const std::shared_ptr<telemetry::Directory>& dpdkDir);
51+
52+
private:
53+
telemetry::Holder m_holder;
54+
};
55+
56+
} // namespace ct

0 commit comments

Comments
 (0)