From 4f08a4cdab78dc73cba3bd8a3fe5ea4c31fcfcc1 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Fri, 26 Jan 2024 19:13:31 +0300 Subject: [PATCH] Dynamic allocation memory allocate memory on update for some acl structs. --- common/idataplane.h | 10 ++ common/idp.h | 24 ++- common/memory_manager.h | 61 +++++++ common/stream.h | 17 ++ common/type.h | 5 + controlplane/base.h | 2 + controlplane/configparser.cpp | 31 ++++ controlplane/configparser.h | 1 + controlplane/controlplane.cpp | 1 + controlplane/controlplane.h | 2 + controlplane/memory_manager.cpp | 12 ++ controlplane/memory_manager.h | 21 +++ controlplane/meson.build | 1 + dataplane/bus.cpp | 4 + dataplane/common.h | 10 ++ dataplane/controlplane.cpp | 12 +- dataplane/dataplane.cpp | 45 ++--- dataplane/dataplane.h | 13 +- dataplane/globalbase.cpp | 101 +++++++++-- dataplane/globalbase.h | 32 ++-- dataplane/hashtable.h | 302 +++++++++++++------------------- dataplane/lpm.h | 296 +++++++++++++++---------------- dataplane/memory_manager.cpp | 142 +++++++++++++++ dataplane/memory_manager.h | 75 ++++++++ dataplane/meson.build | 1 + dataplane/report.cpp | 11 +- dataplane/updater.h | 239 +++++++++++++++++++++++++ 27 files changed, 1058 insertions(+), 413 deletions(-) create mode 100644 common/memory_manager.h create mode 100644 controlplane/memory_manager.cpp create mode 100644 controlplane/memory_manager.h create mode 100644 dataplane/memory_manager.cpp create mode 100644 dataplane/memory_manager.h create mode 100644 dataplane/updater.h diff --git a/common/idataplane.h b/common/idataplane.h index aeeb26d7..2094af41 100644 --- a/common/idataplane.h +++ b/common/idataplane.h @@ -258,6 +258,16 @@ class dataPlane return get(); } + auto memory_manager_update(const common::idp::memory_manager_update::request& request) const + { + return get(request); + } + + auto memory_manager_stats() const + { + return get(); + } + protected: void connectToDataPlane() const { diff --git a/common/idp.h b/common/idp.h index 40e921db..49f7621f 100644 --- a/common/idp.h +++ b/common/idp.h @@ -15,6 +15,7 @@ #include "acl.h" #include "balancer.h" #include "config.h" +#include "memory_manager.h" #include "neighbor.h" #include "result.h" #include "scheduler.h" @@ -82,6 +83,8 @@ enum class requestType : uint32_t neighbor_flush, neighbor_update_interfaces, neighbor_stats, + memory_manager_update, + memory_manager_stats, size, // size should always be at the bottom of the list, this enum allows us to find out the size of the enum list }; @@ -984,6 +987,21 @@ namespace neighbor_stats using response = common::neighbor::stats; } +namespace memory_manager_update +{ +using request = memory_manager::memory_group; +} + +namespace memory_manager_stats +{ +using object = std::tuple; ///< size + +using response = std::tuple>; +} + // using request = std::tuple>; + neighbor_update_interfaces::request, + memory_manager_update::request>>; using response = std::variant, updateGlobalBase::response, ///< + others which have eResult as response @@ -1039,5 +1058,6 @@ using response = std::variant, get_shm_info::response, get_shm_tsc_info::response, neighbor_show::response, - neighbor_stats::response>; + neighbor_stats::response, + memory_manager_stats::response>; } diff --git a/common/memory_manager.h b/common/memory_manager.h new file mode 100644 index 00000000..a9e0b5f2 --- /dev/null +++ b/common/memory_manager.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include "stream.h" + +namespace common::memory_manager +{ + +inline uint64_t convert_string_to_bytes(std::string string) +{ + static std::map multipliers = + {{'k', 1024ull}, + {'K', 1024ull}, + {'m', 1024ull * 1024ull}, + {'M', 1024ull * 1024ull}, + {'g', 1024ull * 1024ull * 1024ull}, + {'G', 1024ull * 1024ull * 1024ull}}; + + if (string.empty()) + { + return 0; + } + + uint64_t multiplier = 1; + + auto iter = multipliers.find(string.back()); + if (iter != multipliers.end()) + { + multiplier = iter->second; + string.pop_back(); + } + + return std::stoll(string) * multiplier; +} + +class memory_group +{ +public: + void pop(common::stream_in_t& stream) + { + stream.pop(name); + stream.pop(limit); + stream.pop(memory_groups); + } + + void push(common::stream_out_t& stream) const + { + stream.push(name); + stream.push(limit); + stream.push(memory_groups); + } + +public: + std::string name; + uint64_t limit; + std::vector> memory_groups; +}; + +} diff --git a/common/stream.h b/common/stream.h index 74291275..a853f6d2 100644 --- a/common/stream.h +++ b/common/stream.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -61,6 +62,9 @@ class stream_in_t template inline void pop(std::optional& optional); + template + inline void pop(std::shared_ptr& pointer); + inline bool isFailed(); protected: @@ -221,6 +225,12 @@ class stream_out_t } } + template + inline void push(const std::shared_ptr& pointer) + { + push(*pointer.get()); + } + inline const std::vector& getBuffer() { return outBuffer; @@ -450,6 +460,13 @@ inline void stream_in_t::pop(std::optional& optional) } } +template +inline void stream_in_t::pop(std::shared_ptr& pointer) +{ + pointer = std::make_shared(); + pop(*pointer.get()); +} + inline bool stream_in_t::isFailed() { return failed; diff --git a/common/type.h b/common/type.h index 9a9d0cf2..7c4dd4b6 100644 --- a/common/type.h +++ b/common/type.h @@ -236,6 +236,11 @@ class mac_address_t return buffer; } + uint8_t* data() + { + return address.data(); + } + const uint8_t* data() const { return address.data(); diff --git a/controlplane/base.h b/controlplane/base.h index 5103415c..6b06b13d 100644 --- a/controlplane/base.h +++ b/controlplane/base.h @@ -484,6 +484,8 @@ class base_t std::map> rib; + + common::memory_manager::memory_group root_memory_group; }; // diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index a9a038e0..2491367f 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -130,6 +130,11 @@ controlplane::base_t config_parser_t::loadConfig(const std::string& rootFilePath { loadConfig_rib(baseNext, rootJson["rib"]); } + + if (exist(rootJson, "memory_groups")) + { + loadConfig_memory_group(baseNext.root_memory_group, rootJson["memory_groups"]); + } } catch (const error_result_t& err) { @@ -1901,3 +1906,29 @@ void config_parser_t::loadConfig_rib(controlplane::base_t& baseNext, } } } + +void config_parser_t::loadConfig_memory_group(common::memory_manager::memory_group& memory_group, + const nlohmann::json& json) +{ + for (const auto& json_iter : json) + { + auto memory_group_next = std::make_shared(); + + std::string name = json_iter["name"].get(); + std::string limit = "0"; + if (exist(json_iter, "limit")) + { + limit = json_iter["limit"].get(); + } + + memory_group_next->name = name; + memory_group_next->limit = common::memory_manager::convert_string_to_bytes(std::move(limit)); + + if (exist(json_iter, "memory_groups")) + { + loadConfig_memory_group(*memory_group_next.get(), json_iter["memory_groups"]); + } + + memory_group.memory_groups.emplace_back(memory_group_next); + } +} diff --git a/controlplane/configparser.h b/controlplane/configparser.h index e041fb10..ad8af05f 100644 --- a/controlplane/configparser.h +++ b/controlplane/configparser.h @@ -39,6 +39,7 @@ class config_parser_t void loadConfig_variables(controlplane::base_t& baseNext, const nlohmann::json& json); void loadConfig_fqdns(controlplane::base_t& baseNext, const nlohmann::json& json, const std::string& rootFilePath, const std::map& jsons); void loadConfig_rib(controlplane::base_t& baseNext, const nlohmann::json& json); + void loadConfig_memory_group(common::memory_manager::memory_group& memory_group, const nlohmann::json& json); private: common::idp::getConfig::response dataPlaneConfig; diff --git a/controlplane/controlplane.cpp b/controlplane/controlplane.cpp index 52c6e32d..3c3e4f51 100644 --- a/controlplane/controlplane.cpp +++ b/controlplane/controlplane.cpp @@ -54,6 +54,7 @@ eResult cControlPlane::init(const std::string& jsonFilePath) modules.emplace_back(&durations); modules.emplace_back(&nat64stateful); modules.emplace_back(&nat46clat); + modules.emplace_back(&memory_manager); for (auto* module : modules) { diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index b80b2281..8d038a22 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -25,6 +25,7 @@ #include "durations.h" #include "fqdn.h" #include "isystem.h" +#include "memory_manager.h" #include "module.h" #include "nat46clat.h" #include "nat64stateful.h" @@ -172,6 +173,7 @@ class cControlPlane durations_t durations; nat64stateful_t nat64stateful; nat46clat::manager nat46clat; + controlplane::memory_manager::memory_manager memory_manager; counter_manager_t counter_manager; diff --git a/controlplane/memory_manager.cpp b/controlplane/memory_manager.cpp new file mode 100644 index 00000000..4f2990d9 --- /dev/null +++ b/controlplane/memory_manager.cpp @@ -0,0 +1,12 @@ +#include "memory_manager.h" + +using namespace controlplane::memory_manager; + +void memory_manager::reload(const base_t& base_prev, + const base_t& base_next, + common::idp::updateGlobalBase::request& globalbase) +{ + (void)base_prev; + (void)globalbase; + dataplane.memory_manager_update(base_next.root_memory_group); +} diff --git a/controlplane/memory_manager.h b/controlplane/memory_manager.h new file mode 100644 index 00000000..4f901a1c --- /dev/null +++ b/controlplane/memory_manager.h @@ -0,0 +1,21 @@ +#pragma once + +#include "base.h" +#include "module.h" +#include "type.h" + +#include "common/idataplane.h" + +namespace controlplane::memory_manager +{ + +class memory_manager : public module_t +{ +public: + void reload(const controlplane::base_t& base_prev, const controlplane::base_t& base_next, common::idp::updateGlobalBase::request& globalbase) override; + +protected: + interface::dataPlane dataplane; +}; + +} diff --git a/controlplane/meson.build b/controlplane/meson.build index 91e9e67c..daf6efa6 100644 --- a/controlplane/meson.build +++ b/controlplane/meson.build @@ -22,6 +22,7 @@ sources = files('acl_compiler.cpp', 'fqdn.cpp', 'isystem.cpp', 'main.cpp', + 'memory_manager.cpp', 'module.cpp', 'nat46clat.cpp', 'nat64stateful.cpp', diff --git a/dataplane/bus.cpp b/dataplane/bus.cpp index c72d7831..89f231de 100644 --- a/dataplane/bus.cpp +++ b/dataplane/bus.cpp @@ -378,6 +378,10 @@ void cBus::clientThread(int clientSocket) { response = dataPlane->neighbor.neighbor_stats(); } + else if (type == common::idp::requestType::memory_manager_update) + { + response = dataPlane->memory_manager.memory_manager_update(std::get(std::get<1>(request))); + } else { stats.errors[(uint32_t)common::idp::errorType::busParse]++; diff --git a/dataplane/common.h b/dataplane/common.h index 0f2d7bf5..041528a6 100644 --- a/dataplane/common.h +++ b/dataplane/common.h @@ -90,3 +90,13 @@ inline uint32_t yanet_hash_crc(const void* data, uint32_t init) // static_assert(CONFIG_YADECAP_PORTS_SIZE <= 0xFF, "invalid CONFIG_YADECAP_PORTS_SIZE"); + +// + +namespace dataplane +{ + +class memory_pointer; +class memory_manager; + +} diff --git a/dataplane/controlplane.cpp b/dataplane/controlplane.cpp index 55123a1b..c98dfb01 100644 --- a/dataplane/controlplane.cpp +++ b/dataplane/controlplane.cpp @@ -973,14 +973,12 @@ common::idp::limits::response cControlPlane::limits() YANET_CONFIG_ROUTE_TUNNEL_LPM6_EXTENDED_SIZE); globalBase->updater.acl.network_table.limits(response, "acl.network.ht"); - globalBase->updater.acl.transport_table.limits(response, "acl.transport.ht"); - globalBase->updater.acl.total_table.limits(response, "acl.total.ht"); - globalBase->updater.acl.network_ipv4_source.limits(response, "acl.network.v4.source.lpm"); - globalBase->updater.acl.network_ipv4_destination.limits(response, "acl.network.v4.destination.lpm"); + globalBase->updater.acl.transport_table->limits(response); + globalBase->updater.acl.total_table->limits(response); + globalBase->updater.acl.network_ipv4_source->limits(response); + globalBase->updater.acl.network_ipv4_destination->limits(response); globalBase->updater.acl.network_ipv6_source.limits(response, "acl.network.v6.source.lpm"); - - /// globalBase->acl.network_ipv6_destination_ht is not critical - + globalBase->updater.acl.network_ipv6_destination_ht->limits(response); globalBase->updater.acl.network_ipv6_destination.limits(response, "acl.network.v6.destination.lpm"); limit_insert(response, diff --git a/dataplane/dataplane.cpp b/dataplane/dataplane.cpp index 83c2626d..f329f59f 100644 --- a/dataplane/dataplane.cpp +++ b/dataplane/dataplane.cpp @@ -32,6 +32,7 @@ #include "common/result.h" #include "common/tsc_deltas.h" #include "dataplane.h" +#include "debug_latch.h" #include "globalbase.h" #include "report.h" #include "sock_dev.h" @@ -226,6 +227,12 @@ eResult cDataPlane::init(const std::string& binaryPath, return result; } + result = memory_manager.init(this); + if (result != eResult::success) + { + return result; + } + result = controlPlane->init(config.use_kernel_interface); if (result != eResult::success) { @@ -654,31 +661,18 @@ eResult cDataPlane::initGlobalBases() return nullptr; } + if (globalbase->init() != eResult::success) { - auto* acl_network_ipv4_source = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_network_lpm4_chunks_size), globalbase->updater.acl.network_ipv4_source); - if (!acl_network_ipv4_source) - { - return nullptr; - } - - auto* acl_network_ipv4_destination = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_network_lpm4_chunks_size), globalbase->updater.acl.network_ipv4_destination); - if (!acl_network_ipv4_destination) - { - return nullptr; - } + return nullptr; + } + { auto* acl_network_ipv6_source = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_network_source_lpm6_chunks_size), globalbase->updater.acl.network_ipv6_source); if (!acl_network_ipv6_source) { return nullptr; } - auto* acl_network_ipv6_destination_ht = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_network_destination_ht_size), globalbase->updater.acl.network_ipv6_destination_ht); - if (!acl_network_ipv6_destination_ht) - { - return nullptr; - } - auto* acl_network_ipv6_destination = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_network_destination_lpm6_chunks_size), globalbase->updater.acl.network_ipv6_destination); if (!acl_network_ipv6_destination) { @@ -711,18 +705,6 @@ eResult cDataPlane::initGlobalBases() return nullptr; } - auto* acl_transport_table = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_transport_ht_size), globalbase->updater.acl.transport_table); - if (!acl_transport_table) - { - return nullptr; - } - - auto* acl_total_table = hugepage_create_dynamic(socket_id, getConfigValue(eConfigType::acl_total_ht_size), globalbase->updater.acl.total_table); - if (!acl_total_table) - { - return nullptr; - } - const auto acl_values_size = getConfigValue(eConfigType::acl_values_size); if (acl_values_size < 2) { @@ -736,16 +718,11 @@ eResult cDataPlane::initGlobalBases() return nullptr; } - globalbase->acl.network.ipv4.source = acl_network_ipv4_source; - globalbase->acl.network.ipv4.destination = acl_network_ipv4_destination; globalbase->acl.network.ipv6.source = acl_network_ipv6_source; - globalbase->acl.network.ipv6.destination_ht = acl_network_ipv6_destination_ht; globalbase->acl.network.ipv6.destination = acl_network_ipv6_destination; globalbase->acl.network_table = acl_network_table; globalbase->acl.transport_layers_mask = acl_transport_layers_size - 1; globalbase->acl.transport_layers = acl_transport_layers; - globalbase->acl.transport_table = acl_transport_table; - globalbase->acl.total_table = acl_total_table; globalbase->acl.values = acl_values; } diff --git a/dataplane/dataplane.h b/dataplane/dataplane.h index cecfd06e..27ae6197 100644 --- a/dataplane/dataplane.h +++ b/dataplane/dataplane.h @@ -356,12 +356,6 @@ class cDataPlane common::idp::get_shm_tsc_info::response tscs_meta; - /// modules - cReport report; - std::unique_ptr controlPlane; - cBus bus; - dataplane::neighbor::module neighbor; - // array instead of the table - how many coreIds can be there? std::unordered_map> coreId_to_stats_tables; @@ -380,4 +374,11 @@ class cDataPlane std::vector threads; mutable std::mutex dpdk_mutex; + +public: ///< modules + cReport report; + std::unique_ptr controlPlane; + cBus bus; + dataplane::memory_manager memory_manager; + dataplane::neighbor::module neighbor; }; diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index 0b019e4e..d10ef9c7 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -53,6 +53,78 @@ generation::~generation() { } +eResult generation::init() +{ + eResult result = eResult::success; + + { + updater.acl.network_ipv4_source = std::make_unique("acl.network.v4.source.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.acl.network_ipv4_source->init(); + if (result != eResult::success) + { + return result; + } + + acl.network.ipv4.source = updater.acl.network_ipv4_source->pointer; + } + + { + updater.acl.network_ipv4_destination = std::make_unique("acl.network.v4.destination.lpm", + &dataPlane->memory_manager, + socketId); + result = updater.acl.network_ipv4_destination->init(); + if (result != eResult::success) + { + return result; + } + + acl.network.ipv4.destination = updater.acl.network_ipv4_destination->pointer; + } + + { + updater.acl.network_ipv6_destination_ht = std::make_unique("acl.network.v6.destination.ht", + &dataPlane->memory_manager, + socketId); + result = updater.acl.network_ipv6_destination_ht->init(); + if (result != eResult::success) + { + return result; + } + + acl.network.ipv6.destination_ht = updater.acl.network_ipv6_destination_ht->pointer; + } + + { + updater.acl.transport_table = std::make_unique("acl.transport.ht", + &dataPlane->memory_manager, + socketId); + result = updater.acl.transport_table->init(); + if (result != eResult::success) + { + return result; + } + + acl.transport_table = updater.acl.transport_table->pointer; + } + + { + updater.acl.total_table = std::make_unique("acl.total.ht", + &dataPlane->memory_manager, + socketId); + result = updater.acl.total_table->init(); + if (result != eResult::success) + { + return result; + } + + acl.total_table = updater.acl.total_table->pointer; + } + + return result; +} + eResult generation::update(const common::idp::updateGlobalBase::request& request) { eResult result = eResult::success; @@ -418,9 +490,6 @@ eResult generation::clear() sampler_enabled = 0; serial = 0; - updater.acl.network_ipv6_destination_ht.clear(); - updater.acl.transport_table.clear(); - updater.acl.total_table.clear(); acl.values[0] = {}; tun64mappingsTable.clear(); @@ -1860,13 +1929,15 @@ eResult generation::acl_network_ipv4_source(const common::idp::updateGlobalBase: { eResult result = eResult::success; - result = updater.acl.network_ipv4_source.update(request); + result = updater.acl.network_ipv4_source->update(request); if (result != eResult::success) { YANET_LOG_ERROR("acl.network.ipv4.source.update(): %s\n", result_to_c_str(result)); return result; } + acl.network.ipv4.source = updater.acl.network_ipv4_source->pointer; + return result; } @@ -1874,13 +1945,15 @@ eResult generation::acl_network_ipv4_destination(const common::idp::updateGlobal { eResult result = eResult::success; - result = updater.acl.network_ipv4_destination.update(request); + result = updater.acl.network_ipv4_destination->update(request); if (result != eResult::success) { YANET_LOG_ERROR("acl.network.ipv4.destination.update(): %s\n", result_to_c_str(result)); return result; } + acl.network.ipv4.destination = updater.acl.network_ipv4_destination->pointer; + return result; } @@ -1900,12 +1973,16 @@ eResult generation::acl_network_ipv6_source(const common::idp::updateGlobalBase: eResult generation::acl_network_ipv6_destination_ht(const common::idp::updateGlobalBase::acl_network_ipv6_destination_ht::request& request) { - auto result = updater.acl.network_ipv6_destination_ht.update(request); - if (result != eResult::success) + std::vector> request_convert; + for (const auto& [address, group_id] : request) { - /// dont panic. this is fine + request_convert.emplace_back(ipv6_address_t::convert(address), group_id); } + /// ignore error + updater.acl.network_ipv6_destination_ht->update(request_convert, false); + acl.network.ipv6.destination_ht = updater.acl.network_ipv6_destination_ht->pointer; + return eResult::success; } @@ -2053,13 +2130,15 @@ eResult generation::acl_transport_table(const common::idp::updateGlobalBase::acl { eResult result = eResult::success; - result = updater.acl.transport_table.update(request); + result = updater.acl.transport_table->update(request); if (result != eResult::success) { YANET_LOG_ERROR("acl.transport_table.update(): %s\n", result_to_c_str(result)); return result; } + acl.transport_table = updater.acl.transport_table->pointer; + return result; } @@ -2067,13 +2146,15 @@ eResult generation::acl_total_table(const common::idp::updateGlobalBase::acl_tot { eResult result = eResult::success; - result = updater.acl.total_table.update(request); + result = updater.acl.total_table->update(request); if (result != eResult::success) { YANET_LOG_ERROR("acl.total_table.update(): %s\n", result_to_c_str(result)); return result; } + acl.total_table = updater.acl.total_table->pointer; + return result; } diff --git a/dataplane/globalbase.h b/dataplane/globalbase.h index 78629343..8244b7af 100644 --- a/dataplane/globalbase.h +++ b/dataplane/globalbase.h @@ -17,6 +17,7 @@ #include "hashtable.h" #include "lpm.h" #include "type.h" +#include "updater.h" /// @todo: move #define YADECAP_GB_DSCP_FLAG_MARK ((uint8_t)1) @@ -61,14 +62,14 @@ struct transport_layer_t }; /// @todo: move to config -using network_ipv4_source = lpm4_24bit_8bit_id32_dynamic; -using network_ipv4_destination = lpm4_24bit_8bit_id32_dynamic; +using network_ipv4_source = dataplane::updater_lpm4_24bit_8bit_id32; +using network_ipv4_destination = dataplane::updater_lpm4_24bit_8bit_id32; using network_ipv6_source = YANET_CONFIG_ACL_NETWORK_LPM6_TYPE; -using network_ipv6_destination_ht = hashtable_mod_id32_dynamic; +using network_ipv6_destination_ht = dataplane::updater_hashtable_mod_id32; using network_ipv6_destination = YANET_CONFIG_ACL_NETWORK_LPM6_TYPE; using network_table = dynamic_table; -using transport_table = hashtable_mod_id32_dynamic; -using total_table = hashtable_mod_id32_dynamic; +using transport_table = dataplane::updater_hashtable_mod_id32; +using total_table = dataplane::updater_hashtable_mod_id32; } namespace nat64stateful @@ -134,6 +135,7 @@ class generation ~generation(); public: + eResult init(); eResult update(const common::idp::updateGlobalBase::request& request); eResult updateBalancer(const common::idp::updateGlobalBaseBalancer::request& request); eResult get(const common::idp::getGlobalBase::request& request, common::idp::getGlobalBase::globalBase& globalBaseResponse) const; @@ -193,14 +195,14 @@ class generation { struct { - acl::network_ipv4_source::updater network_ipv4_source; - acl::network_ipv4_destination::updater network_ipv4_destination; + std::unique_ptr network_ipv4_source; + std::unique_ptr network_ipv4_destination; acl::network_ipv6_source::updater network_ipv6_source; - acl::network_ipv6_destination_ht::updater network_ipv6_destination_ht; + std::unique_ptr network_ipv6_destination_ht; acl::network_ipv6_destination::updater network_ipv6_destination; acl::network_table::updater network_table; - acl::transport_table::updater transport_table; - acl::total_table::updater total_table; + std::unique_ptr transport_table; + std::unique_ptr total_table; } acl; } updater; @@ -257,14 +259,14 @@ class generation { struct { - acl::network_ipv4_source* source; - acl::network_ipv4_destination* destination; + acl::network_ipv4_source::object_type* source; + acl::network_ipv4_destination::object_type* destination; } ipv4; struct { acl::network_ipv6_source* source; - acl::network_ipv6_destination_ht* destination_ht; + acl::network_ipv6_destination_ht::object_type* destination_ht; acl::network_ipv6_destination* destination; } ipv6; } network; @@ -275,8 +277,8 @@ class generation uint32_t transport_layers_mask; acl::transport_layer_t* transport_layers; - acl::transport_table* transport_table; - acl::total_table* total_table; + acl::transport_table::object_type* transport_table; + acl::total_table::object_type* total_table; common::acl::value_t* values; } acl; diff --git a/dataplane/hashtable.h b/dataplane/hashtable.h index 622cd67f..1ea30019 100644 --- a/dataplane/hashtable.h +++ b/dataplane/hashtable.h @@ -230,7 +230,7 @@ class hashtable_chain_t } inline bool lookup(const TKey& key, - TValue*& value) + TValue*& value) const { lookup(&key, &value, 1); return (value != nullptr); @@ -1771,191 +1771,50 @@ class hashtable_mod_id32_dynamic constexpr static uint32_t mask_full = 0xFFFFFFFFu; constexpr static uint32_t shift_valid = (32 - 1 - valid_bit_offset); constexpr static uint64_t longest_chain_size = chunk_size; + constexpr static uint32_t pairs_size_min = 128; static_assert(__builtin_popcount(chunk_size) == 1); static_assert(valid_bit_offset < 32); -public: - class updater + struct stats_t { - public: - void update_pointer(hashtable_t* hashtable, - const tSocketId socket_id, - const uint32_t total_size) - { - this->hashtable = hashtable; - this->socket_id = socket_id; - this->total_size = total_size; - - hashtable->total_mask = total_size - 1; - } - - template - eResult update(const std::vector>& keys) - { - eResult result = eResult::success; - - keys_count = 0; - keys_in_chunks.fill(0); - longest_chain = 0; - insert_failed = 0; - rewrites = 0; - - for (const auto& [key, value] : keys) - { - eResult insert_result; - if constexpr (std::is_same_v) - { - insert_result = insert(key, value); - } - else - { - insert_result = insert(key_t::convert(key), value); - } - - if (insert_result != eResult::success) - { - result = insert_result; - } - } - - for (uint32_t chunk_i = 0; - chunk_i < total_size / chunk_size; - chunk_i++) - { - unsigned int count = 0; - - for (uint32_t pair_i = 0; - pair_i < chunk_size; - pair_i++) - { - if (hashtable->is_valid(chunk_i * chunk_size + pair_i)) - { - count++; - } - } - - keys_in_chunks[count]++; - } - - return result; - } - - void clear() - { - for (uint32_t i = 0; - i < total_size; - i++) - { - hashtable->pairs[i].value = 0; - } - } - - public: - template ///< @todo: common::idp::limits::response - void limits(list_T& list, - const std::string& name) const - { - list.emplace_back(name + ".keys", - socket_id, - keys_count, - total_size); - list.emplace_back(name + ".longest_collision", - socket_id, - longest_chain, - chunk_size); - } - - template ///< @todo: nlohmann::json - void report(json_t& json) const - { - json["total_size"] = total_size; - json["keys_count"] = keys_count; - for (unsigned int i = 0; - i < keys_in_chunks.size(); - i++) - { - json["keys_in_chunks"][i] = keys_in_chunks[i]; - } - json["longest_chain"] = longest_chain; - json["insert_failed"] = insert_failed; - json["rewrites"] = rewrites; - } - - protected: - eResult insert(const key_t& key, - const uint32_t value) - { - const uint32_t hash = calculate_hash(key) & (total_size - 1); - - for (unsigned int try_i = 0; - try_i < chunk_size; - try_i++) - { - const uint32_t index = (hash + try_i) % total_size; - - if (!hashtable->is_valid(index)) - { - memcpy(&hashtable->pairs[index].key, &key, sizeof(key_t)); - hashtable->pairs[index].value = value; - hashtable->pairs[index].value |= 1u << shift_valid; - - keys_count++; - - uint64_t longest_chain = try_i + 1; - if (this->longest_chain < longest_chain) - { - this->longest_chain = longest_chain; - } - - return eResult::success; - } - else if (hashtable->is_valid_and_equal(index, key)) - { - hashtable->pairs[index].value = value; - hashtable->pairs[index].value |= 1u << shift_valid; - - rewrites++; - - return eResult::success; - } - } - - insert_failed++; - - return eResult::isFull; - } - - public: - hashtable_t* hashtable; - tSocketId socket_id; - uint32_t total_size; - uint32_t keys_count; - std::array keys_in_chunks; + uint32_t pairs_count; + uint32_t pairs_size; + std::array pairs_in_chunks; uint32_t longest_chain; uint64_t insert_failed; uint64_t rewrites; }; -public: - static size_t calculate_sizeof(const uint32_t total_size) + static uint64_t calculate_sizeof(const uint32_t pairs_size) { - if (!total_size) + if (!pairs_size) { - YANET_LOG_ERROR("wrong total_size: %u\n", total_size); + YANET_LOG_ERROR("wrong pairs_size: %u\n", pairs_size); return 0; } - if (__builtin_popcount(total_size) != 1) + if (__builtin_popcount(pairs_size) != 1) { - YANET_LOG_ERROR("wrong total_size: %u is non power of 2\n", total_size); + YANET_LOG_ERROR("wrong pairs_size: %u is non power of 2\n", pairs_size); return 0; } - return sizeof(hashtable_t) + (size_t)total_size * sizeof(pair); + return sizeof(hashtable_t) + pairs_size * sizeof(pair); } public: + hashtable_mod_id32_dynamic(const uint32_t pairs_size) : + total_mask(pairs_size - 1) + { + for (uint32_t i = 0; + i < pairs_size; + i++) + { + pairs[i].value = 0; + } + } + /// value: /// valid invalid /// = 0VV = 1VV @@ -2035,14 +1894,90 @@ class hashtable_mod_id32_dynamic return mask; } -protected: - uint32_t total_mask; + eResult fill(stats_t& stats, const std::vector>& pairs) + { + eResult result = eResult::success; - struct pair + stats.pairs_count = 0; + stats.pairs_in_chunks.fill(0); + stats.longest_chain = 0; + stats.insert_failed = 0; + stats.rewrites = 0; + + for (const auto& [key, value] : pairs) + { + eResult insert_result = insert(stats, key, value); + if (insert_result != eResult::success) + { + result = insert_result; + } + } + + for (uint32_t chunk_i = 0; + chunk_i < stats.pairs_size / chunk_size; + chunk_i++) + { + unsigned int count = 0; + + for (uint32_t pair_i = 0; + pair_i < chunk_size; + pair_i++) + { + if (is_valid(chunk_i * chunk_size + pair_i)) + { + count++; + } + } + + stats.pairs_in_chunks[count]++; + } + + return result; + } + + eResult insert(stats_t& stats, + const key_t& key, + const uint32_t value) { - key_t key; - uint32_t value; - } pairs[]; + const uint32_t hash = calculate_hash(key) & total_mask; + + for (unsigned int try_i = 0; + try_i < chunk_size; + try_i++) + { + const uint32_t index = (hash + try_i) & total_mask; + + if (!is_valid(index)) + { + memcpy(&pairs[index].key, &key, sizeof(key_t)); + pairs[index].value = value; + pairs[index].value |= 1u << shift_valid; + + stats.pairs_count++; + + uint64_t longest_chain = try_i + 1; + if (stats.longest_chain < longest_chain) + { + stats.longest_chain = longest_chain; + } + + return eResult::success; + } + else if (is_valid_and_equal(index, key)) + { + pairs[index].value = value; + pairs[index].value |= 1u << shift_valid; + + stats.rewrites++; + + return eResult::success; + } + } + + stats.insert_failed++; + + return eResult::isFull; + } protected: inline bool is_valid(const uint32_t index) const @@ -2059,6 +1994,15 @@ class hashtable_mod_id32_dynamic { return is_valid(index) && is_equal(index, key); } + +protected: + uint32_t total_mask; + + struct pair + { + key_t key; + uint32_t value; + } pairs[]; }; class hashtable_mod_spinlock_stats ///< @todo: move to class::updater @@ -2184,7 +2128,7 @@ class hashtable_mod_spinlock } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ if (chunk_size == 1) @@ -2214,7 +2158,7 @@ class hashtable_mod_spinlock } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ } @@ -2661,7 +2605,7 @@ class hashtable_mod_spinlock_dynamic } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ if (chunk_size == 1) @@ -2691,7 +2635,7 @@ class hashtable_mod_spinlock_dynamic } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ } @@ -2989,6 +2933,11 @@ class hashtable_mod_dynamic class updater { public: + updater() : + hashtable(nullptr) + { + } + void update_pointer(hashtable_t* hashtable, const tSocketId socket_id, const uint32_t total_size) @@ -3011,7 +2960,6 @@ class hashtable_mod_dynamic return hashtable; } - public: range_t range(uint32_t& offset, const uint32_t step) { @@ -3242,7 +3190,7 @@ class hashtable_mod_dynamic } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ if (chunk_size == 1) @@ -3272,7 +3220,7 @@ class hashtable_mod_dynamic } /* else if (is_equal(chunk, pair_index, key)) { - /// hashtable is broken + /// hashtable is broken } */ } diff --git a/dataplane/lpm.h b/dataplane/lpm.h index 0afe4ed9..0f6d7eb1 100644 --- a/dataplane/lpm.h +++ b/dataplane/lpm.h @@ -1922,223 +1922,205 @@ class lpm4_24bit_8bit_id32 class lpm4_24bit_8bit_id32_dynamic { public: - class updater + constexpr static uint64_t extended_chunks_size_min = 8; + + struct stats_t { - public: - updater() : - extended_chunks_count(1) + uint32_t extended_chunks_size; + unsigned int extended_chunks_count; + std::vector remap_chunks; + }; + + static uint64_t calculate_sizeof(const uint64_t extended_chunks_size) + { + if (!extended_chunks_size) { + YANET_LOG_ERROR("wrong extended_chunks_size: %lu\n", extended_chunks_size); + return 0; } - void update_pointer(lpm4_24bit_8bit_id32_dynamic* lpm, - const tSocketId socket_id, - const uint32_t extended_chunks_size) + return sizeof(lpm4_24bit_8bit_id32_dynamic) + extended_chunks_size * sizeof(chunk_step2_t); + } + +public: + lpm4_24bit_8bit_id32_dynamic() + { + for (auto& value : root_chunk.values) { - this->lpm = lpm; - this->socket_id = socket_id; - this->extended_chunks_size = extended_chunks_size; + value.id = 0; } + } - eResult update(const std::vector& from_chunks) + template + inline void lookup(const ipv4_address_t (&addresses)[burst_size], + uint32_t (&group_ids)[burst_size], + const unsigned int count) const + { + /// @todo: OPT: le -> be + + for (unsigned int address_i = 0; + address_i < count; + address_i++) { - extended_chunks_count = 1; - remap_chunks.resize(0); - remap_chunks.resize(from_chunks.size(), 0); - return update_root_chunk<0>(from_chunks, 0, 0); + const auto& address = addresses[address_i].address; + auto& group_id = group_ids[address_i]; + + const auto& root_chunk_value = root_chunk.values[rte_be_to_cpu_32(address) >> 8]; + if (root_chunk_value.id & 0x80000000u) + { + const auto& extended_chunk = extended_chunks[root_chunk_value.id ^ 0x80000000u]; + group_id = extended_chunk.values[address >> 24].id; + } + else + { + group_id = root_chunk_value.id; + } } + } - public: - template ///< @todo: common::idp::limits::response - void limits(list_T& list, - const std::string& name) const + eResult fill(stats_t& stats, const std::vector& values) + { + stats.extended_chunks_count = 1; + stats.remap_chunks.resize(0); + stats.remap_chunks.resize(values.size(), 0); + + if (values.empty()) { - list.emplace_back(name + ".extended_chunks", - socket_id, - extended_chunks_count, - extended_chunks_size); + return eResult::success; } - template ///< @todo: nlohmann::json - void report(json_t& json) const + return update_root_chunk<0>(stats, values, 0, 0); + } + +protected: + constexpr static unsigned int bits_step1 = 24; + constexpr static unsigned int bits_step2 = 8; + constexpr static uint32_t mask_full = 0xFFFFFFFFu; + + unsigned int allocate_extended_chunk(stats_t& stats) + { + if (stats.extended_chunks_count >= stats.extended_chunks_size) { - json["extended_chunks_count"] = extended_chunks_count; + return 0; } - protected: - inline unsigned int allocate_extended_chunk() - { - if (extended_chunks_count >= extended_chunks_size) - { - return 0; - } + unsigned int new_chunk_id = stats.extended_chunks_count; + stats.extended_chunks_count++; - unsigned int new_chunk_id = extended_chunks_count; - extended_chunks_count++; + return new_chunk_id; + } - return new_chunk_id; - } + template + eResult update_root_chunk(stats_t& stats, + const std::vector& from_chunks, + const unsigned int from_chunk_id, + const unsigned int root_chunk_values_offset) + { + eResult result = eResult::success; - template - eResult update_root_chunk(const std::vector& from_chunks, - const unsigned int from_chunk_id, - const unsigned int root_chunk_values_offset) + const auto& from_chunk = from_chunks[from_chunk_id]; + for (uint32_t i = 0; + i < (1u << 8); + i++) { - eResult result = eResult::success; + const unsigned int root_chunk_values_i = root_chunk_values_offset + (i << (bits_step1 - bits_offset - 8)); + const auto& from_chunk_value = from_chunk.values[i]; - const auto& from_chunk = from_chunks[from_chunk_id]; - for (uint32_t i = 0; - i < (1u << 8); - i++) + if (from_chunk_value.is_chunk_id()) { - const unsigned int root_chunk_values_i = root_chunk_values_offset + (i << (bits_step1 - bits_offset - 8)); - const auto& from_chunk_value = from_chunk.values[i]; - - if (from_chunk_value.is_chunk_id()) + if constexpr (bits_offset < bits_step1 - bits_step2) { - if constexpr (bits_offset < bits_step1 - bits_step2) + result = update_root_chunk(stats, + from_chunks, + from_chunk_value.get_chunk_id(), + root_chunk_values_i); + if (result != eResult::success) { - result = update_root_chunk(from_chunks, - from_chunk_value.get_chunk_id(), - root_chunk_values_i); - if (result != eResult::success) - { - return result; - } + return result; } - else if constexpr (bits_offset < bits_step1) - { - auto& root_chunk_value = lpm->root_chunk.values[root_chunk_values_i]; + } + else if constexpr (bits_offset < bits_step1) + { + auto& root_chunk_value = root_chunk.values[root_chunk_values_i]; - auto& extended_chunk_id = remap_chunks[from_chunk_value.get_chunk_id()]; + auto& extended_chunk_id = stats.remap_chunks[from_chunk_value.get_chunk_id()]; + if (!extended_chunk_id) + { + extended_chunk_id = allocate_extended_chunk(stats); if (!extended_chunk_id) { - extended_chunk_id = allocate_extended_chunk(); - if (!extended_chunk_id) - { - YANET_LOG_ERROR("lpm is full\n"); - return eResult::isFull; - } - - result = update_extended_chunk(from_chunks, - from_chunk_value.get_chunk_id(), - extended_chunk_id); - if (result != eResult::success) - { - return result; - } + YANET_LOG_ERROR("lpm is full\n"); + return eResult::isFull; } - root_chunk_value.id = extended_chunk_id ^ 0x80000000u; - } - else - { - YANET_LOG_ERROR("tree broken\n"); - return eResult::invalidArguments; + result = update_extended_chunk(from_chunks, + from_chunk_value.get_chunk_id(), + extended_chunk_id); + if (result != eResult::success) + { + return result; + } } + + root_chunk_value.id = extended_chunk_id ^ 0x80000000u; } else { - if constexpr (bits_offset < bits_step1) - { - for (uint32_t j = 0; - j < (1u << (bits_step1 - bits_offset - 8)); - j++) - { - lpm->root_chunk.values[root_chunk_values_i + j].id = from_chunk_value.get_group_id(); - } - } - else - { - YANET_LOG_ERROR("tree broken\n"); - return eResult::invalidArguments; - } + YANET_LOG_ERROR("tree broken\n"); + return eResult::invalidArguments; } } - - return result; - } - - eResult update_extended_chunk(const std::vector& from_chunks, - const unsigned int from_chunk_id, - const unsigned int extended_chunk_id) - { - const auto& from_chunk = from_chunks[from_chunk_id]; - auto& extended_chunk = lpm->extended_chunks[extended_chunk_id]; - - for (uint32_t i = 0; - i < (1u << 8); - i++) + else { - const auto& from_chunk_value = from_chunk.values[i]; - auto& extended_chunk_value = extended_chunk.values[i]; - - if (from_chunk_value.is_chunk_id()) + if constexpr (bits_offset < bits_step1) { - YANET_LOG_ERROR("is_chunk_id\n"); - return eResult::invalidArguments; + for (uint32_t j = 0; + j < (1u << (bits_step1 - bits_offset - 8)); + j++) + { + root_chunk.values[root_chunk_values_i + j].id = from_chunk_value.get_group_id(); + } } else { - extended_chunk_value.id = from_chunk_value.get_group_id(); + YANET_LOG_ERROR("tree broken\n"); + return eResult::invalidArguments; } } - - return eResult::success; - } - - public: - lpm4_24bit_8bit_id32_dynamic* lpm; - tSocketId socket_id; - uint32_t extended_chunks_size; - unsigned int extended_chunks_count; - std::vector remap_chunks; - }; - -public: - static size_t calculate_sizeof(const uint32_t extended_chunks_size) - { - if (!extended_chunks_size) - { - YANET_LOG_ERROR("wrong extended_chunks_size: %u\n", extended_chunks_size); - return 0; } - return sizeof(lpm4_24bit_8bit_id32_dynamic) + extended_chunks_size * sizeof(chunk_step2_t); + return result; } -public: - template - inline void lookup(const ipv4_address_t (&addresses)[burst_size], - uint32_t (&group_ids)[burst_size], - const unsigned int count) const + eResult update_extended_chunk(const std::vector& from_chunks, + const unsigned int from_chunk_id, + const unsigned int extended_chunk_id) { - /// @todo: OPT: le -> be + const auto& from_chunk = from_chunks[from_chunk_id]; + auto& extended_chunk = extended_chunks[extended_chunk_id]; - for (unsigned int address_i = 0; - address_i < count; - address_i++) + for (uint32_t i = 0; + i < (1u << 8); + i++) { - const auto& address = addresses[address_i].address; - auto& group_id = group_ids[address_i]; + const auto& from_chunk_value = from_chunk.values[i]; + auto& extended_chunk_value = extended_chunk.values[i]; - const auto& root_chunk_value = root_chunk.values[rte_be_to_cpu_32(address) >> 8]; - if (root_chunk_value.id & 0x80000000u) + if (from_chunk_value.is_chunk_id()) { - const auto& extended_chunk = extended_chunks[root_chunk_value.id ^ 0x80000000u]; - group_id = extended_chunk.values[address >> 24].id; + YANET_LOG_ERROR("is_chunk_id\n"); + return eResult::invalidArguments; } else { - group_id = root_chunk_value.id; + extended_chunk_value.id = from_chunk_value.get_group_id(); } } + + return eResult::success; } protected: - constexpr static unsigned int bits_step1 = 24; - constexpr static unsigned int bits_step2 = 8; - constexpr static uint32_t mask_full = 0xFFFFFFFFu; - struct value_t { uint32_t id; diff --git a/dataplane/memory_manager.cpp b/dataplane/memory_manager.cpp new file mode 100644 index 00000000..1d039cea --- /dev/null +++ b/dataplane/memory_manager.cpp @@ -0,0 +1,142 @@ +#include "memory_manager.h" + +using namespace dataplane; + +memory_pointer::memory_pointer(const char* name, + const tSocketId socket_id, + const size_t size, + void* pointer, + const std::function& destructor) : + name(name), + socket_id(socket_id), + size(size), + pointer(pointer), + destructor(destructor) +{ +} + +memory_pointer::~memory_pointer() +{ + YANET_LOG_INFO("yanet_free(name: '%s', socket: %u, size: %lu)\n", + name.data(), + socket_id, + size); + destructor(pointer); +} + +memory_manager::memory_manager() : + dataplane(nullptr) +{ +} + +eResult memory_manager::init(cDataPlane* dataplane) +{ + this->dataplane = dataplane; + return eResult::success; +} + +inline std::string to_hex(const void* pointer) +{ + char buffer[128]; + snprintf(buffer, 128, "%p", pointer); + return buffer; +} + +void memory_manager::report(nlohmann::json& json) +{ + std::lock_guard guard(pointers_mutex); + for (const auto& [pointer, memory_pointer] : pointers) + { + nlohmann::json json_object; + json_object["pointer"] = to_hex(pointer); + json_object["name"] = memory_pointer.name; + json_object["socket_id"] = memory_pointer.socket_id; + json_object["size"] = memory_pointer.size; + json["memory_manager"].emplace_back(json_object); + } +} + +eResult memory_manager::memory_manager_update(const common::idp::memory_manager_update::request& request) +{ + root_memory_group = request; + return eResult::success; +} + +void* memory_manager::alloc(const char* name, + const tSocketId socket_id, + uint64_t size, + const std::function& destructor) +{ + if (!size) + { + YANET_LOG_ERROR("error allocation memory (name: '%s', socket: %u, size: %lu)\n", + name, + socket_id, + size); + return nullptr; + } + + size += 2 * RTE_CACHE_LINE_SIZE; + + YANET_LOG_INFO("yanet_alloc(name: '%s', socket: %u, size: %lu)\n", + name, + socket_id, + size); + + void* pointer = rte_malloc_socket(nullptr, + size, + RTE_CACHE_LINE_SIZE, + socket_id); + if (pointer == nullptr) + { + YANET_LOG_ERROR("error allocation memory (name: '%s', socket: %u, size: %lu)\n", + name, + socket_id, + size); + debug(socket_id); + return nullptr; + } + + { + std::lock_guard guard(pointers_mutex); + pointers.try_emplace(pointer, name, socket_id, size, pointer, [destructor](void* pointer) { + destructor(pointer); + rte_free(pointer); + }); + } + + return pointer; +} + +void memory_manager::destroy(void* pointer) +{ + std::lock_guard guard(pointers_mutex); + + auto it = pointers.find(pointer); + if (it == pointers.end()) + { + YANET_LOG_ERROR("unknown pointer: %p\n", pointer); + return; + } + + pointers.erase(it); +} + +void memory_manager::debug(tSocketId socket_id) +{ + rte_malloc_socket_stats stats; + if (rte_malloc_get_socket_stats(socket_id, &stats) == 0) + { + YANET_LOG_INFO("heap_totalsz_bytes: %lu MB\n", stats.heap_totalsz_bytes / (1024 * 1024)); + YANET_LOG_INFO("heap_freesz_bytes: %lu MB\n", stats.heap_freesz_bytes / (1024 * 1024)); + YANET_LOG_INFO("greatest_free_size: %lu MB\n", stats.greatest_free_size / (1024 * 1024)); + YANET_LOG_INFO("free_count: %u\n", stats.free_count); + YANET_LOG_INFO("alloc_count: %u\n", stats.alloc_count); + YANET_LOG_INFO("heap_allocsz_bytes: %lu MB\n", stats.heap_allocsz_bytes / (1024 * 1024)); + } +} + +void dataplane::memory_manager::limits(common::idp::limits::response& response) +{ + (void)response; +} diff --git a/dataplane/memory_manager.h b/dataplane/memory_manager.h new file mode 100644 index 00000000..4032d22e --- /dev/null +++ b/dataplane/memory_manager.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +#include + +#include "common/idp.h" +#include "common/memory_manager.h" +#include "common/result.h" +#include "type.h" + +namespace dataplane +{ + +class memory_pointer +{ +public: + memory_pointer(const char* name, const tSocketId socket_id, const size_t size, void* pointer, const std::function& destructor); + ~memory_pointer(); + +public: + std::string name; + tSocketId socket_id; + size_t size; + void* pointer; + std::function destructor; +}; + +class memory_manager +{ +public: + memory_manager(); + + eResult init(cDataPlane* dataplane); + void report(nlohmann::json& json); + void limits(common::idp::limits::response& response); + eResult memory_manager_update(const common::idp::memory_manager_update::request& request); + + void* alloc( + const char* name, + const tSocketId socket_id, + const uint64_t size, + const std::function& destructor = [](void*) {}); + + template + type* create(const char* name, + const tSocketId socket_id, + const uint64_t size, + const args_t&... args) + { + void* pointer = alloc(name, socket_id, size, [](void* pointer) { + reinterpret_cast(pointer)->~type(); + }); + + if (pointer == nullptr) + { + return nullptr; + } + + return new (reinterpret_cast(pointer)) type(args...); + } + + void destroy(void* pointer); + void debug(tSocketId socket_id); + +protected: + cDataPlane* dataplane; + common::memory_manager::memory_group root_memory_group; + + std::mutex pointers_mutex; + std::map pointers; +}; + +} diff --git a/dataplane/meson.build b/dataplane/meson.build index 1a8d0712..ae8518b2 100644 --- a/dataplane/meson.build +++ b/dataplane/meson.build @@ -11,6 +11,7 @@ sources = files('bus.cpp', 'fragmentation.cpp', 'globalbase.cpp', 'main.cpp', + 'memory_manager.cpp', 'neighbor.cpp', 'report.cpp', 'sharedmemory.cpp', diff --git a/dataplane/report.cpp b/dataplane/report.cpp index 78677c76..c08c501e 100644 --- a/dataplane/report.cpp +++ b/dataplane/report.cpp @@ -106,6 +106,7 @@ nlohmann::json cReport::getReport() jsonReport["memory_total"] = memory_total; dataPlane->neighbor.report(jsonReport); + dataPlane->memory_manager.report(jsonReport); return jsonReport; } @@ -686,12 +687,12 @@ nlohmann::json cReport::convertGlobalBase(const dataplane::globalBase::generatio } globalBase->updater.acl.network_table.report(json["acl"]["network_table"]); - globalBase->updater.acl.transport_table.report(json["acl"]["transport_table"]); - globalBase->updater.acl.total_table.report(json["acl"]["total_table"]); - globalBase->updater.acl.network_ipv4_source.report(json["acl"]["network"]["ipv4"]["source"]); - globalBase->updater.acl.network_ipv4_destination.report(json["acl"]["network"]["ipv4"]["destination"]); + globalBase->updater.acl.transport_table->report(json["acl"]["transport_table"]); + globalBase->updater.acl.total_table->report(json["acl"]["total_table"]); + globalBase->updater.acl.network_ipv4_source->report(json["acl"]["network"]["ipv4"]["source"]); + globalBase->updater.acl.network_ipv4_destination->report(json["acl"]["network"]["ipv4"]["destination"]); globalBase->updater.acl.network_ipv6_source.report(json["acl"]["network"]["ipv6"]["source"]); - globalBase->updater.acl.network_ipv6_destination_ht.report(json["acl"]["network"]["ipv6"]["destination_ht"]); + globalBase->updater.acl.network_ipv6_destination_ht->report(json["acl"]["network"]["ipv6"]["destination_ht"]); globalBase->updater.acl.network_ipv6_destination.report(json["acl"]["network"]["ipv6"]["destination"]); json["serial"] = globalBase->serial; diff --git a/dataplane/updater.h b/dataplane/updater.h new file mode 100644 index 00000000..7c680da4 --- /dev/null +++ b/dataplane/updater.h @@ -0,0 +1,239 @@ +#pragma once + +#include +#include +#include + +#include "common.h" +#include "common/idp.h" +#include "hashtable.h" +#include "lpm.h" +#include "memory_manager.h" + +namespace dataplane +{ + +[[maybe_unused]] static uint32_t upper_power_of_two(const uint32_t value) +{ + /// @todo: use __builtin_clz + + uint32_t result = 1; + while (result < value) + { + result <<= 1; + if (!result) + { + return 0; + } + } + return result; +} + +[[maybe_unused]] static std::string to_hex(const void* pointer) +{ + char buffer[128]; + snprintf(buffer, 128, "%p", pointer); + return buffer; +} + +class updater_lpm4_24bit_8bit_id32 +{ +public: + using object_type = lpm4_24bit_8bit_id32_dynamic; + + updater_lpm4_24bit_8bit_id32(const char* name, + dataplane::memory_manager* memory_manager, + const tSocketId socket_id) : + name(name), + memory_manager(memory_manager), + socket_id(socket_id), + pointer(nullptr) + { + } + + eResult init() + { + return update({}); + } + + eResult update(const std::vector& values) + { + stats.extended_chunks_size = std::max((uint64_t)object_type::extended_chunks_size_min, + values.size() / 2); + + /// destroy pointer if exist + clear(); + + for (;;) + { + pointer = memory_manager->create(name.data(), + socket_id, + object_type::calculate_sizeof(stats.extended_chunks_size)); + if (pointer == nullptr) + { + return eResult::errorAllocatingMemory; + } + + eResult result = pointer->fill(stats, values); + if (result != eResult::success) + { + /// try again + memory_manager->destroy(pointer); + stats.extended_chunks_size *= 2; + continue; + } + + break; + } + + return eResult::success; + } + + void clear() + { + if (pointer) + { + memory_manager->destroy(pointer); + pointer = nullptr; + } + } + + void limits(common::idp::limits::response& limits) const + { + limits.emplace_back(name + ".extended_chunks", + socket_id, + stats.extended_chunks_count, + stats.extended_chunks_size); + } + + void report(nlohmann::json& report) const + { + report["pointer"] = to_hex(pointer); + report["extended_chunks_count"] = stats.extended_chunks_count; + report["extended_chunks_size"] = stats.extended_chunks_size; + } + +protected: + std::string name; + dataplane::memory_manager* memory_manager; + tSocketId socket_id; + + object_type::stats_t stats; + +public: + object_type* pointer; +}; + +// + +template calculate_hash = calculate_hash_crc> +class updater_hashtable_mod_id32 +{ +public: + using object_type = hashtable_mod_id32_dynamic; + + updater_hashtable_mod_id32(const char* name, + dataplane::memory_manager* memory_manager, + const tSocketId socket_id) : + name(name), + memory_manager(memory_manager), + socket_id(socket_id), + pointer(nullptr) + { + } + + eResult init() + { + return update({}); + } + + eResult update(const std::vector>& values, bool retry = true) + { + stats.pairs_size = upper_power_of_two(std::max(object_type::pairs_size_min, + (uint32_t)(4ull * values.size()))); + + /// destroy pointer if exist + clear(); + + eResult result = eResult::success; + for (;;) + { + pointer = memory_manager->create(name.data(), + socket_id, + object_type::calculate_sizeof(stats.pairs_size), + stats.pairs_size); + if (pointer == nullptr) + { + return eResult::errorAllocatingMemory; + } + + result = pointer->fill(stats, values); + if (result != eResult::success) + { + if (retry) + { + /// try again + memory_manager->destroy(pointer); + stats.pairs_size *= 2; + continue; + } + } + + break; + } + + return result; + } + + void clear() + { + if (pointer) + { + memory_manager->destroy(pointer); + pointer = nullptr; + } + } + + void limits(common::idp::limits::response& limits) const + { + limits.emplace_back(name + ".keys", + socket_id, + stats.pairs_count, + stats.pairs_size); + limits.emplace_back(name + ".longest_collision", + socket_id, + stats.longest_chain, + chunk_size); + } + + void report(nlohmann::json& report) const + { + report["pointer"] = to_hex(pointer); + report["pairs_count"] = stats.pairs_count; + report["pairs_size"] = stats.pairs_size; + for (unsigned int i = 0; + i < stats.pairs_in_chunks.size(); + i++) + { + report["pairs_in_chunks"][i] = stats.pairs_in_chunks[i]; + } + report["longest_chain"] = stats.longest_chain; + report["insert_failed"] = stats.insert_failed; + report["rewrites"] = stats.rewrites; + } + +protected: + std::string name; + dataplane::memory_manager* memory_manager; + tSocketId socket_id; + + typename object_type::stats_t stats; + +public: + object_type* pointer; +}; + +}