Skip to content

Commit

Permalink
Dpdk: Add DPDK telemetry
Browse files Browse the repository at this point in the history
  • Loading branch information
SiskaPavel committed Dec 27, 2024
1 parent 6fb3ee3 commit 904e91d
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ ipfixprobe_input_src+=\
input/dpdk/dpdkCompat.hpp \
input/dpdk/dpdkPortTelemetry.hpp \
input/dpdk/dpdkPortTelemetry.cpp \
input/dpdk/dpdkTelemetry.hpp \
input/dpdk/dpdkTelemetry.cpp \
input/dpdk.cpp \
input/dpdk.h \
input/dpdk-ring.cpp \
Expand Down
2 changes: 2 additions & 0 deletions input/dpdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ void DpdkReader::configure_telemetry_dirs(

telemetry::FileOps statsOps = {[=]() { return get_queue_telemetry(); }, nullptr};
register_file(queues_dir, "input-stats", statsOps);

m_dpdkTelemetry = std::make_unique<DpdkTelemetry>(plugin_dir);
}

void DpdkReader::init(const char* params)
Expand Down
2 changes: 2 additions & 0 deletions input/dpdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "dpdk/dpdkDevice.hpp"
#include "dpdk/dpdkPortTelemetry.hpp"
#include "dpdk/dpdkTelemetry.hpp"

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

std::vector<DpdkPortTelemetry> m_portsTelemetry;
std::unique_ptr<DpdkTelemetry> m_dpdkTelemetry;

struct DpdkRxStats {
uint64_t receivedPackets;
Expand Down
216 changes: 216 additions & 0 deletions input/dpdk/dpdkTelemetry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/**
* \file
* \brief Implementation of DpdkTelemetry class and helper functions for rings and mempools
* information retrieval.
* \author Pavel Siska <[email protected]>
* \date 2024
*/
/*
* Copyright (C) 2024 CESNET
*
* LICENSE TERMS
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the Company nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*/

#include "dpdkTelemetry.hpp"

#include <stdexcept>
#include <string>

#include <rte_eal_memconfig.h>
#include <rte_mempool.h>
#include <rte_ring.h>
#include <rte_tailq.h>

namespace ipxp {

static void createRingsInfo(struct rte_ring* ring, void* arg)
{
std::string& buffer = *reinterpret_cast<std::string*>(arg);
unsigned int count;
unsigned int freeCount;
unsigned int size;
unsigned int capacity;
int isFull;
int isEmpty;

count = rte_ring_count(ring);
freeCount = rte_ring_free_count(ring);
size = rte_ring_get_size(ring);
capacity = rte_ring_get_capacity(ring);
isFull = rte_ring_full(ring);
isEmpty = rte_ring_empty(ring);

if (buffer.empty()) {
buffer += "name ";
buffer += "flags ";
buffer += "usedCount ";
buffer += "freeCount ";
buffer += "size ";
buffer += "capacity ";
buffer += "status";
buffer += "\n";
}

buffer += std::string(ring->name) + " ";
buffer += std::to_string(ring->flags) + " ";
buffer += std::to_string(count) + " ";
buffer += std::to_string(freeCount) + " ";
buffer += std::to_string(size) + " ";
buffer += std::to_string(capacity) + " ";
buffer += isFull == 1 ? "full" : isEmpty == 1 ? "empty" : "inUse";
buffer += "\n";
}

static void ringsWalk(void (*fnc)(struct rte_ring*, void* ctx), void* arg)
{
TAILQ_HEAD(rte_ring_list, rte_tailq_entry);
struct rte_ring_list* rings;
struct rte_tailq_entry* entry;

rte_mcfg_tailq_read_lock();

rings = RTE_TAILQ_LOOKUP(RTE_TAILQ_RING_NAME, rte_ring_list);
if (rings == nullptr) {
rte_mcfg_tailq_read_unlock();
throw std::runtime_error("RTE_TAILQ_LOOKUP(" RTE_TAILQ_RING_NAME ") failed");
}

try {
TAILQ_FOREACH(entry, rings, next)
{
fnc((struct rte_ring*) entry->data, arg);
}
} catch (...) {
rte_mcfg_tailq_read_unlock();
throw;
}

rte_mcfg_tailq_read_unlock();
}

static void createMempoolsInfo(struct rte_mempool* mempool, std::string& buffer)
{
const rte_mempool_ops* ops = rte_mempool_get_ops(mempool->ops_index);
const unsigned int avail = rte_mempool_avail_count(mempool);
const unsigned int inUse = rte_mempool_in_use_count(mempool);
const int isFull = rte_mempool_full(mempool);
const int isEmpty = rte_mempool_empty(mempool);
const uint64_t totalSize = static_cast<uint64_t>(mempool->populated_size)
* static_cast<uint64_t>((mempool->elt_size + mempool->header_size + mempool->trailer_size));

if (buffer.empty()) {
buffer += "name ";
buffer += "socketID ";
buffer += "flags ";
buffer += "poolID ";
buffer += "size ";
buffer += "cacheSize ";
buffer += "elementSize ";
buffer += "headerSize ";
buffer += "trailerSize ";
buffer += "totalSize ";
buffer += "availableCount ";
buffer += "usedCount ";
buffer += "status ";
buffer += "Ops";
buffer += "\n";
}

buffer += std::string(mempool->name) + " ";
buffer += std::to_string(mempool->socket_id) + " ";
buffer += std::to_string(mempool->flags) + " ";
buffer += std::to_string(mempool->pool_id) + " ";
buffer += std::to_string(mempool->size) + " ";
buffer += std::to_string(mempool->cache_size) + " ";
buffer += std::to_string(mempool->elt_size) + " ";
buffer += std::to_string(mempool->header_size) + " ";
buffer += std::to_string(mempool->trailer_size) + " ";
buffer += std::to_string(totalSize) + " ";
buffer += std::to_string(avail) + " ";
buffer += std::to_string(inUse) + " ";
buffer += (isFull == 1 ? "full " : isEmpty == 1 ? "empty " : "inUse ");
buffer += (ops != nullptr ? std::string(ops->name) : "(none)");
buffer += "\n";
}

static std::string getMempoolsInfo()
{
struct Walker {
std::string buffer;
std::exception_ptr exc = nullptr;
void operator()(rte_mempool* pool)
{
if (exc != nullptr) {
return;
}
try {
createMempoolsInfo(pool, buffer);
} catch (...) {
exc = std::current_exception();
}
}
};
Walker walker;

rte_mempool_walk(
[](rte_mempool* pool, void* arg) { (*reinterpret_cast<Walker*>(arg))(pool); },
&walker);
if (walker.exc != nullptr) {
std::rethrow_exception(walker.exc);
}
return walker.buffer;
}

static std::string getRingsInfo()
{
std::string buffer;
ringsWalk(&createRingsInfo, &buffer);
return buffer;
}

struct AppFsFile {
std::string name;
telemetry::FileOps ops;
};

static std::vector<AppFsFile> getAppFsFiles()
{
std::vector<AppFsFile> files = {
{
.name = "mempools",
.ops = {
.read = []() { return getMempoolsInfo(); },
},
},
{
.name = "rings",
.ops = {
.read = []() { return getRingsInfo(); },
},
},
};
return files;
}

DpdkTelemetry::DpdkTelemetry(const std::shared_ptr<telemetry::Directory>& dpdkDir)
{
for (auto [name, ops] : getAppFsFiles()) {
auto file = dpdkDir->addFile(name, ops);
m_holder.add(file);
}
}

} // namespace ct
56 changes: 56 additions & 0 deletions input/dpdk/dpdkTelemetry.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* \file
* \brief Class for managing DPDK telemetry
* \author Pavel Siska <[email protected]>
* \date 2024
*/
/*
* Copyright (C) 2024 CESNET
*
* LICENSE TERMS
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the Company nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*/

#pragma once

#include <memory>

#include <telemetry.hpp>

namespace ipxp {

/**
* @brief Class for managing DPDK telemetry
*
* This class handles the integration of DPDK telemetry data (rings, mempools) into the telemetry
* directory.
*/
class DpdkTelemetry {
public:
/**
* @brief Constructor for DpdkTelemetry
*
* Initializes the DPDK telemetry manager and adds files representing DPDK rings and mempools to
* the provided telemetry directory.
*
* @param dpdkDir Pointer to the telemetry directory where files will be added.
*/
DpdkTelemetry(const std::shared_ptr<telemetry::Directory>& dpdkDir);

private:
telemetry::Holder m_holder;
};

} // namespace ct

0 comments on commit 904e91d

Please sign in to comment.