diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index db946bb1..4f38664a 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -78,6 +78,11 @@ eResult tAutotest::init(const std::string& binaryPath, return ret; } + if (auto ret = common::sdp::SdpClient::ReadSharedMemoryData(sdp_data, true); ret != eResult::success) + { + return ret; + } + return eResult::success; } @@ -1746,7 +1751,7 @@ bool tAutotest::step_memorize_counter_value(const YAML::Node& yamlStep) uint32_t coreId = std::stoi(yamlStep.as().substr(delim_pos + 1)); - const auto response = dataPlane.get_counter_by_name({counter_name, coreId}); + const auto response = common::sdp::SdpClient::GetCounterByName(sdp_data, counter_name, coreId); if (response.empty()) { @@ -1805,7 +1810,7 @@ bool tAutotest::step_diff_with_kept_counter_value(const YAML::Node& yamlStep) return false; } - const auto response = dataPlane.get_counter_by_name({counter_name, coreId}); + const auto response = common::sdp::SdpClient::GetCounterByName(sdp_data, counter_name, coreId); if (response.empty()) { diff --git a/autotest/autotest.h b/autotest/autotest.h index edd2c840..873e9ef4 100644 --- a/autotest/autotest.h +++ b/autotest/autotest.h @@ -11,6 +11,7 @@ #include "common/icontrolplane.h" #include "common/idataplane.h" #include "common/result.h" +#include "common/sdpclient.h" namespace nAutotest { @@ -96,6 +97,7 @@ class tAutotest interface::dataPlane dataPlane; interface::controlPlane controlPlane; + common::sdp::DataPlaneInSharedMemory sdp_data; common::idp::getConfig::response dataPlaneConfig; common::idp::get_shm_info::response dataPlaneSharedMemory; diff --git a/autotest/units/001_one_port/075_counters_shared_memory/autotest.yaml b/autotest/units/001_one_port/075_counters_shared_memory/autotest.yaml new file mode 100644 index 00000000..ff96e5f0 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_shared_memory/autotest.yaml @@ -0,0 +1,5 @@ +steps: +- cli: "telegraf counters" +- cli: "telegraf bus" +- cli: "bus errors" +- cli: "bus requests" diff --git a/autotest/units/001_one_port/075_counters_shared_memory/controlplane.conf b/autotest/units/001_one_port/075_counters_shared_memory/controlplane.conf new file mode 100644 index 00000000..a49ff792 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_shared_memory/controlplane.conf @@ -0,0 +1,32 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "vrf0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "vrf0" + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/yanet-autotest-run.py b/autotest/yanet-autotest-run.py index 492c16a8..19ce51b5 100755 --- a/autotest/yanet-autotest-run.py +++ b/autotest/yanet-autotest-run.py @@ -86,6 +86,7 @@ def start(self, dataplane_conf_path, units): os.makedirs("/run/yanet", exist_ok=True) self.run_dataplane(dataplane_conf_path) + time.sleep(5) self.run_controlplane() self.run_autotest(units) diff --git a/cli/bus.h b/cli/bus.h new file mode 100644 index 00000000..e26c2456 --- /dev/null +++ b/cli/bus.h @@ -0,0 +1,160 @@ +#pragma once + +#include "helper.h" +#include "influxdb_format.h" + +namespace bus +{ + +using bus_request_info = std::tuple; + +inline std::vector get_bus_requests(common::sdp::DataPlaneInSharedMemory& sdp_data) +{ + auto [requests, errors, durations] = sdp_data.BuffersBus(); + (void)errors; + + std::map names = { + {common::idp::requestType::updateGlobalBase, "updateGlobalBase"}, + {common::idp::requestType::updateGlobalBaseBalancer, "updateGlobalBaseBalancer"}, + {common::idp::requestType::getGlobalBase, "getGlobalBase"}, + {common::idp::requestType::getWorkerStats, "getWorkerStats"}, + {common::idp::requestType::getSlowWorkerStats, "getSlowWorkerStats"}, + {common::idp::requestType::get_worker_gc_stats, "get_worker_gc_stats"}, + {common::idp::requestType::get_dregress_counters, "get_dregress_counters"}, + {common::idp::requestType::get_ports_stats, "get_ports_stats"}, + {common::idp::requestType::get_ports_stats_extended, "get_ports_stats_extended"}, + {common::idp::requestType::getControlPlanePortStats, "getControlPlanePortStats"}, + {common::idp::requestType::getPortStatsEx, "getPortStatsEx"}, + {common::idp::requestType::getFragmentationStats, "getFragmentationStats"}, + {common::idp::requestType::getFWState, "getFWState"}, + {common::idp::requestType::getFWStateStats, "getFWStateStats"}, + {common::idp::requestType::clearFWState, "clearFWState"}, + {common::idp::requestType::getConfig, "getConfig"}, + {common::idp::requestType::getErrors, "getErrors"}, + {common::idp::requestType::getReport, "getReport"}, + {common::idp::requestType::lpm4LookupAddress, "lpm4LookupAddress"}, + {common::idp::requestType::lpm6LookupAddress, "lpm6LookupAddress"}, + {common::idp::requestType::nat64stateful_state, "nat64stateful_state"}, + {common::idp::requestType::balancer_connection, "balancer_connection"}, + {common::idp::requestType::balancer_service_connections, "balancer_service_connections"}, + {common::idp::requestType::balancer_real_connections, "balancer_real_connections"}, + {common::idp::requestType::limits, "limits"}, + {common::idp::requestType::samples, "samples"}, + {common::idp::requestType::debug_latch_update, "debug_latch_update"}, + {common::idp::requestType::unrdup_vip_to_balancers, "unrdup_vip_to_balancers"}, + {common::idp::requestType::update_vip_vport_proto, "update_vip_vport_proto"}, + {common::idp::requestType::version, "version"}, + {common::idp::requestType::get_shm_info, "get_shm_info"}, + {common::idp::requestType::get_shm_tsc_info, "get_shm_tsc_info"}, + {common::idp::requestType::set_shm_tsc_state, "set_shm_tsc_state"}, + {common::idp::requestType::dump_physical_port, "dump_physical_port"}, + {common::idp::requestType::balancer_state_clear, "balancer_state_clear"}, + {common::idp::requestType::neighbor_show, "neighbor_show"}, + {common::idp::requestType::neighbor_insert, "neighbor_insert"}, + {common::idp::requestType::neighbor_remove, "neighbor_remove"}, + {common::idp::requestType::neighbor_clear, "neighbor_clear"}, + {common::idp::requestType::neighbor_flush, "neighbor_flush"}, + {common::idp::requestType::neighbor_update_interfaces, "neighbor_update_interfaces"}, + {common::idp::requestType::neighbor_stats, "neighbor_stats"}, + {common::idp::requestType::memory_manager_update, "memory_manager_update"}, + {common::idp::requestType::memory_manager_stats, "memory_manager_stats"}}; + + std::vector result; + for (uint32_t index = 0; index < (uint32_t)common::idp::requestType::size; ++index) + { + if ((requests[index] != 0) || (durations[index] != 0)) + { + const auto& iter = names.find(static_cast(index)); + result.emplace_back((iter != names.end() ? iter->second : "unknown"), requests[index], durations[index]); + } + } + + return result; +} + +inline void bus_requests() +{ + common::sdp::DataPlaneInSharedMemory sdp_data; + OpenSharedMemoryDataplaneBuffers(sdp_data, false); + auto requests = get_bus_requests(sdp_data); + + table_t table; + table.insert("request", "count", "duration_ms"); + for (const auto& [request, count, duration] : requests) + { + if ((count != 0) || (duration != 0)) + { + table.insert(request, count, duration); + } + } + + table.print(); +} + +inline std::vector> get_bus_errors(const common::sdp::DataPlaneInSharedMemory& sdp_data) +{ + auto [requests, errors, durations] = sdp_data.BuffersBus(); + (void)requests; + (void)durations; + + std::map names = { + {common::idp::errorType::busRead, "busRead"}, + {common::idp::errorType::busWrite, "busWrite"}, + {common::idp::errorType::busParse, "busParse"}, + }; + + std::vector> result; + for (uint32_t index = 0; index < (uint32_t)common::idp::errorType::size; ++index) + { + const auto& iter = names.find(static_cast(index)); + result.emplace_back((iter != names.end() ? iter->second : "unknown"), errors[index]); + } + + return result; +} + +inline void bus_errors() +{ + common::sdp::DataPlaneInSharedMemory sdp_data; + OpenSharedMemoryDataplaneBuffers(sdp_data, false); + auto errors = get_bus_errors(sdp_data); + + table_t table; + table.insert("error", "count"); + for (const auto& [error, count] : errors) + { + table.insert(error, count); + } + + table.print(); +} + +inline void bus_telegraf() +{ + common::sdp::DataPlaneInSharedMemory sdp_data; + OpenSharedMemoryDataplaneBuffers(sdp_data, false); + + auto errors = get_bus_errors(sdp_data); + std::vector infl_errors; + for (const auto& [error, count] : errors) + { + infl_errors.emplace_back(error.data(), count); + } + influxdb_format::print("bus_errors", {}, infl_errors); + + auto requests = get_bus_requests(sdp_data); + if (!requests.empty()) + { + std::vector infl_counts; + std::vector infl_durations; + for (const auto& [request, count, duration] : requests) + { + infl_counts.emplace_back(request.data(), count); + infl_durations.emplace_back(request.data(), duration); + } + influxdb_format::print("bus_counts", {}, infl_counts); + influxdb_format::print("bus_durations", {}, infl_durations); + } +} + +} // namespace bus diff --git a/cli/develop.h b/cli/develop.h index 88c4e0b7..46eba193 100644 --- a/cli/develop.h +++ b/cli/develop.h @@ -9,6 +9,7 @@ #include "common/icontrolplane.h" #include "common/idataplane.h" +#include "common/sdpclient.h" #include "common/tsc_deltas.h" #include "helper.h" @@ -151,7 +152,7 @@ void counter(const uint32_t& counter_id, } } - const auto response = dataplane.getCounters(counter_ids); + const auto response = common::sdp::SdpClient::GetCounters(counter_ids); table_t table; table.insert("counter_id", diff --git a/cli/helper.h b/cli/helper.h index 66890a57..4d4ceea6 100644 --- a/cli/helper.h +++ b/cli/helper.h @@ -12,6 +12,7 @@ #include +#include "common/sdpclient.h" #include "converter.h" template @@ -466,3 +467,12 @@ class table_t std::vector> table; std::vector columnLengths; }; + +void OpenSharedMemoryDataplaneBuffers(common::sdp::DataPlaneInSharedMemory& sdp_data, bool open_workers_data) +{ + if (common::sdp::SdpClient::ReadSharedMemoryData(sdp_data, open_workers_data) != eResult::success) + { + YANET_LOG_ERROR("Error openning shared memory dataplane buffers\n"); + std::exit(1); + } +} diff --git a/cli/main.cpp b/cli/main.cpp index ccd74548..fc54b443 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -5,6 +5,7 @@ #include "acl.h" #include "balancer.h" +#include "bus.h" #include "config.h" #include "convert.h" #include "develop.h" @@ -127,12 +128,18 @@ std::vector ", [](const auto& args) { call(latch::dataplane_update, args); }}, {"counter", "[counter_name] ", [](const auto& args) { call(show::counter_by_name, args); }}, {"counters stat", "", [](const auto& args) { call(show::counters_stat, args); }}, + + {"bus requests", "", [](const auto& args) { call(bus::bus_requests, args); }}, + {"bus errors", "", [](const auto& args) { call(bus::bus_errors, args); }}, + {"latch update dataplane", " ", [](const auto& args) { call(latch::dataplane_update, args); }}, {}, {"convert logical_module", "", [](const auto& args) { call(convert::logical_module, args); }}}; diff --git a/cli/show.h b/cli/show.h index b9f2e7e8..6de4f7ca 100644 --- a/cli/show.h +++ b/cli/show.h @@ -6,6 +6,7 @@ #include "common/icontrolplane.h" #include "common/idataplane.h" +#include "common/sdpclient.h" #include "common/tsc_deltas.h" #include "common/version.h" @@ -800,9 +801,7 @@ inline void version() inline void counter_by_name(std::string counter_name, const std::optional& core_id) { - interface::dataPlane dataplane; - - const auto response = dataplane.get_counter_by_name({counter_name, core_id}); + const auto response = common::sdp::SdpClient::GetCounterByName(counter_name, core_id); if (response.empty()) { diff --git a/cli/telegraf.h b/cli/telegraf.h index 20257f3b..1c24b0e0 100644 --- a/cli/telegraf.h +++ b/cli/telegraf.h @@ -3,6 +3,7 @@ #include "common/counters.h" #include "common/icontrolplane.h" #include "common/idataplane.h" +#include "common/sdpclient.h" #include "helper.h" #include "influxdb_format.h" @@ -100,7 +101,7 @@ void unsafe() const auto [responseWorkers, responseWorkerGCs, responseSlowWorkerHashtableGC, responseFragmentation, responseFWState, responseTun64, response_nat64stateful, responseControlplane] = controlplane.telegraf_unsafe(); const auto& [responseSlowWorker, hashtable_gc] = responseSlowWorkerHashtableGC; - const auto static_counters = dataplane.getCounters(vector_range(0, (tCounterId)common::globalBase::static_counter_type::size)); + const auto static_counters = common::sdp::SdpClient::GetCounters(vector_range(0, (tCounterId)common::globalBase::static_counter_type::size)); const auto neighbor_stats = dataplane.neighbor_stats(); const auto memory_stats = dataplane.memory_manager_stats(); const auto& [memory_groups, memory_objects] = memory_stats; @@ -701,4 +702,34 @@ void service() } +void main_counters() +{ + common::sdp::DataPlaneInSharedMemory sdp_data; + OpenSharedMemoryDataplaneBuffers(sdp_data, true); + + for (const auto& [coreId, worker_info] : sdp_data.workers) + { + std::vector values; + uint64_t* buffer = common::sdp::ShiftBuffer(worker_info.buffer, + sdp_data.metadata_worker.start_counters); + for (const auto& [name, index] : sdp_data.metadata_worker.counter_positions) + { + values.emplace_back(name.data(), buffer[index]); + } + influxdb_format::print("worker", {{"coreId", coreId}}, values); + } + + for (const auto& [coreId, worker_info] : sdp_data.workers_gc) + { + std::vector values; + uint64_t* buffer = common::sdp::ShiftBuffer(worker_info.buffer, + sdp_data.metadata_worker.start_counters); + for (const auto& [name, index] : sdp_data.metadata_worker_gc.counter_positions) + { + values.emplace_back(name.data(), buffer[index]); + } + influxdb_format::print("worker_gc", {{"coreId", coreId}}, values); + } +} + } diff --git a/common/idataplane.h b/common/idataplane.h index 5e1c40b9..eb131d56 100644 --- a/common/idataplane.h +++ b/common/idataplane.h @@ -103,26 +103,11 @@ class dataPlane return get(); } - common::idp::getAclCounters::response getAclCounters() const - { - return get(); - } - common::idp::getPortStatsEx::response getPortStatsEx() const { return get(); } - common::idp::getCounters::response getCounters(const common::idp::getCounters::request& request) const - { - return get(request); - } - - common::idp::getOtherStats::response getOtherStats() const - { - return get(); - } - common::idp::getConfig::response getConfig() const { return get(); @@ -193,11 +178,6 @@ class dataPlane return get(); } - auto get_counter_by_name(const common::idp::get_counter_by_name::request& request) const - { - return get(request); - } - auto get_shm_info() const { return get(); @@ -287,7 +267,12 @@ class dataPlane int ret = connect(clientSocket, (struct sockaddr*)&address, sizeof(address)); if (ret == -1) { - throw std::string("connect(): ") + strerror(errno); + int error = errno; + YANET_LOG_ERROR("Error connect to socket %s, error: %d - %s\n", + common::idp::socketPath, + error, + strerror(error)); + throw std::string("connect(): ") + strerror(error); } } diff --git a/common/idp.h b/common/idp.h index 5fff9294..19eca0d8 100644 --- a/common/idp.h +++ b/common/idp.h @@ -48,13 +48,10 @@ enum class requestType : uint32_t get_ports_stats_extended, getControlPlanePortStats, getPortStatsEx, - getCounters, getFragmentationStats, getFWState, getFWStateStats, clearFWState, - getAclCounters, - getOtherStats, getConfig, getErrors, getReport, @@ -70,7 +67,6 @@ enum class requestType : uint32_t unrdup_vip_to_balancers, update_vip_vport_proto, version, - get_counter_by_name, get_shm_info, get_shm_tsc_info, set_shm_tsc_state, @@ -663,13 +659,6 @@ namespace getPortStatsEx using response = ::common::getPortStatsEx::response; } -namespace getCounters -{ -using request = std::vector; - -using response = std::vector; -} - namespace getFragmentationStats { using response = fragmentation::stats_t; @@ -703,18 +692,6 @@ namespace getFWStateStats using response = fwstate::stats_t; } -namespace getAclCounters -{ -using response = std::vector; -} - -namespace getOtherStats -{ -using worker = std::tuple>; ///< bursts - -using response = std::tuple>; -} - namespace getConfig { enum class value_type ///< @todo: delete @@ -863,13 +840,6 @@ using response = std::tuple; ///< custom } -namespace get_counter_by_name -{ -using request = std::tuple>; - -using response = std::map; -} - namespace get_shm_info { using dump_meta = std::tuple, get_ports_stats::response, ///< + getControlPlanePortStats::response get_ports_stats_extended::response, getPortStatsEx::response, - getOtherStats::response, getFragmentationStats::response, getFWState::response, getFWStateStats::response, - getAclCounters::response, ///< + getCounters::response getConfig::response, getErrors::response, getReport::response, @@ -1044,7 +1010,6 @@ using response = std::variant, version::response, limits::response, samples::response, - get_counter_by_name::response, get_shm_info::response, get_shm_tsc_info::response, neighbor_show::response, diff --git a/common/sdpclient.h b/common/sdpclient.h new file mode 100644 index 00000000..b2b91007 --- /dev/null +++ b/common/sdpclient.h @@ -0,0 +1,462 @@ +#pragma once + +#include + +#include "result.h" +#include "sdpcommon.h" +#include "shared_memory.h" + +#define SHARED_MEMORY_REREAD_TIMEOUT_MICROSECONDS 100 +#define SHARED_MEMORY_REREAD_MAXIMUM_ATTEMPTS 100 + +namespace common::sdp +{ + +class SdpClient +{ +public: + /* + * The function opens buffers created in Dataplane in shared memory and fills in the necessary fields in the + * DataPlaneInSharedMemory structure + * Params: + * sdp_data - the Data Plane In Shared Memory object contains data about connection to shared memory buffers + * open_workers_data - if false, only the main file is opened, if true, files with workers counters on + * different numa nodes are also opened + * Returns: result::success if successful, in case of error hresult::error InitSharedMemory + */ + [[nodiscard]] static eResult ReadSharedMemoryData(DataPlaneInSharedMemory& sdp_data, bool open_workers_data) + { + // Read main file + int number_of_attempts = 0; + eResultRead result = eResultRead::need_reread; + while (result != eResultRead::ok) + { + number_of_attempts++; + std::string message_error; + uint64_t size_mmap; + result = ReadItAgainMainFileDataplane(sdp_data, size_mmap, message_error); + if (result == eResultRead::error) + { +#ifdef YANET_USE_POSIX_SHARED_MEMORY + YANET_LOG_ERROR("File %s. %s\n", YANET_SHARED_MEMORY_FILE_DATAPLANE, message_error.c_str()); +#else + YANET_LOG_ERROR("Key %d. %s\n", YANET_SHARED_MEMORY_KEY_DATAPLANE, message_error.c_str()); +#endif + sdp_data.UnmapBuffers(size_mmap); + return eResult::errorInitSharedMemory; + } + else if (result == eResultRead::need_reread) + { + sdp_data.UnmapBuffers(size_mmap); + if (number_of_attempts >= SHARED_MEMORY_REREAD_MAXIMUM_ATTEMPTS) + { +#ifdef YANET_USE_POSIX_SHARED_MEMORY + YANET_LOG_ERROR("File %s. Attempts were made to read: %d. %s\n", + YANET_SHARED_MEMORY_FILE_DATAPLANE, + number_of_attempts, + message_error.c_str()); +#else + YANET_LOG_ERROR("Key %d. Attempts were made to read: %d. %s\n", + YANET_SHARED_MEMORY_KEY_DATAPLANE, + number_of_attempts, + message_error.c_str()); +#endif + return eResult::errorInitSharedMemory; + } +#ifdef YANET_USE_POSIX_SHARED_MEMORY + YANET_LOG_WARNING("File %s. %s\n", YANET_SHARED_MEMORY_FILE_DATAPLANE, message_error.c_str()); +#else + YANET_LOG_WARNING("KEY %d. %s\n", YANET_SHARED_MEMORY_KEY_DATAPLANE, message_error.c_str()); +#endif + std::this_thread::sleep_for(std::chrono::microseconds{SHARED_MEMORY_REREAD_TIMEOUT_MICROSECONDS}); + } + } + + if (!open_workers_data) + { + return eResult::success; + } + + // Read workers files + + // Get all sockets + std::map> sockets_buffer; + for (const auto& iter : sdp_data.workers) + { + sockets_buffer[iter.second.socket] = {nullptr, 0}; + } + for (const auto& iter : sdp_data.workers_gc) + { + sockets_buffer[iter.second.socket] = {nullptr, 0}; + } + + // Open buffers for each socket +#ifndef YANET_USE_POSIX_SHARED_MEMORY + key_t key_shared_memory_segment = YANET_SHARED_MEMORY_KEY_DATAPLANE; +#endif + for (auto& iter : sockets_buffer) + { +#ifdef YANET_USE_POSIX_SHARED_MEMORY + std::string filename = FileNameWorkerOnNumaNode(iter.first); + auto [buffer, size] = common::ipc::SharedMemory::OpenBufferFile(filename, false); + if (buffer == nullptr) + { + YANET_LOG_ERROR("Error openning shared memory buffer from file: %s\n", filename.c_str()); + return eResult::errorInitSharedMemory; + } +#else + key_shared_memory_segment++; + auto [buffer, size] = common::ipc::SharedMemory::OpenBufferKey(key_shared_memory_segment, false); + if (buffer == nullptr) + { + YANET_LOG_ERROR("Error openning shared memory buffer from segment: %d\n", key_shared_memory_segment); + return eResult::errorInitSharedMemory; + } +#endif + iter.second = {buffer, size}; + } + + // Set buffers for workers + for (auto& iter : sdp_data.workers) + { + uint64_t shift = iter.second.shift_in_socket; + auto [buffer, size] = sockets_buffer[iter.second.socket]; + if (shift + sdp_data.metadata_worker.size > size) + { + YANET_LOG_ERROR("Error in file for socket: %d, file size: %ld, worker: %d, metadata_worker.size: %ld, shift: %ld\n", + iter.second.socket, + size, + iter.first, + sdp_data.metadata_worker.size, + shift); + return eResult::errorInitSharedMemory; + } + iter.second.buffer = ShiftBuffer(buffer, shift); + } + for (auto& iter : sdp_data.workers_gc) + { + uint64_t shift = iter.second.shift_in_socket; + auto [buffer, size] = sockets_buffer[iter.second.socket]; + if (shift + sdp_data.metadata_worker_gc.size > size) + { + YANET_LOG_ERROR("Error in file for socket: %d, file size: %ld, worker: %d, metadata_worker_gc.size: %ld, shift: %ld\n", + iter.second.socket, + size, + iter.first, + sdp_data.metadata_worker_gc.size, + shift); + return eResult::errorInitSharedMemory; + } + iter.second.buffer = ShiftBuffer(buffer, shift); + } + + return eResult::success; + } + + /* + * The counter name function gets its value on workers. + * Params: + * - sdp_data - the Data Plane In Shared Memory object contains data about connection to shared memory buffers + * - counter_name - the name of the counter + * - core_id is the id of the core on which the worker is running for which it need to get the counter value, + * if it passed std::nullopt, then it gets from all workers + * Return: The counter value for each core + */ + static std::map GetCounterByName(const DataPlaneInSharedMemory& sdp_data, + const std::string& counter_name, + std::optional core_id) + { + std::map result; + + // Find counter in workers + const auto& iter_workers = sdp_data.metadata_worker.counter_positions.find(counter_name); + if (iter_workers != sdp_data.metadata_worker.counter_positions.end()) + { + uint64_t index = iter_workers->second; + for (const auto& [worker_core_id, worker_info] : sdp_data.workers) + { + if (!core_id.has_value() || worker_core_id == core_id) + { + uint64_t* counters = common::sdp::ShiftBuffer(worker_info.buffer, + sdp_data.metadata_worker.start_counters); + result[worker_core_id] = counters[index]; + } + } + } + + // Find counter in workers_gc + const auto& iter_workers_gc = sdp_data.metadata_worker_gc.counter_positions.find(counter_name); + if (iter_workers_gc != sdp_data.metadata_worker_gc.counter_positions.end()) + { + uint64_t index = iter_workers_gc->second; + for (const auto& [worker_core_id, worker_info] : sdp_data.workers_gc) + { + if (!core_id.has_value() || worker_core_id == core_id) + { + uint64_t* counters = common::sdp::ShiftBuffer(worker_info.buffer, + sdp_data.metadata_worker.start_counters); + result[worker_core_id] = counters[index]; + } + } + } + + return result; + } + + /* + * The function works like the previous one, but it opens buffers in shared memory by itself. In case of + * an opening error, it calls exit(). + */ + static std::map GetCounterByName(const std::string& counter_name, + std::optional core_id) + { + DataPlaneInSharedMemory sdp_data; + if (ReadSharedMemoryData(sdp_data, true) != eResult::success) + { + std::exit(1); + } + return GetCounterByName(sdp_data, counter_name, core_id); + } + + /* + * The function for each counter ID gets the sum of the values for it from all workers + * Params: + * - sdp_data - the Data Plane In Shared Memory object contains data about connection to shared memory buffers + * - counter_ids - counter IDs + * Return: Aggregated counter values + */ + static std::vector GetCounters(const DataPlaneInSharedMemory& sdp_data, + const std::vector& counter_ids) + { + std::vector result(counter_ids.size()); + std::vector buffers; + for (const auto& iter : sdp_data.workers) + { + buffers.push_back(common::sdp::ShiftBuffer(iter.second.buffer, + sdp_data.metadata_worker.start_counters)); + } + + for (size_t i = 0; i < counter_ids.size(); i++) + { + auto counter_id = counter_ids[i]; + if (counter_id >= YANET_CONFIG_COUNTERS_SIZE) + { + continue; + } + + uint64_t counter = 0; + for (const auto& buffer : buffers) + { + counter += buffer[counter_id]; + } + + result[i] = counter; + } + + return result; + } + + /* + * The function works like the previous one, but it opens buffers in shared memory by itself. In case of + * an opening error, it calls exit(). + */ + static std::vector GetCounters(const std::vector& counter_ids) + { + DataPlaneInSharedMemory sdp_data; + if (ReadSharedMemoryData(sdp_data, true) != eResult::success) + { + std::exit(1); + } + return GetCounters(sdp_data, counter_ids); + } + +private: + enum class eResultRead : uint8_t + { + ok, + need_reread, + error + }; + + static eResultRead ReadMainFileDataplane(DataPlaneInSharedMemory& sdp_data, uint64_t& size_mmap, std::string& message) + { + // Try open buffer +#ifdef YANET_USE_POSIX_SHARED_MEMORY + auto [buffer, size] = common::ipc::SharedMemory::OpenBufferFile(YANET_SHARED_MEMORY_FILE_DATAPLANE, false); +#else + auto [buffer, size] = common::ipc::SharedMemory::OpenBufferKey(YANET_SHARED_MEMORY_KEY_DATAPLANE, false); +#endif + size_mmap = size; + if (buffer == nullptr) + { + message = "File opening error"; + return eResultRead::error; + } + sdp_data.dataplane_data = buffer; + + // Compare size of buffer and size header of metadata dataplane + if (size < common::sdp::DataPlaneInSharedMemory::size_header) + { + message = "Size of file " + std::to_string(size) + " < " + + std::to_string(common::sdp::DataPlaneInSharedMemory::size_header) + " size of header"; + return eResultRead::need_reread; + } + + // WORKERS + { + sdp_data.workers.clear(); + sdp_data.workers_gc.clear(); + + uint64_t start_workers = ReadValue(buffer, 0); + uint64_t size_workers = ReadValue(buffer, 1); + if ((start_workers + size_workers > size) || (2 * sizeof(uint64_t) > size_workers)) + { + message = "Bad postion info section WORKERS"; + return eResultRead::need_reread; + } + uint64_t index = start_workers / sizeof(uint64_t); + + uint64_t count_workers = ReadValue(buffer, index++); + uint64_t count_workers_gc = ReadValue(buffer, index++); + if ((2 + 3 * (count_workers + count_workers_gc)) * sizeof(uint64_t) > size_workers) + { + message = "Size of section WORKERS < (2 + 3 * (count_workers + count_workers_gc)) * sizeof(uint64_t)"; + return eResultRead::need_reread; + } + + for (uint64_t index_worker = 0; index_worker < count_workers; index_worker++) + { + uint64_t coreId = ReadValue(buffer, index++); + tSocketId socket = ReadValue(buffer, index++); + uint64_t shift_in_socket = ReadValue(buffer, index++); + sdp_data.workers[coreId] = {socket, shift_in_socket, nullptr}; + } + + for (uint64_t index_worker = 0; index_worker < count_workers_gc; index_worker++) + { + uint64_t coreId = ReadValue(buffer, index++); + tSocketId socket = ReadValue(buffer, index++); + uint64_t shift_in_socket = ReadValue(buffer, index++); + sdp_data.workers_gc[coreId] = {socket, shift_in_socket, nullptr}; + } + } + + // WORKERS_METADATA + { + uint64_t start_workers_metadata = ReadValue(buffer, 2); + uint64_t size_workers_metadata = ReadValue(buffer, 3); + if ((start_workers_metadata + size_workers_metadata > size) || (size_workers_metadata < 128)) + { + message = "Bad postion info section WORKERS_METADATA"; + return eResultRead::need_reread; + } + uint64_t index = start_workers_metadata / sizeof(uint64_t); + + // 0-5 - values from MetadataWorker + sdp_data.metadata_worker.start_counters = ReadValue(buffer, index); + sdp_data.metadata_worker.start_acl_counters = ReadValue(buffer, index + 1); + sdp_data.metadata_worker.start_bursts = ReadValue(buffer, index + 2); + sdp_data.metadata_worker.start_stats = ReadValue(buffer, index + 3); + sdp_data.metadata_worker.start_stats_ports = ReadValue(buffer, index + 4); + sdp_data.metadata_worker.size = ReadValue(buffer, index + 5); + // 6 - n1 = size MetadataWorker.counter_positions + uint64_t n1 = ReadValue(buffer, index + 6); + // 7-9 - значения из MetadataWorker + sdp_data.metadata_worker_gc.start_counters = ReadValue(buffer, index + 7); + sdp_data.metadata_worker_gc.start_stats = ReadValue(buffer, index + 8); + sdp_data.metadata_worker_gc.size = ReadValue(buffer, index + 9); + // 10 - n2 = size MetadataWorker.counter_positions + uint64_t n2 = ReadValue(buffer, index + 10); + + if (128 * (1 + n1 + n2) > size_workers_metadata) + { + message = "Size of section WORKERS_METADATA < 128 * (1 + n1 + n2)"; + return eResultRead::need_reread; + } + + if (!ReadMap(sdp_data.metadata_worker.counter_positions, buffer, start_workers_metadata + 128, n1)) + { + return eResultRead::need_reread; + } + if (!ReadMap(sdp_data.metadata_worker_gc.counter_positions, buffer, start_workers_metadata + 128 * (1 + n1), n2)) + { + return eResultRead::need_reread; + } + } + + // BUS + { + sdp_data.start_bus_section = ReadValue(buffer, 4); + sdp_data.size_bus_section = ReadValue(buffer, 5); + if (sdp_data.start_bus_section + sdp_data.size_bus_section > size) + { + message = "Bad postion info section BUS"; + return eResultRead::need_reread; + } + } + + return eResultRead::ok; + } + + static eResultRead ReadItAgainMainFileDataplane(DataPlaneInSharedMemory& sdp_data, uint64_t& size_mmap, std::string& message) + { + // First read + DataPlaneInSharedMemory tmp_data; + eResultRead result = ReadMainFileDataplane(tmp_data, size_mmap, message); + tmp_data.UnmapBuffers(size_mmap); + if (result != eResultRead::ok) + { + return result; + } + + // Sleep + std::this_thread::sleep_for(std::chrono::microseconds{SHARED_MEMORY_REREAD_TIMEOUT_MICROSECONDS}); + + // Second read + result = ReadMainFileDataplane(sdp_data, size_mmap, message); + if (result != eResultRead::ok) + { + return result; + } + else if (!(sdp_data == tmp_data)) + { + message = "The data changed during the re-reading"; + return eResultRead::need_reread; + } + + return eResultRead::ok; + } + + static uint64_t ReadValue(void* buffer, uint64_t index) + { + uint8_t* data = common::sdp::ShiftBuffer(buffer, index * sizeof(uint64_t)); + uint64_t result = 0; + for (int i = 0; i < 8; i++) + { + result = 256 * result + data[i]; + } + return result; + } + + static bool ReadMap(std::map& values, void* buffer, uint64_t shift, uint64_t count) + { + values.clear(); + for (uint64_t index = 0; index < count; index++) + { + void* current = common::sdp::ShiftBuffer(buffer, shift + 128 * index); + uint64_t value = ReadValue(current, 0); + char* str = common::sdp::ShiftBuffer(current, 8); + if (str[119] != 0) + { + // 119 - index of last symbol + return false; + } + std::string name = std::string(str); + values[name] = value; + } + + return true; + } +}; + +} // namespace common::sdp diff --git a/common/sdpcommon.h b/common/sdpcommon.h new file mode 100644 index 00000000..d3d7900c --- /dev/null +++ b/common/sdpcommon.h @@ -0,0 +1,237 @@ +#pragma once + +#include +#include +#include + +#include "define.h" +#include "idp.h" +#include "shared_memory.h" +#include "stream.h" +#include "type.h" + +// #define YANET_USE_POSIX_SHARED_MEMORY + +#ifdef YANET_USE_POSIX_SHARED_MEMORY + +#define YANET_SHARED_MEMORY_FILE_DATAPLANE "yanet_dataplane.shm" +#define YANET_SHARED_MEMORY_PREFIX_WORKERS "yanet_workers_node_" + +#else + +#define YANET_SHARED_MEMORY_KEY_DATAPLANE 54321 + +#endif + +/* + +The structure of data storage in memory DataPlaneInSharedMemory + +The following files are created to store data in shared memory: +1) The main file with information about workers, metadata, some common counters of the system +2) A separate file is created for each socket (numa node) - it stores the data of the worker counters + +All numeric values are stored as 64-bit numbers in Big Endian + +--------------------------------------- +1 - The main file +The file contains the following sections: +- HEADER +- WORKERS +- WORKERS_METADATA +- BUS + +HEADER - 1024 bytes in size (DataPlaneInSharedMemory::size_header) +Contains the beginning and the size of the remaining sections, 2 numbers each: +- 0,1 - WORKERS +- 2,3 - WORKERS_MET +- 4,5 - BUS + The remaining values are reserved + +WORKERS +Contains the following values: + 0 - n1 = number of workers + 1 - n2 = number of worker_gc + The following contains n1 + n2 triples of numbers: + n - core_id + n+1 - socket + n+2 - shift in socket + +WORKERS_METADATA + At the beginning, 11 64-bit numbers are written: + 0-5 - values from MetadataWorker + 6 - n1 = size MetadataWorker.counter_positions + 7-9 - values from MetadataWorker + 10 - n2 = size MetadataWorker.counter_positions + + Starting from 128 bytes, there are n1+n2 entries from counter_positions, each entry occupies 128 bytes: + The first 8 bytes are the value from the map + The remaining 120 bytes are a string (key), ending with a null byte + +BUS +Contains a buffer used by cBus counters + +--------------------------------------- +2 - Socket data file +The file consists of several blocks, each block corresponds to a worker or worker_gc. + +Block for worker + The block size is equal to MetadataWorker::size. + This block is divided into 5 blocks - counters, acl_counters, bursts, stats, stats_port. + To determine the beginning of a block, for example, stats: + DataPlaneInSharedMemory::workers_info[core_id].shift_in_socket + MetadataWorker::start_stats + +Block for worker_gc + The block size is equal to MetadataWorkerGc::size. + This block is divided into 2 blocks - counters, stats. + +*/ + +namespace common::sdp +{ + +#ifdef YANET_USE_POSIX_SHARED_MEMORY +inline std::string FileNameWorkerOnNumaNode(tSocketId socket_id) +{ + return YANET_SHARED_MEMORY_PREFIX_WORKERS + std::to_string(socket_id) + ".shm"; +} +#endif + +template +inline TResult ShiftBuffer(TBuffer buffer, uint64_t size) +{ + return reinterpret_cast((reinterpret_cast(buffer) + size)); +} + +template +bool MapsEqual(const std::map& left, const std::map& right) +{ + if (left.size() != right.size()) + { + return false; + } + + auto [stop_left, stop_right] = std::mismatch(left.begin(), left.end(), right.begin(), right.end()); + + return (stop_left == left.end()) && (stop_right == right.end()); +} + +struct MetadataWorker +{ + uint64_t start_counters; + uint64_t start_acl_counters; + uint64_t start_bursts; + uint64_t start_stats; + uint64_t start_stats_ports; + uint64_t size; + + std::map counter_positions; + + bool operator==(const MetadataWorker& other) const + { + return other.start_counters == start_counters && + other.start_acl_counters == start_acl_counters && + other.start_bursts == start_bursts && + other.start_stats == start_stats && + other.start_stats_ports == start_stats_ports && + other.size == size && + MapsEqual(other.counter_positions, counter_positions); + } +}; + +struct MetadataWorkerGc +{ + uint64_t start_counters; + uint64_t start_stats; + uint64_t size; + + std::map counter_positions; + + bool operator==(const MetadataWorkerGc& other) const + { + return other.start_counters == start_counters && + other.start_stats == start_stats && + other.size == size && + MapsEqual(other.counter_positions, counter_positions); + } +}; + +struct WorkerInSharedMemory +{ + tSocketId socket; + uint64_t shift_in_socket; + void* buffer; + + bool operator==(const WorkerInSharedMemory& other) const + { + return other.socket == socket && + other.shift_in_socket == shift_in_socket; + } +}; + +struct DataPlaneInSharedMemory +{ + static constexpr uint64_t size_header = 1024; + + using workers_info = std::map; + + workers_info workers; + workers_info workers_gc; + + MetadataWorker metadata_worker; + MetadataWorkerGc metadata_worker_gc; + + uint64_t size_workers_section; + uint64_t size_workers_metadata_section; + uint64_t size_bus_section; + + uint64_t size_dataplane_buffer; + void* dataplane_data = nullptr; + uint64_t start_bus_section; + + void UnmapBuffers(uint64_t size) + { + if (dataplane_data != nullptr) + { + if (munmap(dataplane_data, size) < 0) + { + YANET_LOG_ERROR("Error munmap %d: %s", errno, strerror(errno)); + } + dataplane_data = nullptr; + } + } + + bool operator==(const DataPlaneInSharedMemory& other) const + { + return other.metadata_worker == metadata_worker && + other.metadata_worker_gc == metadata_worker_gc && + other.start_bus_section == start_bus_section && + MapsEqual(other.workers, workers) && + MapsEqual(other.workers_gc, workers_gc); + } + + void FillSizes() + { + size_workers_section = Allign64((2 + 3 * (workers.size() + workers_gc.size())) * sizeof(uint64_t)); + size_workers_metadata_section = 128 * (1 + metadata_worker.counter_positions.size() + metadata_worker_gc.counter_positions.size()); + size_bus_section = Allign64(size_bus_section); + size_dataplane_buffer = size_header + size_workers_section + size_workers_metadata_section + size_bus_section; + } + + static uint64_t Allign64(uint64_t value) + { + return ((value + 63) / 64) * 64; + } + + std::tuple BuffersBus() const + { + uint32_t count_errors = static_cast(common::idp::errorType::size); + uint32_t count_requests = static_cast(common::idp::requestType::size); + uint64_t* requests = common::sdp::ShiftBuffer(dataplane_data, start_bus_section); + uint64_t* errors = common::sdp::ShiftBuffer(dataplane_data, start_bus_section + count_requests * sizeof(uint64_t)); + uint64_t* durations = common::sdp::ShiftBuffer(dataplane_data, start_bus_section + (count_requests + count_errors) * sizeof(uint64_t)); + return {requests, errors, durations}; + } +}; + +} // namespace common::sdp diff --git a/common/shared_memory.h b/common/shared_memory.h new file mode 100644 index 00000000..0d118e1c --- /dev/null +++ b/common/shared_memory.h @@ -0,0 +1,342 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "define.h" +#include "type.h" + +namespace common::ipc +{ + +class SharedMemory +{ +public: + static constexpr int mode_create = 0644; + + /* + * Check if HugeTLB Pages usage is available + * Searches for a string of the type "Hugetlb: zzz kB" in the /proc/meminfo and returns true + * if the parameter value is not 0 + * Some details in the Linux kernel source file Documentation/admin-guide/mm/hugetlbpage.rst + */ + static bool HugeTlbEnabled() + { + const char* path_meminfo = "/proc/meminfo"; + const char* str_hugetlb = "Hugetlb:"; + + FILE* fd = fopen(path_meminfo, "r"); + if (fd == NULL) + { + YANET_LOG_ERROR("Cannot open %s, error %d: %s\n", path_meminfo, errno, strerror(errno)); + return false; + } + + bool hugetlb_enabled = false; + bool line_found = false; + unsigned hugetlb_len = sizeof(str_hugetlb); + char buffer[256]; + while (fgets(buffer, sizeof(buffer), fd)) + { + if (strncmp(buffer, str_hugetlb, hugetlb_len) == 0) + { + char* str = &buffer[hugetlb_len]; + while (isspace((int)*str)) + { + str++; + } + char* endptr; + unsigned long long size = strtoull(str, &endptr, 0); + // The string still contains kB (or mB, gB), but it only matters to us + // whether the value is 0 or not + if (errno != 0) + { + YANET_LOG_ERROR("Error parsing size of %s in file %s\n", str_hugetlb, path_meminfo); + return false; + } + hugetlb_enabled = (size != 0); + line_found = true; + break; + } + } + fclose(fd); + + if (!line_found) + { + YANET_LOG_WARNING("Not found string '%s' in file: %s\n", str_hugetlb, path_meminfo); + } + + return hugetlb_enabled; + } + + /* + * Creating a buffer in shared memory (POSIX shared memory) + * Params: + * - filename - the name of the file without a path, the file is created in /dev/shm + * - size - buffer size + * - use_huge_tlb - if true, it will use MAP_HUGETLB + * - socket_id - id of the numa node on which one want to allocate a buffer, + * if std::nullptr - it will be selected automatically by the system + * Return value: + * void* - address of the allocated buffer, nullptr if an error occurred + */ + static void* CreateBufferFile(std::string filename, size_t size, bool use_huge_tlb, std::optional socket_id) + { + // Open or creare shared memory file + int flags_open = O_RDWR | O_CREAT; + int fd = shm_open(filename.c_str(), flags_open, mode_create); + if (fd == -1) + { + YANET_LOG_ERROR("shm_open(%s, %d, %o): %s\n", filename.c_str(), flags_open, mode_create, strerror(errno)); + return nullptr; + } + + // Truncate - set file size + int res_trunc = ftruncate(fd, size); + if (res_trunc < 0) + { + YANET_LOG_ERROR("filename=%s, ftruncate(%d, %lu): %s\n", filename.c_str(), fd, size, strerror(errno)); + close(fd); + return nullptr; + } + + // Set memory policy if necessary + auto [oldmask, oldpolicy] = SetMemoryPolicy(socket_id); + + // Mmap memory + int prot = PROT_READ | PROT_WRITE; + int flags_mmap = GetFlags(MAP_SHARED, use_huge_tlb, MAP_HUGETLB); + void* addr = mmap(nullptr, size, prot, flags_mmap, fd, 0); + if (addr == MAP_FAILED) + { + // The error occurs when trying to use HugeTlb when this feature is not enabled in the kernel + YANET_LOG_ERROR("filename=%s, mmap(%p, %lu, %d, %d, %d, 0)\n", filename.c_str(), nullptr, size, prot, flags_mmap, fd); + return nullptr; + } + + // Zero memory + memset(addr, 0, size); + + // Restore memory policy if necessary + RestoreMemoryPolicy(socket_id, oldmask, oldpolicy); + + // Close file + if (close(fd) != 0) + { + YANET_LOG_ERROR("filename=%s, error fclose %d: %s\n", filename.c_str(), errno, strerror(errno)); + } + + return addr; + } + + /* + * Creating a buffer in shared memory (System V shared memory) + * Params: + * - key - the identifier of segment + * - size - buffer size + * - use_huge_tlb - if true, it will use MAP_HUGETLB + * - socket_id - id of the numa node on which one want to allocate a buffer, + * if std::nullptr - it will be selected automatically by the system + * Return value: + * void* - address of the allocated buffer, nullptr if an error occurred + */ + static void* CreateBufferKey(key_t key, size_t size, bool use_huge_tlb, std::optional socket_id) + { + // Delete old segment + int shmid = shmget(key, 0, 0); + if ((shmid != -1) && (shmctl(shmid, IPC_RMID, nullptr) < 0)) + { + YANET_LOG_ERROR("key = %d, shmctl(%d, IPC_RMID, nullptr): %s\n", key, shmid, strerror(errno)); + return nullptr; + } + + // Creare shared memory segment + int flags = GetFlags(IPC_CREAT | mode_create, use_huge_tlb, SHM_HUGETLB); + shmid = shmget(key, size, flags); + if (shmid == -1) + { + YANET_LOG_ERROR("shmget(%d, %lu, %d): %s\n", key, size, flags, strerror(errno)); + return nullptr; + } + + // Set memory policy if necessary + auto [oldmask, oldpolicy] = SetMemoryPolicy(socket_id); + + // Mmap memory + void* addr = shmat(shmid, nullptr, 0); + if (addr == (void*)-1) + { + YANET_LOG_ERROR("shmat(%d, %p, %d): %s\n", shmid, nullptr, 0, strerror(errno)); + return nullptr; + } + + // Zero memory + memset(addr, 0, size); + + // Restore memory policy if necessary + RestoreMemoryPolicy(socket_id, oldmask, oldpolicy); + + return addr; + } + + /* + * Open an existing buffer in shared memory (POSIX shared memory) + * Params: + * - filename - the name of the file without a path, the file is created in /dev/shm + * - use_huge_tlb - if true, it will use MAP_HUGETLB + * Return values: + * - void* - address of the allocated buffer, nullptr if an error occurred + * - size - buffer size + */ + static std::pair OpenBufferFile(std::string filename, bool use_huge_tlb) + { + // Open shared memory file + int flags_open = O_RDONLY; + int fd = shm_open(filename.c_str(), flags_open, mode_create); + if (fd == -1) + { + YANET_LOG_ERROR("shm_open(%s, %d, %o): %s\n", filename.c_str(), flags_open, mode_create, strerror(errno)); + return {nullptr, 0}; + } + + // Get the size of file + struct stat buffer; + int status = fstat(fd, &buffer); + if (status != 0) + { + YANET_LOG_ERROR("filename=%s, fstat(%d, &buffer): %s\n", filename.c_str(), fd, strerror(errno)); + close(fd); + return {nullptr, 0}; + } + size_t size = buffer.st_size; + + // Mmap memory + int prot = PROT_READ; + int flags_mmap = GetFlags(MAP_SHARED, use_huge_tlb, MAP_HUGETLB); + void* addr = mmap(nullptr, size, prot, flags_mmap, fd, 0); + if (addr == MAP_FAILED) + { + YANET_LOG_ERROR("filename=%s, mmap(%p, %lu, %d, %d, %d, 0)\n", filename.c_str(), nullptr, size, prot, flags_mmap, fd); + close(fd); + return {nullptr, 0}; + } + + // Close file + if (close(fd) != 0) + { + YANET_LOG_ERROR("filename=%s, error fclose %d: %s\n", filename.c_str(), errno, strerror(errno)); + } + + return {addr, size}; + } + + /* + * Open an existing buffer in shared memory (System V shared memory) + * Params: + * - key - the identifier of segment + * - use_huge_tlb - if true, it will use MAP_HUGETLB + * Return values: + * - void* - address of the allocated buffer, nullptr if an error occurred + * - size - buffer size + */ + static std::pair OpenBufferKey(key_t key, bool use_huge_tlb) + { + // Open shared memory segment + int flags = GetFlags(0, use_huge_tlb, SHM_HUGETLB); + int shmid = shmget(key, 0, flags); + if (shmid == -1) + { + YANET_LOG_ERROR("shmget(%d, %d, %d): %s\n", key, 0, flags, strerror(errno)); + return {nullptr, 0}; + } + + // Get the size of segment + struct shmid_ds buf; + if (shmctl(shmid, IPC_STAT, &buf) == -1) + { + YANET_LOG_ERROR("key=%d, shmctl(%d, IPC_STAT, &buf): %s\n", key, shmid, strerror(errno)); + return {nullptr, 0}; + } + size_t size = buf.shm_segsz; + + // Mmap memory + int shmflg = SHM_RDONLY; + auto addr = shmat(shmid, nullptr, shmflg); + if (addr == (void*)-1) + { + YANET_LOG_ERROR("key=%d, shmat(%d, %p, %d) = -1\n", key, shmid, nullptr, shmflg); + return {nullptr, 0}; + } + + return {addr, size}; + } + +private: + static std::pair SetMemoryPolicy(std::optional socket_id) + { + struct bitmask* oldmask = nullptr; + int oldpolicy; + if (socket_id.has_value()) + { + oldmask = numa_allocate_nodemask(); + if (get_mempolicy(&oldpolicy, oldmask->maskp, oldmask->size + 1, 0, 0) < 0) + { + YANET_LOG_WARNING("get_mempolicy(): %s, continue with the use of sockets turned off\n", strerror(errno)); + oldpolicy = MPOL_DEFAULT; + socket_id = std::nullopt; + } + else + { + numa_set_preferred(*socket_id); + if (errno != 0) + { + YANET_LOG_ERROR("numa_set_preferred(%d): %s\n", *socket_id, strerror(errno)); + } + } + } + return {oldmask, oldpolicy}; + } + + static void RestoreMemoryPolicy(std::optional socket_id, struct bitmask* oldmask, int oldpolicy) + { + if (socket_id.has_value()) + { + if (oldpolicy == MPOL_DEFAULT) + { + numa_set_localalloc(); + } + else if (set_mempolicy(oldpolicy, oldmask->maskp, oldmask->size + 1) < 0) + { + YANET_LOG_ERROR("set_mempolicy(): %s\n", strerror(errno)); + numa_set_localalloc(); + } + numa_free_cpumask(oldmask); + } + } + + static int GetFlags(int start_value, bool use_huge_tlb, int flag_of_huge_tlb) + { + int flags = start_value; + if (use_huge_tlb) + { + if (!HugeTlbEnabled()) + { + YANET_LOG_ERROR("Attempt to use HugeTlb, but it is not enabled\n"); + } + else + { + flags |= flag_of_huge_tlb; + } + } + return flags; + } +}; + +} // namespace common::ipc diff --git a/common/unittest/meson.build b/common/unittest/meson.build index f3cd3852..53458d48 100644 --- a/common/unittest/meson.build +++ b/common/unittest/meson.build @@ -1,11 +1,14 @@ dependencies = [] +dependencies += libjson.get_variable('nlohmann_json_dep') dependencies += dependency('threads') dependencies += dependency('gtest') dependencies += dependency('gtest_main') common_sources = files() -sources = files('static_vector.cpp', +sources = files('unittest.cpp', + 'static_vector.cpp', + 'shared_memory.cpp', ) arch = 'corei7' diff --git a/common/unittest/shared_memory.cpp b/common/unittest/shared_memory.cpp new file mode 100644 index 00000000..67e7c971 --- /dev/null +++ b/common/unittest/shared_memory.cpp @@ -0,0 +1,53 @@ +#include + +#include "../shared_memory.h" + +void TestForSize(void* buffer_writer, void* buffer_reader, size_t size, size_t size_reader) +{ + ASSERT_TRUE(buffer_writer != nullptr); + ASSERT_TRUE(buffer_reader != nullptr); + ASSERT_EQ(size, size_reader); + + uint8_t* buffer_writer8 = reinterpret_cast(buffer_writer); + uint8_t* buffer_reader8 = reinterpret_cast(buffer_reader); + + for (uint64_t index = 0; index < size; index++) + { + buffer_writer8[index] = (index & 0xff); + } + + for (uint64_t index = 0; index < size; index++) + { + ASSERT_EQ(buffer_writer8[index], buffer_reader8[index]); + } +} + +static std::vector sizes_test = {1024, 512, 4096, 8192, 4096, 1024}; + +TEST(SharedMemory, CreateAndOpenSharedMemoryBufferFile) +{ + bool use_huge_tlb = common::ipc::SharedMemory::HugeTlbEnabled(); + std::string filename("test_shared_memory.shm"); + for (size_t size : sizes_test) + { + void* buffer_writer = common::ipc::SharedMemory::CreateBufferFile(filename, size, use_huge_tlb, 0); + auto [buffer_reader, size_reader] = common::ipc::SharedMemory::OpenBufferFile(filename, use_huge_tlb); + TestForSize(buffer_writer, buffer_reader, size, size_reader); + ASSERT_EQ(munmap(buffer_writer, size), 0); + ASSERT_EQ(munmap(buffer_reader, size), 0); + } +} + +TEST(SharedMemory, CreateAndOpenSharedMemoryBufferKey) +{ + bool use_huge_tlb = common::ipc::SharedMemory::HugeTlbEnabled(); + key_t key = 54321; + for (size_t size : sizes_test) + { + void* buffer_writer = common::ipc::SharedMemory::CreateBufferKey(key, size, use_huge_tlb, 0); + auto [buffer_reader, size_reader] = common::ipc::SharedMemory::OpenBufferKey(key, use_huge_tlb); + TestForSize(buffer_writer, buffer_reader, size, size_reader); + ASSERT_EQ(shmdt(buffer_writer), 0); + ASSERT_EQ(shmdt(buffer_reader), 0); + } +} diff --git a/common/unittest/unittest.cpp b/common/unittest/unittest.cpp new file mode 100644 index 00000000..9cfa1ba3 --- /dev/null +++ b/common/unittest/unittest.cpp @@ -0,0 +1,3 @@ +#include "common/define.h" + +common::log::LogPriority common::log::logPriority = common::log::TLOG_DEBUG; diff --git a/controlplane/controlplane.cpp b/controlplane/controlplane.cpp index 2b2b8b83..b51b43f6 100644 --- a/controlplane/controlplane.cpp +++ b/controlplane/controlplane.cpp @@ -42,6 +42,13 @@ eResult cControlPlane::init(const std::string& jsonFilePath) sockets.emplace(std::get<1>(iter.second)); ///< @todo } + result = common::sdp::SdpClient::ReadSharedMemoryData(sdp_data, true); + if (result != eResult::success) + { + return result; + } + counter_manager.init(&sdp_data); + modules.emplace_back(new telegraf_t); ///< @todo modules.emplace_back(new rib_t); ///< @todo modules.emplace_back(new controlplane::module::bus); ///< @todo @@ -264,6 +271,11 @@ eResult cControlPlane::getPhysicalPortName(const tPortId& portId, return eResult::invalidPortId; } +const common::sdp::DataPlaneInSharedMemory* cControlPlane::getSdpData() const +{ + return &sdp_data; +} + common::icp::getPhysicalPorts::response cControlPlane::getPhysicalPorts() const { common::icp::getPhysicalPorts::response response; @@ -613,7 +625,7 @@ common::icp::getFwList::response cControlPlane::command_getFwList(const common:: if (rules_type == common::icp::getFwList::requestType::static_rules_original || rules_type == common::icp::getFwList::requestType::static_rules_generated) { - auto counters = dataPlane.getAclCounters(); + auto counters = getAclCounters(); auto current_guard = generations.current_lock_guard(); const auto& current = generations.current(); const auto need_orig = (rules_type == common::icp::getFwList::requestType::static_rules_original); @@ -877,7 +889,7 @@ eResult cControlPlane::loadConfig(const std::string& rootFilePath, { { std::unique_lock aclCountersDelta_lock(aclCountersDelta_mutex); - aclCountersDelta = dataPlane.getAclCounters(); + aclCountersDelta = getAclCounters(); } generations.next_lock(); @@ -988,3 +1000,20 @@ void cControlPlane::register_service(google::protobuf::Service* service) { services[service->GetDescriptor()->name()] = service; } + +std::vector cControlPlane::getAclCounters() +{ + std::vector response(YANET_CONFIG_ACL_COUNTERS_SIZE); + + uint64_t start_acl_counters = sdp_data.metadata_worker.start_acl_counters; + for (const auto& iter : sdp_data.workers) + { + uint64_t* aclCounters = common::sdp::ShiftBuffer(iter.second.buffer, start_acl_counters); + for (size_t i = 0; i < YANET_CONFIG_ACL_COUNTERS_SIZE; i++) + { + response[i] += aclCounters[i]; + } + } + + return response; +} diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index cfcf82f7..9ff14ab5 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -16,6 +16,7 @@ #include "common/idataplane.h" #include "common/idp.h" #include "common/result.h" +#include "common/sdpclient.h" #include "libprotobuf/controlplane.pb.h" #include "balancer.h" @@ -100,6 +101,8 @@ class cControlPlane } } + const common::sdp::DataPlaneInSharedMemory* getSdpData() const; + protected: /** commands */ common::icp::getPhysicalPorts::response getPhysicalPorts() const; common::icp::getLogicalPorts::response getLogicalPorts() const; @@ -197,6 +200,8 @@ class cControlPlane private: /// used only in loadConfig() controlplane::base_t base; + common::sdp::DataPlaneInSharedMemory sdp_data; void register_service(google::protobuf::Service* service); + std::vector getAclCounters(); }; diff --git a/controlplane/counter.h b/controlplane/counter.h index 63f4e1a3..c961ab99 100644 --- a/controlplane/counter.h +++ b/controlplane/counter.h @@ -9,6 +9,7 @@ #include "common/icp.h" #include "common/idataplane.h" #include "common/refarray.h" +#include "common/sdpclient.h" class counter_manager_t { @@ -20,6 +21,11 @@ class counter_manager_t { } + void init(const common::sdp::DataPlaneInSharedMemory* sdp_data) + { + this->sdp_data = sdp_data; + } + std::tuple stats() const { std::lock_guard guard(counter_mutex); @@ -65,7 +71,7 @@ class counter_manager_t { /// @todo: check counter_ids are reserved - const auto getCountersResponse = counter_dataplane.getCounters(counter_ids); + const auto getCountersResponse = common::sdp::SdpClient::GetCounters(*sdp_data, counter_ids); std::lock_guard guard(counter_mutex); for (unsigned int i = 0; @@ -82,7 +88,7 @@ class counter_manager_t { std::vector result(counter_ids.size()); - const auto getCountersResponse = counter_dataplane.getCounters(counter_ids); + const auto getCountersResponse = common::sdp::SdpClient::GetCounters(*sdp_data, counter_ids); std::lock_guard guard(counter_mutex); for (unsigned int i = 0; @@ -108,9 +114,9 @@ class counter_manager_t static constexpr uint32_t max_buffer_size = 64; mutable std::mutex counter_mutex; - interface::dataPlane counter_dataplane; std::vector counter_shifts; SegmentAllocator allocator; + const common::sdp::DataPlaneInSharedMemory* sdp_data; }; template> currWorkers; + const common::sdp::DataPlaneInSharedMemory* sdp_data = controlPlane->getSdpData(); + for (const auto& [coreId, worker_info] : sdp_data->workers) + { + std::array bursts; + uint64_t* worker_bursts = + common::sdp::ShiftBuffer(worker_info.buffer, sdp_data->metadata_worker.start_bursts); + memcpy(&bursts[0], worker_bursts, sizeof(uint64_t) * (CONFIG_YADECAP_MBUFS_BURST_SIZE + 1)); + currWorkers[coreId] = bursts; + } - const auto getOtherStatsResponse = dataPlane.getOtherStats(); const auto portsStatsExtended = dataPlane.get_ports_stats_extended(); // - const auto& [currWorkers] = getOtherStatsResponse; - common::icp::telegraf_other::response response; auto& [response_flagFirst, response_workers, response_ports] = response; @@ -323,8 +329,7 @@ common::icp::telegraf_other::response telegraf_t::telegraf_other() { for (const auto& [coreId, workerStats] : currWorkers) { - response_workers[coreId] = {calcUsage(std::get<0>(workerStats), - std::get<0>(prevWorkers[coreId]))}; + response_workers[coreId] = {calcUsage(workerStats, prevWorkers[coreId])}; } } else diff --git a/controlplane/telegraf.h b/controlplane/telegraf.h index b432bf2f..926f3570 100644 --- a/controlplane/telegraf.h +++ b/controlplane/telegraf.h @@ -88,7 +88,7 @@ class telegraf_t : public module_t bool flagFirst; - std::map prevWorkers; + std::map> prevWorkers; std::map, std::array> route_tunnel_peer_counters; ///< @todo: gc std::map> dregress_traffic_counters_prev; diff --git a/dataplane/bus.cpp b/dataplane/bus.cpp index 4b880b77..95a81a03 100644 --- a/dataplane/bus.cpp +++ b/dataplane/bus.cpp @@ -55,6 +55,21 @@ void cBus::join() } } +uint64_t cBus::GetSizeForCounters() +{ + uint32_t count_errors = static_cast(common::idp::errorType::size); + uint32_t count_requests = static_cast(common::idp::requestType::size); + return (count_errors + 2 * count_requests) * sizeof(uint64_t); +} + +void cBus::SetBufferForCounters(const common::sdp::DataPlaneInSharedMemory& sdp_data) +{ + auto [requests, errors, durations] = sdp_data.BuffersBus(); + stats.requests = requests; + stats.errors = errors; + stats.durations = durations; +} + static bool recvAll(int clientSocket, char* buffer, uint64_t size) @@ -254,14 +269,6 @@ void cBus::clientThread(int clientSocket) { response = callWithResponse(&cControlPlane::clearFWState, request); } - else if (type == common::idp::requestType::getCounters) - { - response = callWithResponse(&cControlPlane::getCounters, request); - } - else if (type == common::idp::requestType::getOtherStats) - { - response = callWithResponse(&cControlPlane::getOtherStats, request); - } else if (type == common::idp::requestType::getConfig) { response = callWithResponse(&cControlPlane::getConfig, request); @@ -286,10 +293,6 @@ void cBus::clientThread(int clientSocket) { response = callWithResponse(&cControlPlane::limits, request); } - else if (type == common::idp::requestType::getAclCounters) - { - response = callWithResponse(&cControlPlane::getAclCounters, request); - } else if (type == common::idp::requestType::balancer_connection) { response = callWithResponse(&cControlPlane::balancer_connection, request); @@ -322,10 +325,6 @@ void cBus::clientThread(int clientSocket) { response = callWithResponse(&cControlPlane::version, request); } - else if (type == common::idp::requestType::get_counter_by_name) - { - response = callWithResponse(&cControlPlane::get_counter_by_name, request); - } else if (type == common::idp::requestType::nat64stateful_state) { response = callWithResponse(&cControlPlane::nat64stateful_state, request); @@ -406,6 +405,8 @@ void cBus::clientThread(int clientSocket) std::chrono::duration duration = std::chrono::system_clock::now() - startTime; + // The duration time is measured in milliseconds + stats.durations[(uint32_t)type] += static_cast(1000 * duration.count()); YANET_LOG_DEBUG("request type %d processed - %.3f sec\n", (int)type, duration.count()); diff --git a/dataplane/bus.h b/dataplane/bus.h index c52607e3..1a43f223 100644 --- a/dataplane/bus.h +++ b/dataplane/bus.h @@ -12,6 +12,7 @@ #include "common/idp.h" #include "common/result.h" +#include "sdpserver.h" #include "type.h" class cBus @@ -24,6 +25,9 @@ class cBus void stop(); void join(); + static uint64_t GetSizeForCounters(); + void SetBufferForCounters(const common::sdp::DataPlaneInSharedMemory& sdp_data); + protected: void mainLoop(); void clientThread(int clientSocket); @@ -67,13 +71,9 @@ class cBus struct sStats { - sStats() - { - memset(this, 0, sizeof(*this)); - } - - uint64_t requests[(uint32_t)common::idp::requestType::size]; - uint64_t errors[(uint32_t)common::idp::errorType::size]; + uint64_t* requests; // common::idp::requestType::size + uint64_t* errors; // common::idp::errorType::size + uint64_t* durations; // common::idp::requestType::size } stats; cDataPlane* dataPlane; diff --git a/dataplane/controlplane.cpp b/dataplane/controlplane.cpp index 72171e78..525bfa4f 100644 --- a/dataplane/controlplane.cpp +++ b/dataplane/controlplane.cpp @@ -176,25 +176,6 @@ common::idp::getGlobalBase::response cControlPlane::getGlobalBase(const common:: return response; } -common::idp::getOtherStats::response cControlPlane::getOtherStats() -{ - common::idp::getOtherStats::response response; - auto& [response_workers] = response; - - /// workers - { - for (const cWorker* worker : dataPlane->workers_vector) - { - std::array bursts; - memcpy(&bursts[0], worker->bursts, sizeof(worker->bursts)); - - response_workers[worker->coreId] = {bursts}; - } - } - - return response; -} - common::idp::getWorkerStats::response cControlPlane::getWorkerStats(const common::idp::getWorkerStats::request& request) { /// unsafe @@ -209,7 +190,7 @@ common::idp::getWorkerStats::response cControlPlane::getWorkerStats(const common } response[coreId] = {worker->iteration, - worker->stats, + *worker->stats, portsStats}; }; @@ -325,7 +306,7 @@ common::idp::get_worker_gc_stats::response cControlPlane::get_worker_gc_stats() for (const auto& [core_id, worker] : dataPlane->worker_gcs) { response[core_id] = {worker->iteration, - worker->stats}; + *worker->stats}; } return response; @@ -572,24 +553,6 @@ eResult cControlPlane::clearFWState() return common::result_e::success; } -common::idp::getAclCounters::response cControlPlane::getAclCounters() -{ - std::lock_guard guard(mutex); - - common::idp::getAclCounters::response response; - - response.resize(YANET_CONFIG_ACL_COUNTERS_SIZE); - for (const cWorker* worker : dataPlane->workers_vector) - { - for (size_t i = 0; i < YANET_CONFIG_ACL_COUNTERS_SIZE; i++) - { - response[i] += worker->aclCounters[i]; - } - } - - return response; -} - common::idp::getPortStatsEx::response cControlPlane::getPortStatsEx() { common::idp::getPortStatsEx::response response; @@ -625,33 +588,6 @@ common::idp::getPortStatsEx::response cControlPlane::getPortStatsEx() return response; } -common::idp::getCounters::response cControlPlane::getCounters(const common::idp::getCounters::request& request) -{ - common::idp::getCounters::response response; - response.resize(request.size()); - - for (size_t i = 0; - i < request.size(); - i++) - { - const auto& counter_id = request[i]; - - if (counter_id >= YANET_CONFIG_COUNTERS_SIZE) - { - std::lock_guard guard(mutex); - ++errors["getCounters: invalid counterId"]; - continue; - } - - response[i] = accumulateWorkerStats( - [counter_id](cWorker* worker) { - return worker->counters[counter_id]; - }); - } - - return response; -} - common::idp::getConfig::response cControlPlane::getConfig() const { common::idp::getConfig::response response; @@ -1092,47 +1028,6 @@ common::idp::version::response cControlPlane::version() version_custom()}; } -common::idp::get_counter_by_name::response cControlPlane::get_counter_by_name(const common::idp::get_counter_by_name::request& request) -{ - common::idp::get_counter_by_name::response response; - - const auto& [counter_name, optional_core_id] = request; - - if (optional_core_id.has_value()) - { - std::optional counter_val = dataPlane->getCounterValueByName(counter_name, optional_core_id.value()); - if (counter_val.has_value()) - { - response[optional_core_id.value()] = counter_val.value(); - } - - // if counter with provided name does not exist, empty map will be returned, and its emptiness should be checked on another end - return response; - } - - // core_id was not specified, return counter for each core_id - for (const cWorker* worker : dataPlane->workers_vector) - { - std::optional counter_val = dataPlane->getCounterValueByName(counter_name, worker->coreId); - if (counter_val.has_value()) - { - response[worker->coreId] = counter_val.value(); - } - } - - for (const auto& [core_id, worker_gc] : dataPlane->worker_gcs) - { - (void)worker_gc; - std::optional counter_val = dataPlane->getCounterValueByName(counter_name, core_id); - if (counter_val.has_value()) - { - response[core_id] = counter_val.value(); - } - } - - return response; -} - common::idp::get_shm_info::response cControlPlane::get_shm_info() { common::idp::get_shm_info::response response; diff --git a/dataplane/controlplane.h b/dataplane/controlplane.h index b8cd44b0..182aa590 100644 --- a/dataplane/controlplane.h +++ b/dataplane/controlplane.h @@ -67,9 +67,6 @@ class cControlPlane ///< @todo: move to cDataPlane common::idp::getFWState::response getFWState(); common::idp::getFWStateStats::response getFWStateStats(); eResult clearFWState(); - common::idp::getAclCounters::response getAclCounters(); - common::idp::getCounters::response getCounters(const common::idp::getCounters::request& request); - common::idp::getOtherStats::response getOtherStats(); common::idp::getConfig::response getConfig() const; common::idp::getErrors::response getErrors(); common::idp::getReport::response getReport(); @@ -84,7 +81,6 @@ class cControlPlane ///< @todo: move to cDataPlane eResult unrdup_vip_to_balancers(const common::idp::unrdup_vip_to_balancers::request& request); eResult update_vip_vport_proto(const common::idp::update_vip_vport_proto::request& request); common::idp::version::response version(); - common::idp::get_counter_by_name::response get_counter_by_name(const common::idp::get_counter_by_name::request& request); common::idp::nat64stateful_state::response nat64stateful_state(const common::idp::nat64stateful_state::request& request); common::idp::get_shm_info::response get_shm_info(); common::idp::get_shm_tsc_info::response get_shm_tsc_info(); diff --git a/dataplane/dataplane.cpp b/dataplane/dataplane.cpp index 037aa28a..b443d3e7 100644 --- a/dataplane/dataplane.cpp +++ b/dataplane/dataplane.cpp @@ -164,6 +164,12 @@ eResult cDataPlane::init(const std::string& binaryPath, socket_cplane_mempools.emplace(socket, pool); } + result = initSharedMemory(); + if (result != eResult::success) + { + return result; + } + result = initWorkers(); if (result != eResult::success) { @@ -246,6 +252,7 @@ eResult cDataPlane::init(const std::string& binaryPath, { return result; } + bus.SetBufferForCounters(sdp_data); result = neighbor.init(this); if (result != eResult::success) @@ -853,6 +860,8 @@ eResult cDataPlane::initWorkers() return eResult::errorAllocatingMemory; } + worker->SetBufferForCounters(sdp_data.workers[coreId].buffer, sdp_data.metadata_worker); + dataplane::base::permanently basePermanently; { auto iter = globalBaseAtomics.find(socket_id); @@ -985,7 +994,6 @@ eResult cDataPlane::initWorkers() return result; } - worker->fillStatsNamesToAddrsTable(coreId_to_stats_tables[coreId]); workers[coreId] = worker; workers_vector.emplace_back(worker); @@ -1025,6 +1033,8 @@ eResult cDataPlane::initWorkers() return eResult::errorAllocatingMemory; } + worker->SetBufferForCounters(sdp_data.workers_gc[core_id].buffer, sdp_data.metadata_worker_gc); + dataplane::base::permanently basePermanently; { auto iter = globalBaseAtomics.find(socket_id); @@ -1084,7 +1094,6 @@ eResult cDataPlane::initWorkers() return result; } - worker->fillStatsNamesToAddrsTable(coreId_to_stats_tables[core_id]); worker_gcs[core_id] = worker; socket_worker_gcs[socket_id] = worker; } @@ -1106,6 +1115,8 @@ eResult cDataPlane::InitSlowWorker(const tCoreId core, const CPlaneWorkerConfig& return eResult::errorAllocatingMemory; } + worker->SetBufferForCounters(sdp_data.workers[core].buffer, sdp_data.metadata_worker); + dataplane::base::permanently basePermanently; basePermanently.globalBaseAtomic = globalBaseAtomics[socket_id]; basePermanently.outQueueId = tx_queues_; @@ -1128,8 +1139,6 @@ eResult cDataPlane::InitSlowWorker(const tCoreId core, const CPlaneWorkerConfig& return result; } - worker->fillStatsNamesToAddrsTable(coreId_to_stats_tables[core]); - workers_vector.emplace_back(worker); std::vector kni_bundleconf; @@ -1225,24 +1234,6 @@ eResult cDataPlane::InitSlowWorkers() return eResult::success; } -std::optional cDataPlane::getCounterValueByName(const std::string& counter_name, uint32_t coreId) -{ - if (coreId_to_stats_tables.count(coreId) == 0) - { - return std::optional(); - } - - const auto& specific_core_table = coreId_to_stats_tables[coreId]; - - if (specific_core_table.count(counter_name) == 0) - { - return std::optional(); - } - - uint64_t counter_value = *(specific_core_table.at(counter_name)); - return std::optional(counter_value); -} - eResult cDataPlane::InitTxQueues() { for (const auto& portIter : ports) @@ -1494,6 +1485,31 @@ void cDataPlane::run_on_worker_gc(const tSocketId socket_id, socket_worker_gcs.find(socket_id)->second->run_on_this_thread(callback); } +eResult cDataPlane::initSharedMemory() +{ + std::vector workers_id; + std::vector workers_gc_id; + + // workers + for (const auto& worker : config.workers) + { + workers_id.push_back(worker.first); + } + // slow worker + workers_id.push_back(config.controlPlaneCoreId); + // workers gc + for (const auto& coreId : config.workerGCs) + { + workers_gc_id.push_back(coreId); + } + + cWorker::FillMetadataWorkerCounters(sdp_data.metadata_worker); + worker_gc_t::FillMetadataWorkerCounters(sdp_data.metadata_worker_gc); + sdp_data.size_bus_section = cBus::GetSizeForCounters(); + + return common::sdp::SdrSever::PrepareSharedMemoryData(sdp_data, workers_id, workers_gc_id, config.useHugeMem); +} + eResult cDataPlane::allocateSharedMemory() { /// precalculation of shared memory size for each numa diff --git a/dataplane/dataplane.h b/dataplane/dataplane.h index 31491954..453a8cec 100644 --- a/dataplane/dataplane.h +++ b/dataplane/dataplane.h @@ -26,6 +26,7 @@ #include "memory_manager.h" #include "neighbor.h" #include "report.h" +#include "sdpserver.h" #include "slow_worker.h" #include "type.h" @@ -152,12 +153,12 @@ class cDataPlane eResult initKniQueues(); eResult InitTxQueues(); eResult InitRxQueues(); + eResult initSharedMemory(); void init_worker_base(); eResult allocateSharedMemory(); eResult splitSharedMemoryPerWorkers(); - std::optional getCounterValueByName(const std::string& counter_name, uint32_t coreId); common::idp::get_shm_info::response getShmInfo(); common::idp::get_shm_tsc_info::response getShmTscInfo(); @@ -169,7 +170,6 @@ class cDataPlane friend class cWorker; friend class cReport; friend class cControlPlane; - friend class cBus; friend class dataplane::globalBase::generation; friend class worker_gc_t; @@ -224,9 +224,6 @@ class cDataPlane common::idp::get_shm_tsc_info::response tscs_meta; - // array instead of the table - how many coreIds can be there? - std::unordered_map> coreId_to_stats_tables; - std::map> shm_by_socket_id; std::set socket_ids; @@ -242,6 +239,8 @@ class cDataPlane mutable std::mutex dpdk_mutex; + common::sdp::DataPlaneInSharedMemory sdp_data; + public: ///< modules cReport report; std::unique_ptr controlPlane; diff --git a/dataplane/report.cpp b/dataplane/report.cpp index ca037fb8..19ebf3e5 100644 --- a/dataplane/report.cpp +++ b/dataplane/report.cpp @@ -139,37 +139,37 @@ nlohmann::json cReport::convertWorker(const cWorker* worker) json["mempool"] = convertMempool(worker->mempool); json["iteration"] = worker->iteration; - json["stats"]["brokenPackets"] = worker->stats.brokenPackets; - json["stats"]["dropPackets"] = worker->stats.dropPackets; - json["stats"]["ring_highPriority_drops"] = worker->stats.ring_highPriority_drops; - json["stats"]["ring_normalPriority_drops"] = worker->stats.ring_normalPriority_drops; - json["stats"]["ring_lowPriority_drops"] = worker->stats.ring_lowPriority_drops; - json["stats"]["decap_packets"] = worker->stats.decap_packets; - json["stats"]["decap_fragments"] = worker->stats.decap_fragments; - json["stats"]["decap_unknownExtensions"] = worker->stats.decap_unknownExtensions; - json["stats"]["interface_lookupMisses"] = worker->stats.interface_lookupMisses; - json["stats"]["interface_hopLimits"] = worker->stats.interface_hopLimits; - json["stats"]["interface_neighbor_invalid"] = worker->stats.interface_neighbor_invalid; - json["stats"]["nat64stateless_ingressPackets"] = worker->stats.nat64stateless_ingressPackets; - json["stats"]["nat64stateless_ingressFragments"] = worker->stats.nat64stateless_ingressFragments; - json["stats"]["nat64stateless_ingressUnknownICMP"] = worker->stats.nat64stateless_ingressUnknownICMP; - json["stats"]["nat64stateless_egressPackets"] = worker->stats.nat64stateless_egressPackets; - json["stats"]["nat64stateless_egressFragments"] = worker->stats.nat64stateless_egressFragments; - json["stats"]["nat64stateless_egressUnknownICMP"] = worker->stats.nat64stateless_egressUnknownICMP; - json["stats"]["balancer_invalid_reals_count"] = worker->stats.balancer_invalid_reals_count; - json["stats"]["fwsync_multicast_egress_drops"] = worker->stats.fwsync_multicast_egress_drops; - json["stats"]["fwsync_multicast_egress_packets"] = worker->stats.fwsync_multicast_egress_packets; - json["stats"]["fwsync_unicast_egress_drops"] = worker->stats.fwsync_unicast_egress_drops; - json["stats"]["fwsync_unicast_egress_packets"] = worker->stats.fwsync_unicast_egress_packets; - json["stats"]["fwsync_multicast_egress_imm_packets"] = worker->stats.fwsync_multicast_egress_imm_packets; - json["stats"]["fwsync_no_config_drops"] = worker->stats.fwsync_no_config_drops; - json["stats"]["acl_ingress_dropPackets"] = worker->stats.acl_ingress_dropPackets; - json["stats"]["acl_egress_dropPackets"] = worker->stats.acl_egress_dropPackets; - json["stats"]["repeat_ttl"] = worker->stats.repeat_ttl; - json["stats"]["leakedMbufs"] = worker->stats.leakedMbufs; + json["stats"]["brokenPackets"] = worker->stats->brokenPackets; + json["stats"]["dropPackets"] = worker->stats->dropPackets; + json["stats"]["ring_highPriority_drops"] = worker->stats->ring_highPriority_drops; + json["stats"]["ring_normalPriority_drops"] = worker->stats->ring_normalPriority_drops; + json["stats"]["ring_lowPriority_drops"] = worker->stats->ring_lowPriority_drops; + json["stats"]["decap_packets"] = worker->stats->decap_packets; + json["stats"]["decap_fragments"] = worker->stats->decap_fragments; + json["stats"]["decap_unknownExtensions"] = worker->stats->decap_unknownExtensions; + json["stats"]["interface_lookupMisses"] = worker->stats->interface_lookupMisses; + json["stats"]["interface_hopLimits"] = worker->stats->interface_hopLimits; + json["stats"]["interface_neighbor_invalid"] = worker->stats->interface_neighbor_invalid; + json["stats"]["nat64stateless_ingressPackets"] = worker->stats->nat64stateless_ingressPackets; + json["stats"]["nat64stateless_ingressFragments"] = worker->stats->nat64stateless_ingressFragments; + json["stats"]["nat64stateless_ingressUnknownICMP"] = worker->stats->nat64stateless_ingressUnknownICMP; + json["stats"]["nat64stateless_egressPackets"] = worker->stats->nat64stateless_egressPackets; + json["stats"]["nat64stateless_egressFragments"] = worker->stats->nat64stateless_egressFragments; + json["stats"]["nat64stateless_egressUnknownICMP"] = worker->stats->nat64stateless_egressUnknownICMP; + json["stats"]["balancer_invalid_reals_count"] = worker->stats->balancer_invalid_reals_count; + json["stats"]["fwsync_multicast_egress_drops"] = worker->stats->fwsync_multicast_egress_drops; + json["stats"]["fwsync_multicast_egress_packets"] = worker->stats->fwsync_multicast_egress_packets; + json["stats"]["fwsync_unicast_egress_drops"] = worker->stats->fwsync_unicast_egress_drops; + json["stats"]["fwsync_unicast_egress_packets"] = worker->stats->fwsync_unicast_egress_packets; + json["stats"]["fwsync_multicast_egress_imm_packets"] = worker->stats->fwsync_multicast_egress_imm_packets; + json["stats"]["fwsync_no_config_drops"] = worker->stats->fwsync_no_config_drops; + json["stats"]["acl_ingress_dropPackets"] = worker->stats->acl_ingress_dropPackets; + json["stats"]["acl_egress_dropPackets"] = worker->stats->acl_egress_dropPackets; + json["stats"]["repeat_ttl"] = worker->stats->repeat_ttl; + json["stats"]["leakedMbufs"] = worker->stats->leakedMbufs; json["stats"]["samples_drops"] = worker->sampler.get_drops(); - json["stats"]["logs_packets"] = worker->stats.logs_packets; - json["stats"]["logs_drops"] = worker->stats.logs_drops; + json["stats"]["logs_packets"] = worker->stats->logs_packets; + json["stats"]["logs_drops"] = worker->stats->logs_drops; for (tPortId portId = 0; portId < dataPlane->ports.size(); @@ -267,15 +267,15 @@ nlohmann::json cReport::convertWorkerGC(const worker_gc_t* worker) json["iteration"] = worker->iteration; json["samples"] = worker->samples.size(); - json["stats"]["broken_packets"] = worker->stats.broken_packets; - json["stats"]["drop_packets"] = worker->stats.drop_packets; - json["stats"]["drop_samples"] = worker->stats.drop_samples; - json["stats"]["fwsync_multicast_egress_packets"] = worker->stats.fwsync_multicast_egress_packets; - json["stats"]["fwsync_multicast_egress_drops"] = worker->stats.fwsync_multicast_egress_drops; - json["stats"]["fwsync_unicast_egress_packets"] = worker->stats.fwsync_unicast_egress_packets; - json["stats"]["fwsync_unicast_egress_drops"] = worker->stats.fwsync_unicast_egress_drops; - json["stats"]["balancer_state_insert_failed"] = worker->stats.balancer_state_insert_failed; - json["stats"]["balancer_state_insert_done"] = worker->stats.balancer_state_insert_done; + json["stats"]["broken_packets"] = worker->stats->broken_packets; + json["stats"]["drop_packets"] = worker->stats->drop_packets; + json["stats"]["drop_samples"] = worker->stats->drop_samples; + json["stats"]["fwsync_multicast_egress_packets"] = worker->stats->fwsync_multicast_egress_packets; + json["stats"]["fwsync_multicast_egress_drops"] = worker->stats->fwsync_multicast_egress_drops; + json["stats"]["fwsync_unicast_egress_packets"] = worker->stats->fwsync_unicast_egress_packets; + json["stats"]["fwsync_unicast_egress_drops"] = worker->stats->fwsync_unicast_egress_drops; + json["stats"]["balancer_state_insert_failed"] = worker->stats->balancer_state_insert_failed; + json["stats"]["balancer_state_insert_done"] = worker->stats->balancer_state_insert_done; /// permanently base json["permanentlyBase"]["globalBaseAtomic"]["pointer"] = pointerToHex(worker->base_permanently.globalBaseAtomic); diff --git a/dataplane/sdpserver.h b/dataplane/sdpserver.h new file mode 100644 index 00000000..e224ee92 --- /dev/null +++ b/dataplane/sdpserver.h @@ -0,0 +1,220 @@ +#pragma once + +#include "common/result.h" +#include "common/sdpcommon.h" +#include "type.h" + +namespace common::sdp +{ + +class SdrSever +{ +public: + static eResult PrepareSharedMemoryData(DataPlaneInSharedMemory& sdp_data, + const std::vector& workers_id, + const std::vector& workers_gc_id, + bool use_huge_tlb) + { + // Part 1 - prepare data workers + // + std::map sockets_shifts; + + // Fill workers info + for (tCoreId core_id : workers_id) + { + tSocketId socket_id = GetNumaNode(core_id); + sdp_data.workers[core_id] = {socket_id, sockets_shifts[socket_id], nullptr}; + sockets_shifts[socket_id] += sdp_data.metadata_worker.size; + } + + // Fill workers_gc info + for (tCoreId core_id : workers_gc_id) + { + tSocketId socket_id = GetNumaNode(core_id); + sdp_data.workers_gc[core_id] = {socket_id, sockets_shifts[socket_id], nullptr}; + sockets_shifts[socket_id] += sdp_data.metadata_worker_gc.size; + } + + // Create buffers in shared memory for workers in numa nodes +#ifndef YANET_USE_POSIX_SHARED_MEMORY + key_t key_shared_memory_segment = YANET_SHARED_MEMORY_KEY_DATAPLANE; +#endif + std::map sockets_buffers; + for (auto [socket_id, size] : sockets_shifts) + { +#ifdef YANET_USE_POSIX_SHARED_MEMORY + std::string filename = common::sdp::FileNameWorkerOnNumaNode(socket_id); + void* buffer = common::ipc::SharedMemory::CreateBufferFile(filename, size, use_huge_tlb, socket_id); + if (buffer == nullptr) + { + YANET_LOG_ERROR("Error create buffer in shared memory for workers on numa=%d, filename=%s, size=%ld", + socket_id, + filename.c_str(), + size); + return eResult::errorInitSharedMemory; + } +#else + key_shared_memory_segment++; + void* buffer = common::ipc::SharedMemory::CreateBufferKey(key_shared_memory_segment, size, use_huge_tlb, socket_id); + if (buffer == nullptr) + { + YANET_LOG_ERROR("Error create buffer in shared memory for workers on numa=%d, key=%d, size=%ld", + socket_id, + key_shared_memory_segment, + size); + return eResult::errorInitSharedMemory; + } +#endif + sockets_buffers[socket_id] = buffer; + } + + // Fill workers buffers + for (auto& worker_info : sdp_data.workers) + { + worker_info.second.buffer = (char*)sockets_buffers[worker_info.second.socket] + worker_info.second.shift_in_socket; + } + + // Fill workers_gc buffers + for (auto& worker_info : sdp_data.workers_gc) + { + worker_info.second.buffer = (char*)sockets_buffers[worker_info.second.socket] + worker_info.second.shift_in_socket; + } + + // Part 2 - prepare data dataplane + // Create buffer in shared memory for dataplane data + sdp_data.FillSizes(); +#ifdef YANET_USE_POSIX_SHARED_MEMORY + sdp_data.dataplane_data = common::ipc::SharedMemory::CreateBufferFile(YANET_SHARED_MEMORY_FILE_DATAPLANE, + sdp_data.size_dataplane_buffer, + use_huge_tlb, + std::nullopt); + if (sdp_data.dataplane_data == nullptr) + { + YANET_LOG_ERROR("Error create buffer in shared memory for dataplane data, filename=%s, size=%ld", + YANET_SHARED_MEMORY_FILE_DATAPLANE, + sdp_data.size_dataplane_buffer); + return eResult::errorInitSharedMemory; + } +#else + sdp_data.dataplane_data = common::ipc::SharedMemory::CreateBufferKey(YANET_SHARED_MEMORY_KEY_DATAPLANE, + sdp_data.size_dataplane_buffer, + use_huge_tlb, + std::nullopt); + if (sdp_data.dataplane_data == nullptr) + { + YANET_LOG_ERROR("Error create buffer in shared memory for dataplane data, key=%d, size=%ld", + key_shared_memory_segment, + sdp_data.size_dataplane_buffer); + return eResult::errorInitSharedMemory; + } +#endif + + WriteMainDataToBuffer(sdp_data); + + return eResult::success; + } + + static uint64_t GetStartData(uint64_t size, uint64_t& current_start) + { + static constexpr uint64_t cache_line_size = 64; + uint64_t result = current_start; + current_start += size; + current_start = cache_line_size * ((current_start + cache_line_size - 1) / cache_line_size); + return result; + } + +private: + static void WriteMainDataToBuffer(DataPlaneInSharedMemory& sdp_data) + { + // HEADER + uint64_t start_workers = DataPlaneInSharedMemory::size_header; + WriteValue(sdp_data, 0, start_workers); + WriteValue(sdp_data, 1, sdp_data.size_workers_section); + + uint64_t start_workers_metadata = start_workers + sdp_data.size_workers_section; + WriteValue(sdp_data, 2, start_workers_metadata); + WriteValue(sdp_data, 3, sdp_data.size_workers_metadata_section); + + sdp_data.start_bus_section = start_workers_metadata + sdp_data.size_workers_metadata_section; + WriteValue(sdp_data, 4, sdp_data.start_bus_section); + WriteValue(sdp_data, 5, sdp_data.size_bus_section); + + // WORKERS + { + uint64_t index = start_workers / sizeof(uint64_t); + WriteValue(sdp_data, index++, sdp_data.workers.size()); + WriteValue(sdp_data, index++, sdp_data.workers_gc.size()); + + for (const auto& [coreId, info] : sdp_data.workers) + { + WriteValue(sdp_data, index++, coreId); + WriteValue(sdp_data, index++, info.socket); + WriteValue(sdp_data, index++, info.shift_in_socket); + } + + for (const auto& [coreId, info] : sdp_data.workers_gc) + { + WriteValue(sdp_data, index++, coreId); + WriteValue(sdp_data, index++, info.socket); + WriteValue(sdp_data, index++, info.shift_in_socket); + } + } + + // WORKERS_METADATA + { + uint64_t index = start_workers_metadata / sizeof(uint64_t); + + // 0-5 - values from MetadataWorker + WriteValue(sdp_data, index, sdp_data.metadata_worker.start_counters); + WriteValue(sdp_data, index + 1, sdp_data.metadata_worker.start_acl_counters); + WriteValue(sdp_data, index + 2, sdp_data.metadata_worker.start_bursts); + WriteValue(sdp_data, index + 3, sdp_data.metadata_worker.start_stats); + WriteValue(sdp_data, index + 4, sdp_data.metadata_worker.start_stats_ports); + WriteValue(sdp_data, index + 5, sdp_data.metadata_worker.size); + // 6 - n1 = size MetadataWorker.counter_positions + WriteValue(sdp_data, index + 6, sdp_data.metadata_worker.counter_positions.size()); + // 7-9 - значения из MetadataWorker + WriteValue(sdp_data, index + 7, sdp_data.metadata_worker_gc.start_counters); + WriteValue(sdp_data, index + 8, sdp_data.metadata_worker_gc.start_stats); + WriteValue(sdp_data, index + 9, sdp_data.metadata_worker_gc.size); + // 10 - n2 = size MetadataWorker.counter_positions + WriteValue(sdp_data, index + 10, sdp_data.metadata_worker_gc.counter_positions.size()); + + WriteMap(sdp_data, start_workers_metadata + 128, sdp_data.metadata_worker.counter_positions); + WriteMap(sdp_data, start_workers_metadata + 128 * (1 + sdp_data.metadata_worker.counter_positions.size()), sdp_data.metadata_worker_gc.counter_positions); + } + } + + static void WriteMap(DataPlaneInSharedMemory& sdp_data, uint64_t index, const std::map& values) + { + for (const auto& [key, value] : values) + { + WriteValue(sdp_data, index / sizeof(uint64_t), value); + WriteString(sdp_data, index, key); + index += 128; + } + } + + static void WriteValue(DataPlaneInSharedMemory& sdp_data, uint64_t index, uint64_t value) + { + ((uint64_t*)sdp_data.dataplane_data)[index] = rte_cpu_to_be_64(value); + } + + static void WriteString(DataPlaneInSharedMemory& sdp_data, uint64_t index, const std::string& str) + { + snprintf(reinterpret_cast(sdp_data.dataplane_data) + index + 8, 120, "%s", str.c_str()); + } + + static int GetNumaNode(tCoreId core_id) + { + int socket_id = numa_node_of_cpu(core_id); + if (socket_id == -1) + { + YANET_LOG_ERROR("numa_node_of_cpu(%d) err: %s\n", core_id, strerror(errno)); + socket_id = 0; + } + return socket_id; + } +}; + +} // namespace common::sdp diff --git a/dataplane/unittest/meson.build b/dataplane/unittest/meson.build index 71429fb4..18c19364 100644 --- a/dataplane/unittest/meson.build +++ b/dataplane/unittest/meson.build @@ -8,7 +8,8 @@ dependencies += dependency('gtest_main') sources = files('unittest.cpp', 'ip_address.cpp', - 'hashtable.cpp') + 'hashtable.cpp', + 'sdp.cpp') arch = 'corei7' cpp_args_append = ['-march=' + arch] diff --git a/dataplane/unittest/sdp.cpp b/dataplane/unittest/sdp.cpp new file mode 100644 index 00000000..312e024f --- /dev/null +++ b/dataplane/unittest/sdp.cpp @@ -0,0 +1,368 @@ +#include + +#include "../../common/idp.h" +#include "../../common/sdpclient.h" +#include "../sdpserver.h" + +class TestBus +{ +public: + static uint64_t GetSizeForCounters() + { + uint32_t count_errors = static_cast(common::idp::errorType::size); + uint32_t count_requests = static_cast(common::idp::requestType::size); + return (count_errors + 2 * count_requests) * sizeof(uint64_t); + } + + void SetBufferForCounters(const common::sdp::DataPlaneInSharedMemory& sdp_data) + { + auto [requests, errors, durations] = sdp_data.BuffersBus(); + stats.requests = requests; + stats.errors = errors; + stats.durations = durations; + } + + void SetTestValues() + { + for (uint32_t index = 0; index < static_cast(common::idp::requestType::size); index++) + { + if (index % 2 == 0) + { + stats.requests[index] = index * index; + stats.durations[index] = index * index * index; + } + } + + stats.errors[static_cast(common::idp::errorType::busRead)] = 19; + } + + void CompareWithClient(const common::sdp::DataPlaneInSharedMemory& sdp_data_client) + { + void* buffer = common::sdp::ShiftBuffer(sdp_data_client.dataplane_data, sdp_data_client.start_bus_section); + uint32_t count_errors = static_cast(common::idp::errorType::size); + uint32_t count_requests = static_cast(common::idp::requestType::size); + uint64_t* requests = common::sdp::ShiftBuffer(buffer, 0); + uint64_t* errors = common::sdp::ShiftBuffer(buffer, count_requests * sizeof(uint64_t)); + uint64_t* durations = common::sdp::ShiftBuffer(buffer, (count_requests + count_errors) * sizeof(uint64_t)); + + for (uint32_t index = 0; index < static_cast(common::idp::requestType::size); index++) + { + ASSERT_EQ(stats.requests[index], requests[index]); + ASSERT_EQ(stats.durations[index], durations[index]); + } + + for (uint32_t index = 0; index < static_cast(common::idp::requestType::size); index++) + { + ASSERT_EQ(stats.errors[index], errors[index]); + } + } + +protected: + struct sStats + { + uint64_t* requests; // common::idp::requestType::size + uint64_t* errors; // common::idp::errorType::size + uint64_t* durations; // common::idp::requestType::size + } stats; +}; + +class TestWorker +{ +public: + static void FillMetadataWorkerCounters(common::sdp::MetadataWorker& metadata) + { + metadata.size = 0; + metadata.start_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_acl_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_ACL_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_bursts = common::sdp::SdrSever::GetStartData((CONFIG_YADECAP_MBUFS_BURST_SIZE + 1) * sizeof(uint64_t), metadata.size); + metadata.start_stats = common::sdp::SdrSever::GetStartData(sizeof(common::worker::stats::common), metadata.size); + metadata.start_stats_ports = common::sdp::SdrSever::GetStartData(sizeof(common::worker::stats::port[CONFIG_YADECAP_PORTS_SIZE]), metadata.size); + + // stats + std::map counters_stats; + counters_stats["brokenPackets"] = offsetof(common::worker::stats::common, brokenPackets); + counters_stats["dropPackets"] = offsetof(common::worker::stats::common, dropPackets); + counters_stats["ring_highPriority_drops"] = offsetof(common::worker::stats::common, ring_highPriority_drops); + counters_stats["ring_normalPriority_drops"] = offsetof(common::worker::stats::common, ring_normalPriority_drops); + counters_stats["ring_lowPriority_drops"] = offsetof(common::worker::stats::common, ring_lowPriority_drops); + counters_stats["ring_highPriority_packets"] = offsetof(common::worker::stats::common, ring_highPriority_packets); + counters_stats["ring_normalPriority_packets"] = offsetof(common::worker::stats::common, ring_normalPriority_packets); + counters_stats["ring_lowPriority_packets"] = offsetof(common::worker::stats::common, ring_lowPriority_packets); + counters_stats["decap_packets"] = offsetof(common::worker::stats::common, decap_packets); + counters_stats["decap_fragments"] = offsetof(common::worker::stats::common, decap_fragments); + counters_stats["decap_unknownExtensions"] = offsetof(common::worker::stats::common, decap_unknownExtensions); + counters_stats["interface_lookupMisses"] = offsetof(common::worker::stats::common, interface_lookupMisses); + counters_stats["interface_hopLimits"] = offsetof(common::worker::stats::common, interface_hopLimits); + counters_stats["interface_neighbor_invalid"] = offsetof(common::worker::stats::common, interface_neighbor_invalid); + counters_stats["nat64stateless_ingressPackets"] = offsetof(common::worker::stats::common, nat64stateless_ingressPackets); + counters_stats["nat64stateless_ingressFragments"] = offsetof(common::worker::stats::common, nat64stateless_ingressFragments); + counters_stats["nat64stateless_ingressUnknownICMP"] = offsetof(common::worker::stats::common, nat64stateless_ingressUnknownICMP); + counters_stats["nat64stateless_egressPackets"] = offsetof(common::worker::stats::common, nat64stateless_egressPackets); + counters_stats["nat64stateless_egressFragments"] = offsetof(common::worker::stats::common, nat64stateless_egressFragments); + counters_stats["nat64stateless_egressUnknownICMP"] = offsetof(common::worker::stats::common, nat64stateless_egressUnknownICMP); + counters_stats["balancer_invalid_reals_count"] = offsetof(common::worker::stats::common, balancer_invalid_reals_count); + counters_stats["fwsync_multicast_egress_drops"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_drops); + counters_stats["fwsync_multicast_egress_packets"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_packets); + counters_stats["fwsync_multicast_egress_imm_packets"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_imm_packets); + counters_stats["fwsync_no_config_drops"] = offsetof(common::worker::stats::common, fwsync_no_config_drops); + counters_stats["fwsync_unicast_egress_drops"] = offsetof(common::worker::stats::common, fwsync_unicast_egress_drops); + counters_stats["fwsync_unicast_egress_packets"] = offsetof(common::worker::stats::common, fwsync_unicast_egress_packets); + counters_stats["acl_ingress_dropPackets"] = offsetof(common::worker::stats::common, acl_ingress_dropPackets); + counters_stats["acl_egress_dropPackets"] = offsetof(common::worker::stats::common, acl_egress_dropPackets); + counters_stats["repeat_ttl"] = offsetof(common::worker::stats::common, repeat_ttl); + counters_stats["leakedMbufs"] = offsetof(common::worker::stats::common, leakedMbufs); + counters_stats["logs_packets"] = offsetof(common::worker::stats::common, logs_packets); + counters_stats["logs_drops"] = offsetof(common::worker::stats::common, logs_drops); + for (const auto& iter : counters_stats) + { + metadata.counter_positions[iter.first] = (metadata.start_stats + iter.second) / sizeof(uint64_t); + } + + // counters + std::map counters_named; + counters_named["balancer_state_insert_failed"] = common::globalBase::static_counter_type::balancer_state_insert_failed; + counters_named["balancer_state_insert_done"] = common::globalBase::static_counter_type::balancer_state_insert_done; + counters_named["balancer_icmp_generated_echo_reply_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv4; + counters_named["balancer_icmp_generated_echo_reply_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv6; + counters_named["balancer_icmp_drop_icmpv4_payload_too_short_ip"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_ip; + counters_named["balancer_icmp_drop_icmpv4_payload_too_short_port"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_port; + counters_named["balancer_icmp_drop_icmpv6_payload_too_short_ip"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_ip; + counters_named["balancer_icmp_drop_icmpv6_payload_too_short_port"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_port; + counters_named["balancer_icmp_unmatching_src_from_original_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv4; + counters_named["balancer_icmp_unmatching_src_from_original_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv6; + counters_named["balancer_icmp_drop_real_disabled"] = common::globalBase::static_counter_type::balancer_icmp_drop_real_disabled; + counters_named["balancer_icmp_no_balancer_src_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv4; + counters_named["balancer_icmp_no_balancer_src_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv6; + counters_named["balancer_icmp_drop_already_cloned"] = common::globalBase::static_counter_type::balancer_icmp_drop_already_cloned; + counters_named["balancer_icmp_drop_no_unrdup_table_for_balancer_id"] = common::globalBase::static_counter_type::balancer_icmp_drop_no_unrdup_table_for_balancer_id; + counters_named["balancer_icmp_drop_unrdup_vip_not_found"] = common::globalBase::static_counter_type::balancer_icmp_drop_unrdup_vip_not_found; + counters_named["balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id"] = common::globalBase::static_counter_type::balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id; + counters_named["balancer_icmp_drop_unexpected_transport_protocol"] = common::globalBase::static_counter_type::balancer_icmp_drop_unexpected_transport_protocol; + counters_named["balancer_icmp_drop_unknown_service"] = common::globalBase::static_counter_type::balancer_icmp_drop_unknown_service; + counters_named["balancer_icmp_failed_to_clone"] = common::globalBase::static_counter_type::balancer_icmp_failed_to_clone; + counters_named["balancer_icmp_clone_forwarded"] = common::globalBase::static_counter_type::balancer_icmp_clone_forwarded; + counters_named["balancer_icmp_sent_to_real"] = common::globalBase::static_counter_type::balancer_icmp_sent_to_real; + counters_named["balancer_icmp_out_rate_limit_reached"] = common::globalBase::static_counter_type::balancer_icmp_out_rate_limit_reached; + counters_named["slow_worker_normal_priority_rate_limit_exceeded"] = common::globalBase::static_counter_type::slow_worker_normal_priority_rate_limit_exceeded; + + counters_named["acl_ingress_v4_broken_packet"] = common::globalBase::static_counter_type::acl_ingress_v4_broken_packet; + counters_named["acl_ingress_v6_broken_packet"] = common::globalBase::static_counter_type::acl_ingress_v6_broken_packet; + counters_named["acl_egress_v4_broken_packet"] = common::globalBase::static_counter_type::acl_egress_v4_broken_packet; + counters_named["acl_egress_v6_broken_packet"] = common::globalBase::static_counter_type::acl_egress_v6_broken_packet; + counters_named["balancer_fragment_drops"] = common::globalBase::static_counter_type::balancer_fragment_drops; + + for (const auto& iter : counters_named) + { + metadata.counter_positions[iter.first] = metadata.start_counters / sizeof(uint64_t) + static_cast(iter.second); + } + } + + void SetBufferForCounters(void* buffer, const common::sdp::MetadataWorker& metadata) + { + counters = common::sdp::ShiftBuffer(buffer, metadata.start_counters); + aclCounters = common::sdp::ShiftBuffer(buffer, metadata.start_acl_counters); + bursts = common::sdp::ShiftBuffer(buffer, metadata.start_bursts); + stats = common::sdp::ShiftBuffer(buffer, metadata.start_stats); + statsPorts = common::sdp::ShiftBuffer(buffer, metadata.start_stats_ports); + } + + void SetTestValues(tCoreId coreId) + { + // stats + stats->dropPackets = (coreId + 1) * (coreId + 1); + + // statsPorts + for (uint32_t index = 0; index < CONFIG_YADECAP_PORTS_SIZE + 1; index++) + { + statsPorts[index].controlPlane_drops = 3 * (index + coreId); + statsPorts[index].physicalPort_egress_drops = 4 * (index + coreId); + } + + // bursts + for (uint32_t index = 0; index < CONFIG_YADECAP_MBUFS_BURST_SIZE + 1; index++) + { + bursts[index] = 5 * (index + coreId); + } + + // counters + for (uint32_t index = YANET_CONFIG_COUNTER_FALLBACK_SIZE; index < YANET_CONFIG_COUNTERS_SIZE; index++) + { + counters[index] = (index + coreId) * (index + coreId); + } + + // aclCounters + for (uint32_t index = 0; index < YANET_CONFIG_ACL_COUNTERS_SIZE; index++) + { + aclCounters[index] = index + coreId; + } + } + + void CompareWithClient(tCoreId coreId, const common::sdp::DataPlaneInSharedMemory& sdp_data_client) + { + auto iter = sdp_data_client.workers.find(coreId); + ASSERT_TRUE(iter != sdp_data_client.workers.end()); + void* buffer = iter->second.buffer; + + // stats + ASSERT_EQ(common::sdp::SdpClient::GetCounterByName(sdp_data_client, "dropPackets", coreId)[coreId], stats->dropPackets); + + // statsPorts + common::worker::stats::port* bufStatsPorts = common::sdp::ShiftBuffer(buffer, sdp_data_client.metadata_worker.start_stats_ports); + for (uint32_t index = 0; index < CONFIG_YADECAP_PORTS_SIZE + 1; index++) + { + ASSERT_EQ(statsPorts[index].controlPlane_drops, bufStatsPorts[index].controlPlane_drops); + ASSERT_EQ(statsPorts[index].physicalPort_egress_drops, bufStatsPorts[index].physicalPort_egress_drops); + } + + // bursts + uint64_t* bufBursts = common::sdp::ShiftBuffer(buffer, sdp_data_client.metadata_worker.start_bursts); + for (uint32_t index = 0; index < CONFIG_YADECAP_MBUFS_BURST_SIZE + 1; index++) + { + ASSERT_EQ(bursts[index], bufBursts[index]); + } + + // counters + uint64_t* bufCounters = common::sdp::ShiftBuffer(buffer, sdp_data_client.metadata_worker.start_counters); + for (uint32_t index = 0; index < YANET_CONFIG_COUNTERS_SIZE; index++) + { + ASSERT_EQ(counters[index], bufCounters[index]); + } + + // aclCounters + uint64_t* bufAclCounters = common::sdp::ShiftBuffer(buffer, sdp_data_client.metadata_worker.start_acl_counters); + for (uint32_t index = 0; index < YANET_CONFIG_ACL_COUNTERS_SIZE; index++) + { + ASSERT_EQ(aclCounters[index], bufAclCounters[index]); + } + } + +protected: + common::worker::stats::common* stats; + common::worker::stats::port* statsPorts; // CONFIG_YADECAP_PORTS_SIZE + uint64_t* bursts; // CONFIG_YADECAP_MBUFS_BURST_SIZE + 1 + uint64_t* counters; // YANET_CONFIG_COUNTERS_SIZE + uint64_t* aclCounters; // YANET_CONFIG_ACL_COUNTERS_SIZE +}; + +class TestWorkerGc +{ +public: + static void FillMetadataWorkerCounters(common::sdp::MetadataWorkerGc& metadata) + { + metadata.size = 0; + metadata.start_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_stats = common::sdp::SdrSever::GetStartData(sizeof(common::worker_gc::stats_t), metadata.size); + + // stats + static_assert(std::is_trivially_destructible::value, "invalid struct destructible"); + std::map counters_stats; + counters_stats["broken_packets"] = offsetof(common::worker_gc::stats_t, broken_packets); + counters_stats["drop_packets"] = offsetof(common::worker_gc::stats_t, drop_packets); + counters_stats["ring_to_slowworker_packets"] = offsetof(common::worker_gc::stats_t, ring_to_slowworker_packets); + counters_stats["ring_to_slowworker_drops"] = offsetof(common::worker_gc::stats_t, ring_to_slowworker_drops); + counters_stats["fwsync_multicast_egress_packets"] = offsetof(common::worker_gc::stats_t, fwsync_multicast_egress_packets); + counters_stats["fwsync_multicast_egress_drops"] = offsetof(common::worker_gc::stats_t, fwsync_multicast_egress_drops); + counters_stats["fwsync_unicast_egress_packets"] = offsetof(common::worker_gc::stats_t, fwsync_unicast_egress_packets); + counters_stats["fwsync_unicast_egress_drops"] = offsetof(common::worker_gc::stats_t, fwsync_unicast_egress_drops); + counters_stats["drop_samples"] = offsetof(common::worker_gc::stats_t, drop_samples); + counters_stats["balancer_state_insert_failed"] = offsetof(common::worker_gc::stats_t, balancer_state_insert_failed); + counters_stats["balancer_state_insert_done"] = offsetof(common::worker_gc::stats_t, balancer_state_insert_done); + + for (const auto& iter : counters_stats) + { + metadata.counter_positions[iter.first] = (metadata.start_stats + iter.second) / sizeof(uint64_t); + } + } + + void SetBufferForCounters(void* buffer, const common::sdp::MetadataWorkerGc& metadata) + { + counters = common::sdp::ShiftBuffer(buffer, metadata.start_counters); + stats = common::sdp::ShiftBuffer(buffer, metadata.start_stats); + } + + void SetTestValues(tCoreId coreId) + { + // stats + stats->drop_samples = 7 * (coreId + 1) * (coreId + 1); + + // counters + for (uint32_t index = YANET_CONFIG_COUNTER_FALLBACK_SIZE; index < YANET_CONFIG_COUNTERS_SIZE; index++) + { + counters[index] = 11 * (index + coreId) * (index + coreId); + } + } + + void CompareWithClient(tCoreId coreId, const common::sdp::DataPlaneInSharedMemory& sdp_data_client) + { + auto iter = sdp_data_client.workers_gc.find(coreId); + ASSERT_TRUE(iter != sdp_data_client.workers_gc.end()); + void* buffer = iter->second.buffer; + + // stats + ASSERT_EQ(common::sdp::SdpClient::GetCounterByName(sdp_data_client, "drop_samples", coreId)[coreId], stats->drop_samples); + + // counters + uint64_t* bufCounters = common::sdp::ShiftBuffer(buffer, sdp_data_client.metadata_worker_gc.start_counters); + for (uint32_t index = 0; index < YANET_CONFIG_COUNTERS_SIZE; index++) + { + ASSERT_EQ(counters[index], bufCounters[index]); + } + } + +protected: + uint64_t* counters; // YANET_CONFIG_COUNTERS_SIZE + common::worker_gc::stats_t* stats; +}; + +TEST(SDP, FullTests) +{ + bool useHugeMem = false; + std::vector workers_id = {1, 2, 5}; + std::vector workers_gc_id = {0, 3}; + + // Initialize server + common::sdp::DataPlaneInSharedMemory sdp_data_server; + TestWorker::FillMetadataWorkerCounters(sdp_data_server.metadata_worker); + TestWorkerGc::FillMetadataWorkerCounters(sdp_data_server.metadata_worker_gc); + sdp_data_server.size_bus_section = TestBus::GetSizeForCounters(); + ASSERT_EQ(common::sdp::SdrSever::PrepareSharedMemoryData(sdp_data_server, workers_id, workers_gc_id, useHugeMem), eResult::success); + + // Initialize client + common::sdp::DataPlaneInSharedMemory sdp_data_client; + ASSERT_EQ(common::sdp::SdpClient::ReadSharedMemoryData(sdp_data_client, true), eResult::success); + + // Check, that server structure = client structure + ASSERT_EQ(sdp_data_server, sdp_data_client); + + // Test work bus + TestBus bus; + bus.SetBufferForCounters(sdp_data_server); + bus.SetTestValues(); + bus.CompareWithClient(sdp_data_client); + + // Test workers + std::map> workers; + for (tCoreId coreId : workers_id) + { + workers[coreId] = std::make_shared(); + workers[coreId]->SetBufferForCounters(sdp_data_server.workers[coreId].buffer, sdp_data_server.metadata_worker); + workers[coreId]->SetTestValues(coreId); + } + for (tCoreId coreId : workers_id) + { + workers[coreId]->CompareWithClient(coreId, sdp_data_client); + } + + // Test workers_gc + std::map> workers_gc; + for (tCoreId coreId : workers_gc_id) + { + workers_gc[coreId] = std::make_shared(); + workers_gc[coreId]->SetBufferForCounters(sdp_data_server.workers_gc[coreId].buffer, sdp_data_server.metadata_worker_gc); + workers_gc[coreId]->SetTestValues(coreId); + } + for (tCoreId coreId : workers_id) + { + workers[coreId]->CompareWithClient(coreId, sdp_data_client); + } +} diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index 06db1d24..aa5b09ce 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -47,8 +47,6 @@ cWorker::cWorker(cDataPlane* dataPlane) : ring_log(nullptr), packetsToSWNPRemainder(dataPlane->config.SWNormalPriorityRateLimitPerWorker) { - memset(bursts, 0, sizeof(bursts)); - memset(counters, 0, sizeof(counters)); } cWorker::~cWorker() @@ -260,71 +258,101 @@ void cWorker::start() mainThread(); } -void cWorker::fillStatsNamesToAddrsTable(std::unordered_map& table) +void cWorker::FillMetadataWorkerCounters(common::sdp::MetadataWorker& metadata) { - table["brokenPackets"] = &stats.brokenPackets; - table["dropPackets"] = &stats.dropPackets; - table["ring_highPriority_drops"] = &stats.ring_highPriority_drops; - table["ring_normalPriority_drops"] = &stats.ring_normalPriority_drops; - table["ring_lowPriority_drops"] = &stats.ring_lowPriority_drops; - table["ring_highPriority_packets"] = &stats.ring_highPriority_packets; - table["ring_normalPriority_packets"] = &stats.ring_normalPriority_packets; - table["ring_lowPriority_packets"] = &stats.ring_lowPriority_packets; - table["decap_packets"] = &stats.decap_packets; - table["decap_fragments"] = &stats.decap_fragments; - table["decap_unknownExtensions"] = &stats.decap_unknownExtensions; - table["interface_lookupMisses"] = &stats.interface_lookupMisses; - table["interface_hopLimits"] = &stats.interface_hopLimits; - table["interface_neighbor_invalid"] = &stats.interface_neighbor_invalid; - table["nat64stateless_ingressPackets"] = &stats.nat64stateless_ingressPackets; - table["nat64stateless_ingressFragments"] = &stats.nat64stateless_ingressFragments; - table["nat64stateless_ingressUnknownICMP"] = &stats.nat64stateless_ingressUnknownICMP; - table["nat64stateless_egressPackets"] = &stats.nat64stateless_egressPackets; - table["nat64stateless_egressFragments"] = &stats.nat64stateless_egressFragments; - table["nat64stateless_egressUnknownICMP"] = &stats.nat64stateless_egressUnknownICMP; - table["balancer_invalid_reals_count"] = &stats.balancer_invalid_reals_count; - table["fwsync_multicast_egress_drops"] = &stats.fwsync_multicast_egress_drops; - table["fwsync_multicast_egress_packets"] = &stats.fwsync_multicast_egress_packets; - table["fwsync_multicast_egress_imm_packets"] = &stats.fwsync_multicast_egress_imm_packets; - table["fwsync_no_config_drops"] = &stats.fwsync_no_config_drops; - table["fwsync_unicast_egress_drops"] = &stats.fwsync_unicast_egress_drops; - table["fwsync_unicast_egress_packets"] = &stats.fwsync_unicast_egress_packets; - table["acl_ingress_dropPackets"] = &stats.acl_ingress_dropPackets; - table["acl_egress_dropPackets"] = &stats.acl_egress_dropPackets; - table["repeat_ttl"] = &stats.repeat_ttl; - table["leakedMbufs"] = &stats.leakedMbufs; - table["logs_packets"] = &stats.logs_packets; - table["logs_drops"] = &stats.logs_drops; - - table["balancer_state_insert_failed"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_state_insert_failed]; - table["balancer_state_insert_done"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_state_insert_done]; - table["balancer_icmp_generated_echo_reply_ipv4"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv4]; - table["balancer_icmp_generated_echo_reply_ipv6"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv6]; - table["balancer_icmp_drop_icmpv4_payload_too_short_ip"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_ip]; - table["balancer_icmp_drop_icmpv4_payload_too_short_port"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_port]; - table["balancer_icmp_drop_icmpv6_payload_too_short_ip"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_ip]; - table["balancer_icmp_drop_icmpv6_payload_too_short_port"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_port]; - table["balancer_icmp_unmatching_src_from_original_ipv4"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv4]; - table["balancer_icmp_unmatching_src_from_original_ipv6"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv6]; - table["balancer_icmp_drop_real_disabled"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_real_disabled]; - table["balancer_icmp_no_balancer_src_ipv4"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv4]; - table["balancer_icmp_no_balancer_src_ipv6"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv6]; - table["balancer_icmp_drop_already_cloned"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_already_cloned]; - table["balancer_icmp_drop_no_unrdup_table_for_balancer_id"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_no_unrdup_table_for_balancer_id]; - table["balancer_icmp_drop_unrdup_vip_not_found"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_unrdup_vip_not_found]; - table["balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id]; - table["balancer_icmp_drop_unexpected_transport_protocol"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_unexpected_transport_protocol]; - table["balancer_icmp_drop_unknown_service"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_drop_unknown_service]; - table["balancer_icmp_failed_to_clone"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_failed_to_clone]; - table["balancer_icmp_clone_forwarded"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_clone_forwarded]; - table["balancer_icmp_sent_to_real"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_sent_to_real]; - table["balancer_icmp_out_rate_limit_reached"] = &counters[(uint32_t)common::globalBase::static_counter_type::balancer_icmp_out_rate_limit_reached]; - table["slow_worker_normal_priority_rate_limit_exceeded"] = &counters[(uint32_t)common::globalBase::static_counter_type::slow_worker_normal_priority_rate_limit_exceeded]; - - table["acl_ingress_v4_broken_packet"] = &counters[(uint32_t)common::globalBase::static_counter_type::acl_ingress_v4_broken_packet]; - table["acl_ingress_v6_broken_packet"] = &counters[(uint32_t)common::globalBase::static_counter_type::acl_ingress_v6_broken_packet]; - table["acl_egress_v4_broken_packet"] = &counters[(uint32_t)common::globalBase::static_counter_type::acl_egress_v4_broken_packet]; - table["acl_egress_v6_broken_packet"] = &counters[(uint32_t)common::globalBase::static_counter_type::acl_egress_v6_broken_packet]; + metadata.size = 0; + metadata.start_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_acl_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_ACL_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_bursts = common::sdp::SdrSever::GetStartData((CONFIG_YADECAP_MBUFS_BURST_SIZE + 1) * sizeof(uint64_t), metadata.size); + metadata.start_stats = common::sdp::SdrSever::GetStartData(sizeof(common::worker::stats::common), metadata.size); + metadata.start_stats_ports = common::sdp::SdrSever::GetStartData(sizeof(common::worker::stats::port[CONFIG_YADECAP_PORTS_SIZE]), metadata.size); + + // stats + std::map counters_stats; + counters_stats["brokenPackets"] = offsetof(common::worker::stats::common, brokenPackets); + counters_stats["dropPackets"] = offsetof(common::worker::stats::common, dropPackets); + counters_stats["ring_highPriority_drops"] = offsetof(common::worker::stats::common, ring_highPriority_drops); + counters_stats["ring_normalPriority_drops"] = offsetof(common::worker::stats::common, ring_normalPriority_drops); + counters_stats["ring_lowPriority_drops"] = offsetof(common::worker::stats::common, ring_lowPriority_drops); + counters_stats["ring_highPriority_packets"] = offsetof(common::worker::stats::common, ring_highPriority_packets); + counters_stats["ring_normalPriority_packets"] = offsetof(common::worker::stats::common, ring_normalPriority_packets); + counters_stats["ring_lowPriority_packets"] = offsetof(common::worker::stats::common, ring_lowPriority_packets); + counters_stats["decap_packets"] = offsetof(common::worker::stats::common, decap_packets); + counters_stats["decap_fragments"] = offsetof(common::worker::stats::common, decap_fragments); + counters_stats["decap_unknownExtensions"] = offsetof(common::worker::stats::common, decap_unknownExtensions); + counters_stats["interface_lookupMisses"] = offsetof(common::worker::stats::common, interface_lookupMisses); + counters_stats["interface_hopLimits"] = offsetof(common::worker::stats::common, interface_hopLimits); + counters_stats["interface_neighbor_invalid"] = offsetof(common::worker::stats::common, interface_neighbor_invalid); + counters_stats["nat64stateless_ingressPackets"] = offsetof(common::worker::stats::common, nat64stateless_ingressPackets); + counters_stats["nat64stateless_ingressFragments"] = offsetof(common::worker::stats::common, nat64stateless_ingressFragments); + counters_stats["nat64stateless_ingressUnknownICMP"] = offsetof(common::worker::stats::common, nat64stateless_ingressUnknownICMP); + counters_stats["nat64stateless_egressPackets"] = offsetof(common::worker::stats::common, nat64stateless_egressPackets); + counters_stats["nat64stateless_egressFragments"] = offsetof(common::worker::stats::common, nat64stateless_egressFragments); + counters_stats["nat64stateless_egressUnknownICMP"] = offsetof(common::worker::stats::common, nat64stateless_egressUnknownICMP); + counters_stats["balancer_invalid_reals_count"] = offsetof(common::worker::stats::common, balancer_invalid_reals_count); + counters_stats["fwsync_multicast_egress_drops"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_drops); + counters_stats["fwsync_multicast_egress_packets"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_packets); + counters_stats["fwsync_multicast_egress_imm_packets"] = offsetof(common::worker::stats::common, fwsync_multicast_egress_imm_packets); + counters_stats["fwsync_no_config_drops"] = offsetof(common::worker::stats::common, fwsync_no_config_drops); + counters_stats["fwsync_unicast_egress_drops"] = offsetof(common::worker::stats::common, fwsync_unicast_egress_drops); + counters_stats["fwsync_unicast_egress_packets"] = offsetof(common::worker::stats::common, fwsync_unicast_egress_packets); + counters_stats["acl_ingress_dropPackets"] = offsetof(common::worker::stats::common, acl_ingress_dropPackets); + counters_stats["acl_egress_dropPackets"] = offsetof(common::worker::stats::common, acl_egress_dropPackets); + counters_stats["repeat_ttl"] = offsetof(common::worker::stats::common, repeat_ttl); + counters_stats["leakedMbufs"] = offsetof(common::worker::stats::common, leakedMbufs); + counters_stats["logs_packets"] = offsetof(common::worker::stats::common, logs_packets); + counters_stats["logs_drops"] = offsetof(common::worker::stats::common, logs_drops); + for (const auto& iter : counters_stats) + { + metadata.counter_positions[iter.first] = (metadata.start_stats + iter.second) / sizeof(uint64_t); + } + + // counters + std::map counters_named; + counters_named["balancer_state_insert_failed"] = common::globalBase::static_counter_type::balancer_state_insert_failed; + counters_named["balancer_state_insert_done"] = common::globalBase::static_counter_type::balancer_state_insert_done; + counters_named["balancer_icmp_generated_echo_reply_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv4; + counters_named["balancer_icmp_generated_echo_reply_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_generated_echo_reply_ipv6; + counters_named["balancer_icmp_drop_icmpv4_payload_too_short_ip"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_ip; + counters_named["balancer_icmp_drop_icmpv4_payload_too_short_port"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv4_payload_too_short_port; + counters_named["balancer_icmp_drop_icmpv6_payload_too_short_ip"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_ip; + counters_named["balancer_icmp_drop_icmpv6_payload_too_short_port"] = common::globalBase::static_counter_type::balancer_icmp_drop_icmpv6_payload_too_short_port; + counters_named["balancer_icmp_unmatching_src_from_original_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv4; + counters_named["balancer_icmp_unmatching_src_from_original_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_unmatching_src_from_original_ipv6; + counters_named["balancer_icmp_drop_real_disabled"] = common::globalBase::static_counter_type::balancer_icmp_drop_real_disabled; + counters_named["balancer_icmp_no_balancer_src_ipv4"] = common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv4; + counters_named["balancer_icmp_no_balancer_src_ipv6"] = common::globalBase::static_counter_type::balancer_icmp_no_balancer_src_ipv6; + counters_named["balancer_icmp_drop_already_cloned"] = common::globalBase::static_counter_type::balancer_icmp_drop_already_cloned; + counters_named["balancer_icmp_drop_no_unrdup_table_for_balancer_id"] = common::globalBase::static_counter_type::balancer_icmp_drop_no_unrdup_table_for_balancer_id; + counters_named["balancer_icmp_drop_unrdup_vip_not_found"] = common::globalBase::static_counter_type::balancer_icmp_drop_unrdup_vip_not_found; + counters_named["balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id"] = common::globalBase::static_counter_type::balancer_icmp_drop_no_vip_vport_proto_table_for_balancer_id; + counters_named["balancer_icmp_drop_unexpected_transport_protocol"] = common::globalBase::static_counter_type::balancer_icmp_drop_unexpected_transport_protocol; + counters_named["balancer_icmp_drop_unknown_service"] = common::globalBase::static_counter_type::balancer_icmp_drop_unknown_service; + counters_named["balancer_icmp_failed_to_clone"] = common::globalBase::static_counter_type::balancer_icmp_failed_to_clone; + counters_named["balancer_icmp_clone_forwarded"] = common::globalBase::static_counter_type::balancer_icmp_clone_forwarded; + counters_named["balancer_icmp_sent_to_real"] = common::globalBase::static_counter_type::balancer_icmp_sent_to_real; + counters_named["balancer_icmp_out_rate_limit_reached"] = common::globalBase::static_counter_type::balancer_icmp_out_rate_limit_reached; + counters_named["slow_worker_normal_priority_rate_limit_exceeded"] = common::globalBase::static_counter_type::slow_worker_normal_priority_rate_limit_exceeded; + + counters_named["acl_ingress_v4_broken_packet"] = common::globalBase::static_counter_type::acl_ingress_v4_broken_packet; + counters_named["acl_ingress_v6_broken_packet"] = common::globalBase::static_counter_type::acl_ingress_v6_broken_packet; + counters_named["acl_egress_v4_broken_packet"] = common::globalBase::static_counter_type::acl_egress_v4_broken_packet; + counters_named["acl_egress_v6_broken_packet"] = common::globalBase::static_counter_type::acl_egress_v6_broken_packet; + counters_named["balancer_fragment_drops"] = common::globalBase::static_counter_type::balancer_fragment_drops; + + for (const auto& iter : counters_named) + { + metadata.counter_positions[iter.first] = metadata.start_counters / sizeof(uint64_t) + static_cast(iter.second); + } +} + +void cWorker::SetBufferForCounters(void* buffer, const common::sdp::MetadataWorker& metadata) +{ + counters = common::sdp::ShiftBuffer(buffer, metadata.start_counters); + aclCounters = common::sdp::ShiftBuffer(buffer, metadata.start_acl_counters); + bursts = common::sdp::ShiftBuffer(buffer, metadata.start_bursts); + stats = common::sdp::ShiftBuffer(buffer, metadata.start_stats); + statsPorts = common::sdp::ShiftBuffer(buffer, metadata.start_stats_ports); } eResult cWorker::sanityCheck() @@ -453,7 +481,7 @@ void cWorker::preparePacket(rte_mbuf* mbuf) // will traverse through ipv4 options/ipv6 extensions and try to determine transport header type and offset if (!prepareL3(mbuf, metadata)) { - stats.brokenPackets++; + stats->brokenPackets++; return; } @@ -475,7 +503,7 @@ void cWorker::preparePacket(rte_mbuf* mbuf) if ((!(metadata->network_flags & YANET_NETWORK_FLAG_NOT_FIRST_FRAGMENT)) && network_payload_length < basePermanently.transportSizes[metadata->transport_headerType]) { - stats.brokenPackets++; + stats->brokenPackets++; metadata->transport_headerType = YANET_TRANSPORT_TYPE_UNKNOWN; return; } @@ -1309,7 +1337,7 @@ inline void cWorker::logicalPort_egress_handle() } if (rte_mbuf_refcnt_read(mbuf) < 1) { - stats.leakedMbufs++; + stats->leakedMbufs++; #ifdef CONFIG_YADECAP_AUTOTEST YADECAP_LOG_ERROR("mbuf[%p] is broken\n", mbuf); @@ -1766,7 +1794,7 @@ inline void cWorker::acl_ingress_flow(rte_mbuf* mbuf, } else { - stats.acl_ingress_dropPackets++; ///< @todo + stats->acl_ingress_dropPackets++; ///< @todo drop(mbuf); } } @@ -1977,7 +2005,7 @@ inline void cWorker::decap_handle() mark_ipv4_dscp(mbuf, decap.ipv4DSCPFlags); } - stats.decap_packets++; + stats->decap_packets++; decap_flow(mbuf, decap.flow); } @@ -2019,7 +2047,7 @@ inline bool cWorker::decap_cut(rte_mbuf* mbuf) const rte_gre_hdr* greHeader = rte_pktmbuf_mtod_offset(mbuf, rte_gre_hdr*, metadata->transport_headerOffset); if (((*(uint32_t*)greHeader) & 0xFFFFFF4F) != 0x00080000) ///< |X|0|X|X|0|0|0x0800|. @todo: ACL_GRE { - stats.decap_unknownExtensions++; + stats->decap_unknownExtensions++; return false; } @@ -2061,7 +2089,7 @@ inline bool cWorker::decap_cut(rte_mbuf* mbuf) return true; } - stats.decap_unknownExtensions++; + stats->decap_unknownExtensions++; return false; } @@ -2120,7 +2148,7 @@ inline void cWorker::route_handle4() if (route_ipv4_values[mbuf_i] == dataplane::lpmValueIdInvalid) { - stats.interface_lookupMisses++; + stats->interface_lookupMisses++; rte_pktmbuf_free(mbuf); continue; } @@ -2134,7 +2162,7 @@ inline void cWorker::route_handle4() rte_ipv4_hdr* ipv4Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv4_hdr*, metadata->network_headerOffset); if (ipv4Header->time_to_live <= 1) { - stats.interface_hopLimits++; + stats->interface_hopLimits++; drop(mbuf); continue; } @@ -2167,7 +2195,7 @@ inline void cWorker::route_handle4() } else { - stats.interface_neighbor_invalid++; + stats->interface_neighbor_invalid++; drop(mbuf); neighbor_resolve.insert_or_update(key, 0); @@ -2194,7 +2222,7 @@ inline void cWorker::route_handle4() metadata->repeat_ttl--; if (metadata->repeat_ttl == 0) { - stats.repeat_ttl++; + stats->repeat_ttl++; rte_pktmbuf_free(mbuf); } else @@ -2245,7 +2273,7 @@ inline void cWorker::route_handle6() if (route_ipv6_values[mbuf_i] == dataplane::lpmValueIdInvalid) { - stats.interface_lookupMisses++; + stats->interface_lookupMisses++; rte_pktmbuf_free(mbuf); continue; } @@ -2259,7 +2287,7 @@ inline void cWorker::route_handle6() rte_ipv6_hdr* ipv6Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); if (ipv6Header->hop_limits <= 1) { - stats.interface_hopLimits++; + stats->interface_hopLimits++; drop(mbuf); continue; } @@ -2288,7 +2316,7 @@ inline void cWorker::route_handle6() } else { - stats.interface_neighbor_invalid++; + stats->interface_neighbor_invalid++; drop(mbuf); neighbor_resolve.insert_or_update(key, 0); @@ -2313,7 +2341,7 @@ inline void cWorker::route_handle6() metadata->repeat_ttl--; if (metadata->repeat_ttl == 0) { - stats.repeat_ttl++; + stats->repeat_ttl++; rte_pktmbuf_free(mbuf); } else @@ -2451,7 +2479,7 @@ inline void cWorker::route_tunnel_handle4() if (route_ipv4_values[mbuf_i] == dataplane::lpmValueIdInvalid) { - stats.interface_lookupMisses++; + stats->interface_lookupMisses++; rte_pktmbuf_free(mbuf); continue; } @@ -2467,7 +2495,7 @@ inline void cWorker::route_tunnel_handle4() rte_ipv4_hdr* ipv4Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv4_hdr*, metadata->network_headerOffset); if (ipv4Header->time_to_live <= 1) { - stats.interface_hopLimits++; + stats->interface_hopLimits++; drop(mbuf); continue; } @@ -2500,7 +2528,7 @@ inline void cWorker::route_tunnel_handle4() } else { - stats.interface_neighbor_invalid++; + stats->interface_neighbor_invalid++; drop(mbuf); neighbor_resolve.insert_or_update(key, 0); @@ -2530,7 +2558,7 @@ inline void cWorker::route_tunnel_handle4() metadata->repeat_ttl--; if (metadata->repeat_ttl == 0) { - stats.repeat_ttl++; + stats->repeat_ttl++; rte_pktmbuf_free(mbuf); } else @@ -2582,7 +2610,7 @@ inline void cWorker::route_tunnel_handle6() if (route_ipv6_values[mbuf_i] == dataplane::lpmValueIdInvalid) { - stats.interface_lookupMisses++; + stats->interface_lookupMisses++; rte_pktmbuf_free(mbuf); continue; } @@ -2598,7 +2626,7 @@ inline void cWorker::route_tunnel_handle6() rte_ipv6_hdr* ipv6Header = rte_pktmbuf_mtod_offset(mbuf, rte_ipv6_hdr*, metadata->network_headerOffset); if (ipv6Header->hop_limits <= 1) { - stats.interface_hopLimits++; + stats->interface_hopLimits++; drop(mbuf); continue; } @@ -2627,7 +2655,7 @@ inline void cWorker::route_tunnel_handle6() } else { - stats.interface_neighbor_invalid++; + stats->interface_neighbor_invalid++; drop(mbuf); neighbor_resolve.insert_or_update(key, 0); @@ -2655,7 +2683,7 @@ inline void cWorker::route_tunnel_handle6() metadata->repeat_ttl--; if (metadata->repeat_ttl == 0) { - stats.repeat_ttl++; + stats->repeat_ttl++; rte_pktmbuf_free(mbuf); } else @@ -3371,7 +3399,7 @@ inline void cWorker::nat64stateless_ingress_handle() nat64stateless_ingress_translation(mbuf, nat64stateless, translation); - stats.nat64stateless_ingressPackets++; + stats->nat64stateless_ingressPackets++; nat64stateless_ingress_flow(mbuf, nat64stateless.flow); } @@ -3490,7 +3518,7 @@ inline void cWorker::nat64stateless_egress_handle() nat64stateless_egress_translation(mbuf, translation); - stats.nat64stateless_egressPackets++; + stats->nat64stateless_egressPackets++; nat64stateless_egress_flow(mbuf, nat64stateless.flow); } @@ -4085,7 +4113,7 @@ inline void cWorker::balancer_handle() { locker->unlock(); - stats.balancer_invalid_reals_count++; + stats->balancer_invalid_reals_count++; drop(mbuf); continue; } @@ -4895,7 +4923,7 @@ inline void cWorker::acl_create_state(rte_mbuf* mbuf, tAclId aclId, const common if (base.globalBase->fw_state_sync_configs[aclId].flows_size == 0) { // No fw state synchronization configured. - stats.fwsync_no_config_drops++; + stats->fwsync_no_config_drops++; return; } @@ -4992,7 +5020,7 @@ inline void cWorker::acl_create_state(rte_mbuf* mbuf, tAclId aclId, const common if (base.globalBase->fw_state_sync_configs[aclId].flows_size == 0) { // No fw state synchronization configured. - stats.fwsync_no_config_drops++; + stats->fwsync_no_config_drops++; return; } @@ -5010,7 +5038,7 @@ inline void cWorker::acl_state_emit(tAclId aclId, const dataplane::globalBase::f rte_mbuf* mbuf = rte_pktmbuf_alloc(mempool); if (mbuf == nullptr) { - stats.fwsync_multicast_egress_drops++; + stats->fwsync_multicast_egress_drops++; return; } @@ -5030,7 +5058,7 @@ inline void cWorker::acl_state_emit(tAclId aclId, const dataplane::globalBase::f // Push packet to the ring through stack. metadata->flow.type = common::globalBase::eFlowType::slowWorker_fw_sync; controlPlane_stack.insert(mbuf); - stats.fwsync_multicast_egress_imm_packets++; + stats->fwsync_multicast_egress_imm_packets++; } inline void cWorker::acl_egress_entry(rte_mbuf* mbuf, tAclId aclId) @@ -5350,7 +5378,7 @@ void cWorker::acl_log(rte_mbuf* mbuf, const common::globalBase::tFlow& flow, tAc { if (rte_ring_full(ring_log)) { - stats.logs_drops++; + stats->logs_drops++; return; } @@ -5360,7 +5388,7 @@ void cWorker::acl_log(rte_mbuf* mbuf, const common::globalBase::tFlow& flow, tAc samples::sample_t* sample; if (rte_mempool_get(dataPlane->mempool_log, (void**)&sample) != 0) { - stats.logs_drops++; + stats->logs_drops++; return; } @@ -5380,7 +5408,7 @@ void cWorker::acl_log(rte_mbuf* mbuf, const common::globalBase::tFlow& flow, tAc } else { - stats.logs_drops++; + stats->logs_drops++; rte_mempool_put(dataPlane->mempool_log, sample); return; } @@ -5414,11 +5442,11 @@ void cWorker::acl_log(rte_mbuf* mbuf, const common::globalBase::tFlow& flow, tAc if (rte_ring_enqueue(ring_log, sample) != 0) { - stats.logs_drops++; + stats->logs_drops++; rte_mempool_put(dataPlane->mempool_log, sample); return; } - stats.logs_packets++; + stats->logs_packets++; } inline cWorker::FlowFromState cWorker::acl_egress_checkstate(rte_mbuf* mbuf) @@ -5538,12 +5566,12 @@ inline void cWorker::acl_egress_flow(rte_mbuf* mbuf, const common::globalBase::t if (flow.type == common::globalBase::eFlowType::controlPlane) { - stats.acl_egress_dropPackets++; + stats->acl_egress_dropPackets++; controlPlane(mbuf); } else if (flow.type == common::globalBase::eFlowType::drop) { - stats.acl_egress_dropPackets++; + stats->acl_egress_dropPackets++; drop(mbuf); } else if (metadata->flow.type == common::globalBase::eFlowType::logicalPort_egress || metadata->flow.type == common::globalBase::eFlowType::acl_egress) @@ -5615,18 +5643,18 @@ inline void cWorker::controlPlane_handle() mbuf_i++) { rte_mbuf* mbuf = controlPlane_stack.mbufs[mbuf_i]; - stats.ring_normalPriority_drops++; + stats->ring_normalPriority_drops++; rte_pktmbuf_free(mbuf); } - stats.ring_normalPriority_packets += count; + stats->ring_normalPriority_packets += count; controlPlane_stack.clear(); } inline void cWorker::drop(rte_mbuf* mbuf) { - stats.dropPackets++; + stats->dropPackets++; dataplane::metadata* metadata = YADECAP_METADATA(mbuf); if (basePermanently.globalBaseAtomic->physicalPort_flags[metadata->fromPortId] & YANET_PHYSICALPORT_FLAG_DROP_DUMP) @@ -5681,12 +5709,12 @@ inline void cWorker::slowWorker_entry_highPriority(rte_mbuf* mbuf, if (rte_ring_sp_enqueue(ring_highPriority, (void*)mbuf)) { - stats.ring_highPriority_drops++; + stats->ring_highPriority_drops++; rte_pktmbuf_free(mbuf); } else { - stats.ring_highPriority_packets++; + stats->ring_highPriority_packets++; } } @@ -5708,12 +5736,12 @@ inline void cWorker::slowWorker_entry_normalPriority(rte_mbuf* mbuf, if (rte_ring_sp_enqueue(ring_normalPriority, (void*)mbuf)) { - stats.ring_normalPriority_drops++; + stats->ring_normalPriority_drops++; rte_pktmbuf_free(mbuf); } else { - stats.ring_normalPriority_packets++; + stats->ring_normalPriority_packets++; } } @@ -5723,12 +5751,12 @@ inline void cWorker::slowWorker_entry_lowPriority(rte_mbuf* mbuf) if (rte_ring_sp_enqueue(ring_lowPriority, (void*)mbuf)) { - stats.ring_lowPriority_drops++; + stats->ring_lowPriority_drops++; rte_pktmbuf_free(mbuf); } else { - stats.ring_lowPriority_packets++; + stats->ring_lowPriority_packets++; } } @@ -5866,7 +5894,7 @@ YANET_NEVER_INLINE void cWorker::slowWorkerFarmHandleFragment(rte_mbuf* mbuf) metadata->repeat_ttl--; if (metadata->repeat_ttl == 0) { - stats.repeat_ttl++; + stats->repeat_ttl++; rte_pktmbuf_free(mbuf); return; } diff --git a/dataplane/worker.h b/dataplane/worker.h index a11c017b..8595206c 100644 --- a/dataplane/worker.h +++ b/dataplane/worker.h @@ -16,6 +16,7 @@ #include "common.h" #include "globalbase.h" #include "samples.h" +#include "sdpserver.h" #include "sharedmemory.h" namespace dataplane @@ -69,7 +70,8 @@ class cWorker eResult init(const tCoreId& coreId, const dataplane::base::permanently& basePermanently, const dataplane::base::generation& base); void start(); - void fillStatsNamesToAddrsTable(std::unordered_map& table); + static void FillMetadataWorkerCounters(common::sdp::MetadataWorker& metadata); + void SetBufferForCounters(void* buffer, const common::sdp::MetadataWorker& metadata); const dataplane::base::generation& current_base() const { return bases[localBaseId & 1]; } @@ -340,16 +342,16 @@ class cWorker rte_ring* ring_lowPriority; dataplane::perf::tsc_deltas* tsc_deltas; rte_ring* ring_toFreePackets; - common::worker::stats::common& Stats() { return stats; } + common::worker::stats::common& Stats() { return *stats; } protected: rte_ring* ring_log; - common::worker::stats::common stats; - common::worker::stats::port statsPorts[CONFIG_YADECAP_PORTS_SIZE]; - uint64_t bursts[CONFIG_YADECAP_MBUFS_BURST_SIZE + 1]; - uint64_t counters[YANET_CONFIG_COUNTERS_SIZE]; - uint64_t aclCounters[YANET_CONFIG_ACL_COUNTERS_SIZE]; + common::worker::stats::common* stats; + common::worker::stats::port* statsPorts; // CONFIG_YADECAP_PORTS_SIZE + uint64_t* bursts; // CONFIG_YADECAP_MBUFS_BURST_SIZE + 1 + uint64_t* counters; // YANET_CONFIG_COUNTERS_SIZE + uint64_t* aclCounters; // YANET_CONFIG_ACL_COUNTERS_SIZE // will decrease with each new packet sent to slow worker, replenishes each N mseconds int32_t packetsToSWNPRemainder; diff --git a/dataplane/worker_gc.cpp b/dataplane/worker_gc.cpp index 92849dee..832f18cb 100644 --- a/dataplane/worker_gc.cpp +++ b/dataplane/worker_gc.cpp @@ -24,7 +24,6 @@ worker_gc_t::worker_gc_t(const ConfigValues& cfg, const PortToSocketArray& pts, gc_step{static_cast(cfg.gc_step)}, sample_gc_step{static_cast(cfg.sample_gc_step)} { - memset(counters, 0, sizeof(counters)); } worker_gc_t::~worker_gc_t() @@ -154,19 +153,37 @@ void worker_gc_t::limits(common::idp::limits::response& response) const globalbase_atomic->updater.fw6_state.limits(response, "acl.state.v6.ht"); } -void worker_gc_t::fillStatsNamesToAddrsTable(std::unordered_map& table) +void worker_gc_t::FillMetadataWorkerCounters(common::sdp::MetadataWorkerGc& metadata) { - table["broken_packets"] = &stats.broken_packets; - table["drop_packets"] = &stats.drop_packets; - table["ring_to_slowworker_packets"] = &stats.ring_to_slowworker_packets; - table["ring_to_slowworker_drops"] = &stats.ring_to_slowworker_drops; - table["fwsync_multicast_egress_packets"] = &stats.fwsync_multicast_egress_packets; - table["fwsync_multicast_egress_drops"] = &stats.fwsync_multicast_egress_drops; - table["fwsync_unicast_egress_packets"] = &stats.fwsync_unicast_egress_packets; - table["fwsync_unicast_egress_drops"] = &stats.fwsync_unicast_egress_drops; - table["drop_samples"] = &stats.drop_samples; - table["balancer_state_insert_failed"] = &stats.balancer_state_insert_failed; - table["balancer_state_insert_done"] = &stats.balancer_state_insert_done; + metadata.size = 0; + metadata.start_counters = common::sdp::SdrSever::GetStartData(YANET_CONFIG_COUNTERS_SIZE * sizeof(uint64_t), metadata.size); + metadata.start_stats = common::sdp::SdrSever::GetStartData(sizeof(common::worker_gc::stats_t), metadata.size); + + // stats + static_assert(std::is_trivially_destructible::value, "invalid struct destructible"); + std::map counters_stats; + counters_stats["broken_packets"] = offsetof(common::worker_gc::stats_t, broken_packets); + counters_stats["drop_packets"] = offsetof(common::worker_gc::stats_t, drop_packets); + counters_stats["ring_to_slowworker_packets"] = offsetof(common::worker_gc::stats_t, ring_to_slowworker_packets); + counters_stats["ring_to_slowworker_drops"] = offsetof(common::worker_gc::stats_t, ring_to_slowworker_drops); + counters_stats["fwsync_multicast_egress_packets"] = offsetof(common::worker_gc::stats_t, fwsync_multicast_egress_packets); + counters_stats["fwsync_multicast_egress_drops"] = offsetof(common::worker_gc::stats_t, fwsync_multicast_egress_drops); + counters_stats["fwsync_unicast_egress_packets"] = offsetof(common::worker_gc::stats_t, fwsync_unicast_egress_packets); + counters_stats["fwsync_unicast_egress_drops"] = offsetof(common::worker_gc::stats_t, fwsync_unicast_egress_drops); + counters_stats["drop_samples"] = offsetof(common::worker_gc::stats_t, drop_samples); + counters_stats["balancer_state_insert_failed"] = offsetof(common::worker_gc::stats_t, balancer_state_insert_failed); + counters_stats["balancer_state_insert_done"] = offsetof(common::worker_gc::stats_t, balancer_state_insert_done); + + for (const auto& iter : counters_stats) + { + metadata.counter_positions[iter.first] = (metadata.start_stats + iter.second) / sizeof(uint64_t); + } +} + +void worker_gc_t::SetBufferForCounters(void* buffer, const common::sdp::MetadataWorkerGc& metadata) +{ + counters = common::sdp::ShiftBuffer(buffer, metadata.start_counters); + stats = common::sdp::ShiftBuffer(buffer, metadata.start_stats); } YANET_INLINE_NEVER void worker_gc_t::thread() @@ -452,7 +469,7 @@ void worker_gc_t::handle_balancer_gc() if (saved) { - stats.balancer_state_insert_done++; + stats->balancer_state_insert_done++; const auto& real_from_base = base.globalBase->balancer_reals[value.real_unordered_id]; if (updated) { @@ -470,7 +487,7 @@ void worker_gc_t::handle_balancer_gc() } else { - stats.balancer_state_insert_failed++; + stats->balancer_state_insert_failed++; } } @@ -812,7 +829,7 @@ void worker_gc_t::handle_acl_sync() rte_mbuf* mbuf_clone = rte_pktmbuf_alloc(mempool); if (mbuf_clone == nullptr) { - stats.fwsync_multicast_egress_drops++; + stats->fwsync_multicast_egress_drops++; continue; } @@ -824,7 +841,7 @@ void worker_gc_t::handle_acl_sync() mbuf_clone->data_len = mbuf->data_len; mbuf_clone->pkt_len = mbuf->pkt_len; - stats.fwsync_multicast_egress_packets++; + stats->fwsync_multicast_egress_packets++; utils::SetFlow(mbuf_clone, flow); SendToSlowWorker(mbuf_clone); } @@ -841,7 +858,7 @@ void worker_gc_t::handle_acl_sync() rte_mbuf* mbuf_clone = rte_pktmbuf_alloc(mempool); if (mbuf_clone == nullptr) { - stats.fwsync_unicast_egress_drops++; + stats->fwsync_unicast_egress_drops++; } else { @@ -853,7 +870,7 @@ void worker_gc_t::handle_acl_sync() mbuf_clone->data_len = mbuf->data_len; mbuf_clone->pkt_len = mbuf->pkt_len; - stats.fwsync_unicast_egress_packets++; + stats->fwsync_unicast_egress_packets++; utils::SetFlow(mbuf_clone, fw_state_config.ingress_flow); SendToSlowWorker(mbuf_clone); } @@ -969,12 +986,12 @@ void worker_gc_t::SendToSlowWorker(rte_mbuf* mbuf) { if (toSlowWorker_->EnqueueSP(mbuf)) { - stats.ring_to_slowworker_drops++; + stats->ring_to_slowworker_drops++; rte_pktmbuf_free(mbuf); } else { - stats.ring_to_slowworker_packets++; + stats->ring_to_slowworker_packets++; } } @@ -996,7 +1013,7 @@ void worker_gc_t::handle_samples() } else { - stats.drop_samples++; + stats->drop_samples++; } }); sampler->visit4([this](auto& sample) { @@ -1006,7 +1023,7 @@ void worker_gc_t::handle_samples() } else { - stats.drop_samples++; + stats->drop_samples++; } }); sampler->clear(); @@ -1015,7 +1032,7 @@ void worker_gc_t::handle_samples() if (samples_current_base_id != current_base_id) { // config changed, aclId may be invalid now - stats.drop_samples += samples.size(); + stats->drop_samples += samples.size(); samples.clear(); samples_current_base_id = current_base_id; } diff --git a/dataplane/worker_gc.h b/dataplane/worker_gc.h index 02e16cfd..a74c56c9 100644 --- a/dataplane/worker_gc.h +++ b/dataplane/worker_gc.h @@ -12,6 +12,7 @@ #include "common/idp.h" #include "common/static_vector.h" #include "hashtable.h" +#include "sdpserver.h" class worker_gc_t { @@ -30,7 +31,8 @@ class worker_gc_t void limits(common::idp::limits::response& response) const; - void fillStatsNamesToAddrsTable(std::unordered_map& table); + static void FillMetadataWorkerCounters(common::sdp::MetadataWorkerGc& metadata); + void SetBufferForCounters(void* buffer, const common::sdp::MetadataWorkerGc& metadata); protected: YANET_INLINE_NEVER void thread(); @@ -64,7 +66,7 @@ class worker_gc_t uint32_t current_base_id; uint32_t local_base_id; dataplane::base::permanently base_permanently; - common::worker_gc::stats_t stats; + common::worker_gc::stats_t* stats; dataplane::base::generation bases[2]; YADECAP_CACHE_ALIGNED(align1); @@ -101,7 +103,7 @@ class worker_gc_t generation_manager balancer_real_connections; generation_manager balancer_state_stats; - uint64_t counters[YANET_CONFIG_COUNTERS_SIZE]; + uint64_t* counters; // YANET_CONFIG_COUNTERS_SIZE uint32_t current_time; dataplane::hashtable_gc_t nat64stateful_lan_state_gc; diff --git a/meson.build b/meson.build index a77af658..29fd6af9 100644 --- a/meson.build +++ b/meson.build @@ -37,6 +37,8 @@ add_global_arguments(compiler_args, language: 'cpp') add_global_arguments('-DGOOGLE_PROTOBUF_NO_RTTI', language: 'cpp') +add_project_link_arguments('-lnuma', language : 'cpp') + add_global_arguments('-Wno-unused-parameter', language: 'cpp') if target_option.contains('librib')