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
51 changes: 46 additions & 5 deletions dataplane/dataplane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "common/utils.h"
#include "dataplane.h"
#include "dataplane/sdpserver.h"
#include "dpdk.h"
#include "dump_rings.h"
#include "globalbase.h"
#include "sock_dev.h"
Expand Down Expand Up @@ -69,12 +70,23 @@ cDataPlane::~cDataPlane()
if (mempool_log)
{
rte_mempool_free(mempool_log);
mempool_log = nullptr;
}
for (auto& [socket_id, rte_mempool] : socket_cplane_mempools)
{
GCC_BUG_UNUSED(socket_id);
rte_mempool_free(rte_mempool);
}
socket_cplane_mempools.clear();

// Explicitly run all object destructors and rte_free() calls while EAL is
// still valid, then shut EAL down cleanly. This prevents the implicit
// destruction of memory_manager (which happens after the destructor body)
// from calling rte_free() after EAL has already been torn down, which
// would corrupt glibc's internal linked lists and crash with
// "corrupted double-linked list".
memory_manager.cleanup();
rte_eal_cleanup();
}

eResult cDataPlane::init(const std::string& binaryPath,
Expand Down Expand Up @@ -167,12 +179,18 @@ eResult cDataPlane::init(const std::string& binaryPath,

for (auto socket : slow_sockets)
{
const uint64_t cp_pool_count = CONFIG_YADECAP_MBUFS_COUNT +
config_values_.fragmentation.size +
config_values_.master_mempool_size +
4 * CONFIG_YADECAP_PORTS_SIZE * CONFIG_YADECAP_MBUFS_BURST_SIZE +
4 * ports.size() * config_values_.kernel_interface_queue_size;
YADECAP_LOG_INFO("rte_mempool_create(cp-%u): count=%lu, elem_size=%u, total_approx=%lu MB\n",
socket,
cp_pool_count,
CONFIG_YADECAP_MBUF_SIZE,
cp_pool_count * CONFIG_YADECAP_MBUF_SIZE / (1024 * 1024));
auto pool = rte_mempool_create(("cp-" + std::to_string(socket)).c_str(),
CONFIG_YADECAP_MBUFS_COUNT +
config_values_.fragmentation.size +
config_values_.master_mempool_size +
4 * CONFIG_YADECAP_PORTS_SIZE * CONFIG_YADECAP_MBUFS_BURST_SIZE +
4 * ports.size() * config_values_.kernel_interface_queue_size,
cp_pool_count,
CONFIG_YADECAP_MBUF_SIZE,
0,
sizeof(struct rte_pktmbuf_pool_private),
Expand All @@ -185,6 +203,7 @@ eResult cDataPlane::init(const std::string& binaryPath,
if (!pool)
{
YADECAP_LOG_ERROR("rte_mempool_create(): %s [%u]\n", rte_strerror(rte_errno), rte_errno);
memory_manager.debug(socket);
return eResult::errorAllocatingMemory;
}
socket_cplane_mempools.emplace(socket, pool);
Expand Down Expand Up @@ -707,11 +726,33 @@ void cDataPlane::StartInterfaces()
{
for (auto& [portid, handles] : kni_interface_handles)
{
// Read the actual MAC after rte_eth_dev_start(): for some drivers
// the MAC only becomes valid (or may change) once the port is started.
auto actual_mac = dpdk::GetMacAddress(portid);
if (!actual_mac)
{
YANET_LOG_ERROR("Failed to get MAC for port belonging to %s", std::get<0>(ports.at(portid)).c_str());
std::abort();
}

if (!handles.Start())
{
YANET_LOG_ERROR("Failed to start kni interfaces");
std::abort();
}

// Sync the actual MAC to all KNI interfaces, because it may differ
// from what was used at vdev creation time (before the port start).
// MAC must be changed while the interface is DOWN, hence before SetUp().
if (!handles.forward.SyncMac(*actual_mac) ||
!handles.in_dump.SyncMac(*actual_mac) ||
!handles.out_dump.SyncMac(*actual_mac) ||
!handles.drop_dump.SyncMac(*actual_mac))
{
YANET_LOG_ERROR("Failed to sync MAC on kni interfaces belonging to %s", std::get<0>(ports.at(portid)).c_str());
std::abort();
}

if (!handles.forward.SetUp())
{
YANET_LOG_ERROR("Failed to set kni interface belonging to %s up", std::get<0>(ports.at(portid)).c_str());
Expand Down
42 changes: 41 additions & 1 deletion dataplane/kernel_interface_handle.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include <linux/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <unistd.h>

#include <rte_ethdev.h>

Expand All @@ -9,6 +11,42 @@
namespace dataplane
{

bool KernelInterfaceHandle::SyncMac(const common::mac_address_t& addr) const noexcept
{
// Skip zero/invalid MAC (e.g. sock_dev leaves it all-zeros). Setting a
// zero MAC via SIOCSIFHWADDR fails with EINVAL on most drivers.
if (addr.is_default())
{
YANET_LOG_WARNING("SyncMac: skipping zero MAC for interface %s\n", name_.data());
return true;
}

// NOTE: MAC must be changed while the interface is DOWN. This method is
// therefore expected to be called before SetUp() (which raises IFF_UP).
int sock = ::socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
YANET_LOG_ERROR("SyncMac: failed to open socket for interface %s\n", name_.data());
return false;
}

struct ifreq request;
memset(&request, 0, sizeof(request));
strncpy(request.ifr_name, name_.data(), IFNAMSIZ - 1);
request.ifr_hwaddr.sa_family = ARPHRD_ETHER;
memcpy(request.ifr_hwaddr.sa_data, addr.data(), RTE_ETHER_ADDR_LEN);

if (ioctl(sock, SIOCSIFHWADDR, &request) < 0)
{
YANET_LOG_ERROR("SyncMac: failed to set MAC on interface %s\n", name_.data());
::close(sock);
return false;
}

::close(sock);
return true;
}

bool KernelInterfaceHandle::SetUp() const noexcept
{
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
Expand All @@ -20,14 +58,16 @@ bool KernelInterfaceHandle::SetUp() const noexcept
struct ifreq request;
memset(&request, 0, sizeof request);

strncpy(request.ifr_name, name_.data(), IFNAMSIZ);
strncpy(request.ifr_name, name_.data(), IFNAMSIZ - 1);

request.ifr_flags |= IFF_UP;
if (auto res = ioctl(socket, SIOCSIFFLAGS, &request))
{
YANET_LOG_ERROR("failed to set interface %s up, ioctl returned (%d)", name_.data(), res);
::close(socket);
return false;
}
::close(socket);
return true;
}

Expand Down
1 change: 1 addition & 0 deletions dataplane/kernel_interface_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class KernelInterfaceHandle
[[nodiscard]] const tPortId& Id() const noexcept { return kni_port_; }
[[nodiscard]] bool Start() const noexcept;
[[nodiscard]] bool SetUp() const noexcept;
[[nodiscard]] bool SyncMac(const common::mac_address_t& addr) const noexcept;
bool SetupRxQueue(tQueueId queue, tSocketId socket, rte_mempool* mempool) noexcept;
bool SetupTxQueue(tQueueId queue, tSocketId socket) noexcept;
bool CloneMTU(const uint16_t) noexcept;
Expand Down
11 changes: 11 additions & 0 deletions dataplane/memory_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ void memory_manager::destroy(void* pointer)
pointers.erase(it);
}

void memory_manager::cleanup()
{
std::lock_guard<std::mutex> guard(mutex);

// Explicitly destroy all tracked objects and free hugepage memory in a
// controlled order, before rte_eal_cleanup() is called. Clearing the map
// here means the default destructor of memory_manager will find it empty
// and will not attempt any rte_free() calls after EAL has been torn down.
pointers.clear();
}

void memory_manager::debug(tSocketId socket_id)
{
rte_malloc_socket_stats stats;
Expand Down
1 change: 1 addition & 0 deletions dataplane/memory_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class memory_manager
}

void destroy(void* pointer);
void cleanup();
void debug(tSocketId socket_id);
bool check_memory_limit(const std::string& name, const uint64_t size);
Deleter deleter() { return Deleter{this}; }
Expand Down
12 changes: 7 additions & 5 deletions dataplane/worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@ eResult cWorker::init(const tCoreId& coreId,
const dataplane::base::permanently& basePermanently,
const dataplane::base::generation& base)
{
YADECAP_LOG_DEBUG("rte_mempool_create(coreId: %u, socketId: %u)\n",
coreId,
rte_lcore_to_socket_id(coreId));

this->coreId = coreId;
this->socketId = rte_lcore_to_socket_id(coreId);
this->basePermanently = basePermanently;
Expand All @@ -113,7 +109,12 @@ eResult cWorker::init(const tCoreId& coreId,

unsigned int elements_count = MempoolSize();

YADECAP_LOG_DEBUG("elements_count: %u\n", elements_count);
YADECAP_LOG_INFO("rte_mempool_create(fp%u, socketId: %u): count=%u, elem_size=%u, total_approx=%lu MB\n",
coreId,
socketId,
elements_count,
CONFIG_YADECAP_MBUF_SIZE,
(uint64_t)elements_count * CONFIG_YADECAP_MBUF_SIZE / (1024 * 1024));

/// init mempool
mempool = rte_mempool_create(("fp" + std::to_string(coreId)).data(),
Expand All @@ -130,6 +131,7 @@ eResult cWorker::init(const tCoreId& coreId,
if (!mempool)
{
YADECAP_LOG_ERROR("rte_mempool_create(): %s [%u]\n", rte_strerror(rte_errno), rte_errno);
dataPlane->memory_manager.debug(socketId);
return eResult::errorInitMempool;
}

Expand Down
9 changes: 8 additions & 1 deletion dataplane/worker_gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,15 @@ eResult worker_gc_t::init(const tCoreId& core_id,
this->bases[local_base_id] = base;
this->bases[local_base_id ^ 1] = base;

const uint64_t wgc_pool_count = CONFIG_YADECAP_MBUFS_COUNT + 3 * CONFIG_YADECAP_PORTS_SIZE * CONFIG_YADECAP_MBUFS_BURST_SIZE;
YADECAP_LOG_INFO("rte_mempool_create(wgc%u, socketId: %u): count=%lu, elem_size=%u, total_approx=%lu MB\n",
core_id,
socket_id,
wgc_pool_count,
CONFIG_YADECAP_MBUF_SIZE,
wgc_pool_count * CONFIG_YADECAP_MBUF_SIZE / (1024 * 1024));
mempool = rte_mempool_create(("wgc" + std::to_string(core_id)).data(),
CONFIG_YADECAP_MBUFS_COUNT + 3 * CONFIG_YADECAP_PORTS_SIZE * CONFIG_YADECAP_MBUFS_BURST_SIZE,
wgc_pool_count,
CONFIG_YADECAP_MBUF_SIZE,
0,
sizeof(struct rte_pktmbuf_pool_private),
Expand Down
Loading