diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index a884deb1..f4db89f5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -14,7 +14,7 @@ jobs: - name: Run clang-format style check uses: jidicula/clang-format-action@v4.11.0 with: - clang-format-version: '10' + clang-format-version: '18' exclude-regex: .*\.proto build-unittest: diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index 4f38664a..5a3cef86 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include #include #include #include @@ -11,14 +11,17 @@ #include #include -#include #include +#include #include #include "autotest.h" #include "common.h" +#include "common/sdpclient.h" +#include "common/utils.h" + #define MAX_PACK_LEN 16384 #define SOCK_DEV_PREFIX "sock_dev:" @@ -56,15 +59,11 @@ tAutotest::tAutotest() : ::testing::GTEST_FLAG(throw_on_failure) = true; } -tAutotest::~tAutotest() -{ -} - eResult tAutotest::init(const std::string& binaryPath, bool dumpPackets, const std::vector& configFilePaths) { - (void)binaryPath; + YANET_GCC_BUG_UNUSED(binaryPath); this->dumpPackets = dumpPackets; this->configFilePaths = configFilePaths; @@ -126,9 +125,9 @@ eResult tAutotest::initSharedMemory() dataPlaneSharedMemory = dataPlane.get_shm_info(); std::map shm_by_key; - key_t ipcKey; - int shmid; - void* shmaddr; + key_t ipcKey = 0; + int shmid = 0; + void* shmaddr = nullptr; for (const auto& shmInfo : dataPlaneSharedMemory) { @@ -141,10 +140,10 @@ eResult tAutotest::initSharedMemory() return eResult::errorInitSharedMemory; } - shmaddr = shmat(shmid, NULL, 0); + shmaddr = shmat(shmid, nullptr, 0); if (shmaddr == (void*)-1) { - YANET_LOG_ERROR("shmat(%d, NULL, 0) = %d\n", shmid, errno); + YANET_LOG_ERROR("shmat(%d, nullptr, 0) = %d\n", shmid, errno); return eResult::errorInitSharedMemory; } @@ -240,8 +239,8 @@ void tAutotest::sendThread(std::string interfaceName, throw ""; } - pcap_pkthdr* header; - const u_char* data; + pcap_pkthdr* header = nullptr; + const u_char* data = nullptr; static u_char zeros[MAX_PACK_LEN]; auto iface = pcaps[interfaceName]; @@ -411,10 +410,10 @@ class TextDumper class PcapDumper { public: - PcapDumper(const std::string& path, int capsize = MAX_PACK_LEN) : - tmpFilePath(path) + PcapDumper(std::string path, int capsize = MAX_PACK_LEN) : + tmpFilePath(std::move(path)), pcap(pcap_open_dead(DLT_EN10MB, capsize)) { - pcap = pcap_open_dead(DLT_EN10MB, capsize); + if (!pcap) { YANET_LOG_ERROR("error: pcap_open_dead()\n"); @@ -441,7 +440,7 @@ class PcapDumper pcap_dump((u_char*)dumper, header, data); } - std::string path() const + [[nodiscard]] std::string path() const { return tmpFilePath; } @@ -479,7 +478,7 @@ class pcap_expectation { public: pcap_expectation(std::string filename) : - filename(filename), has_packet(true), packetsCount(0), buffer(MAX_PACK_LEN, 0) + filename(filename), buffer(MAX_PACK_LEN, 0) { char pcap_errbuf[PCAP_ERRBUF_SIZE]; pcap = pcap_open_offline(filename.c_str(), pcap_errbuf); @@ -509,8 +508,8 @@ class pcap_expectation { return; } - pcap_pkthdr* h = 0; - const u_char* data = 0; + pcap_pkthdr* h = nullptr; + const u_char* data = nullptr; if (pcap_next_ex(pcap, &h, &data) >= 0) { memcpy(&header, h, sizeof(struct pcap_pkthdr)); @@ -529,7 +528,7 @@ class pcap_expectation } } - bool has_unmatched_packets() const + [[nodiscard]] bool has_unmatched_packets() const { return has_packet; } @@ -541,22 +540,22 @@ class pcap_expectation !memcmp(buffer.data(), packet, packetSize); } - std::string location() const + [[nodiscard]] std::string location() const { return filename + ":" + std::to_string(packetsCount); } - int expected_len() const + [[nodiscard]] int expected_len() const { return header.len; } - const u_char* begin() const + [[nodiscard]] const u_char* begin() const { return buffer.data(); } - const u_char* end() const + [[nodiscard]] const u_char* end() const { return buffer.data() + header.len; } @@ -571,9 +570,9 @@ class pcap_expectation private: std::string filename; - bool has_packet; + bool has_packet{true}; struct pcap_pkthdr header; - uint64_t packetsCount; + uint64_t packetsCount{}; pcap_t* pcap; std::vector buffer; }; @@ -720,7 +719,7 @@ void tAutotest::recvThread(std::string interfaceName, auto packetSize = tmp_pcap_packetHeader.len; YANET_LOG_DEBUG("unexpected %u\n", packetSize); - dumper.dump(NULL, NULL, buffer, buffer + packetSize); + dumper.dump(nullptr, nullptr, buffer, buffer + packetSize); } success = false; @@ -743,21 +742,6 @@ void tAutotest::recvThread(std::string interfaceName, unlink(pcapDumper.path().data()); } -std::vector split(const std::string& string, - char delimiter = ' ') -{ - std::vector result; - - std::stringstream stream(string); - std::string item; - while (std::getline(stream, item, delimiter)) - { - result.emplace_back(item); - } - - return result; -} - bool tAutotest::step_ipv4Update(const YAML::Node& yamlStep) { if (yamlStep.IsScalar()) @@ -873,10 +857,10 @@ bool tAutotest::step_checkCounters(const YAML::Node& yamlStep) auto fwList = controlPlane.getFwList(common::icp::getFwList::requestType::static_rules_original); for (auto& [ruleno, rules] : fwList) { - (void)ruleno; + YANET_GCC_BUG_UNUSED(ruleno); for (auto& [id, counter, text] : rules) { - (void)text; + YANET_GCC_BUG_UNUSED(text); counters[id] = counter; } } @@ -895,7 +879,7 @@ bool tAutotest::step_sendPackets(const YAML::Node& yamlStep, for (const auto& yamlPort : yamlStep) { - std::string interfaceName = yamlPort["port"].as(); + auto interfaceName = yamlPort["port"].as(); if (yamlPort["send"]) { @@ -1198,9 +1182,9 @@ bool tAutotest::step_rib_clear(const YAML::Node& yaml) if (yaml_attribute["peer"].IsDefined() && yaml_attribute["vrf"].IsDefined() && yaml_attribute["priority"].IsDefined()) { - std::string peer = yaml_attribute["peer"].as(); - std::string vrf = yaml_attribute["vrf"].as(); - uint32_t priority = yaml_attribute["priority"].as(); + auto peer = yaml_attribute["peer"].as(); + auto vrf = yaml_attribute["vrf"].as(); + auto priority = yaml_attribute["priority"].as(); std::tuple vrf_priority_tup(std::move(vrf), std::move(priority)); std::tuple> peer_vrf_priority_tup(std::move(peer), std::move(vrf_priority_tup)); @@ -1537,7 +1521,7 @@ void tAutotest::convert_ipv4Update(const std::string& string) convert_ipv4Remove(prefix); - for (const auto& nexthop : split(nexthops)) + for (const auto& nexthop : utils::split(nexthops, ' ')) { common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv4"][nexthop].emplace_back(prefix, @@ -1574,7 +1558,7 @@ void tAutotest::convert_ipv4LabelledUpdate(const std::string& string) convert_ipv4LabelledRemove(prefix); - for (const auto& nexthop_label : split(nexthops)) + for (const auto& nexthop_label : utils::split(nexthops, ' ')) { std::string nexthop = nexthop_label.substr(0, nexthop_label.find(":")); std::string label = nexthop_label.substr(nexthop_label.find(":") + 1); @@ -1618,7 +1602,7 @@ void tAutotest::convert_ipv6Update(const std::string& string) std::string prefix = string.substr(0, string.find(" -> ")); std::string nexthops = string.substr(string.find(" -> ") + 4); - for (const auto& nexthop : split(nexthops)) + for (const auto& nexthop : utils::split(nexthops, ' ')) { common::icp::rib_update::insert request = {"autotest", "default", YANET_RIB_PRIORITY_DEFAULT, {}}; std::get<3>(request)[attribute_default]["ipv6"][nexthop].emplace_back(prefix, @@ -1635,7 +1619,7 @@ void tAutotest::convert_ipv6LabelledUpdate(const std::string& string) std::string prefix = string.substr(0, string.find(" -> ")); std::string nexthops = string.substr(string.find(" -> ") + 4); - for (const auto& nexthop_label : split(nexthops)) + for (const auto& nexthop_label : utils::split(nexthops, ' ')) { std::string nexthop = nexthop_label.substr(0, nexthop_label.find("|")); std::string label = nexthop_label.substr(nexthop_label.find("|") + 1); @@ -1864,7 +1848,7 @@ std::string exec(const char* cmd) try { - while (fgets(buffer, sizeof buffer, pipe) != NULL) + while (fgets(buffer, sizeof buffer, pipe) != nullptr) { result += buffer; } @@ -1916,7 +1900,7 @@ common::bufferring::item_t* read_shm_packet(common::bufferring* buffer, uint64_t { return nullptr; } - common::bufferring::item_t* item = (common::bufferring::item_t*)((uintptr_t)buffer->ring->memory + (position * buffer->unit_size)); + auto* item = (common::bufferring::item_t*)((uintptr_t)buffer->ring->memory + (position * buffer->unit_size)); return item; } @@ -1926,11 +1910,11 @@ bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep, TextDumper dumper; for (const auto& yamlDump : yamlStep) { - std::string tag = yamlDump["ringTag"].as(); + auto tag = yamlDump["ringTag"].as(); std::string expectFilePath = path + "/" + yamlDump["expect"].as(); bool success = true; - common::bufferring* ring; + common::bufferring* ring = nullptr; { /// searching memory ring by tag auto it = dumpRings.find(tag); if (it == dumpRings.end()) @@ -1941,7 +1925,7 @@ bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep, ring = &it->second; } - pcap_t* pcap; + pcap_t* pcap = nullptr; { /// open pcap file with expected data char pcap_errbuf[PCAP_ERRBUF_SIZE]; pcap = pcap_open_offline(expectFilePath.data(), pcap_errbuf); @@ -1953,8 +1937,8 @@ bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep, } struct pcap_pkthdr header; - const u_char* pcap_packet; - common::bufferring::item_t* shm_packet; + const u_char* pcap_packet = nullptr; + common::bufferring::item_t* shm_packet = nullptr; uint64_t position = 0; /// read packets from pcap and compare them with packets from memory ring @@ -1998,7 +1982,7 @@ bool tAutotest::step_dumpPackets(const YAML::Node& yamlStep, if (dumpPackets) { YANET_LOG_DEBUG("dump [%s]: unexpected %u\n", tag.data(), shm_packet->header.size); - dumper.dump(NULL, NULL, shm_packet->memory, shm_packet->memory + header.len); + dumper.dump(nullptr, nullptr, shm_packet->memory, shm_packet->memory + header.len); } } @@ -2023,4 +2007,4 @@ void tAutotest::fflushSharedMemory() memset(memaddr, 0, size); } -} // namespace autotest \ No newline at end of file +} // namespace autotest diff --git a/autotest/autotest.h b/autotest/autotest.h index 873e9ef4..1725a16c 100644 --- a/autotest/autotest.h +++ b/autotest/autotest.h @@ -11,7 +11,7 @@ #include "common/icontrolplane.h" #include "common/idataplane.h" #include "common/result.h" -#include "common/sdpclient.h" +#include "common/sdpcommon.h" namespace nAutotest { @@ -36,7 +36,7 @@ class tAutotest { public: tAutotest(); - ~tAutotest(); + ~tAutotest() = default; eResult init(const std::string& binaryPath, bool dumpPackets, diff --git a/autotest/main.cpp b/autotest/main.cpp index eedeade2..f007132d 100644 --- a/autotest/main.cpp +++ b/autotest/main.cpp @@ -1,6 +1,4 @@ -#include - -#include +#include #include "common/result.h" @@ -45,7 +43,7 @@ int main(int argc, /** @todo if (signal(SIGINT, handleSignal) == SIG_ERR) { - return 3; + return 3; } */ diff --git a/cli/acl.h b/cli/acl.h index 7579300f..5f143e0f 100644 --- a/cli/acl.h +++ b/cli/acl.h @@ -1,8 +1,9 @@ #pragma once +#include "cli/helper.h" #include "common/icontrolplane.h" -#include "helper.h" +#include "table_printer.h" namespace acl { @@ -52,39 +53,21 @@ void unwind(const std::string& in_module, transport_flags, recordstate}); - table_t table({.optional_null = "any"}); - table.insert("module", - "direction", - "network_source", - "network_destination", - "fragment", - "protocol", - "transport_source", - "transport_destination", - "transport_flags", - "recordstate", - "next_module", - "ids", - "log"); - - for (const auto& [module, direction, network_source, network_destination, fragment, protocol, transport_source, transport_destination, transport_flags, recordstate, next_module, ids, log] : response) - { - table.insert(module, - direction, - network_source, - network_destination, - fragment, - protocol, - transport_source, - transport_destination, - transport_flags, - recordstate, - next_module, - ids, - log); - } - - table.print(); + FillAndPrintTable({"module", + "direction", + "network_source", + "network_destination", + "fragment", + "protocol", + "transport_source", + "transport_destination", + "transport_flags", + "recordstate", + "next_module", + "ids", + "log"}, + response, + {.optional_null = "any"}); } void lookup(std::optional module, @@ -113,19 +96,7 @@ void lookup(std::optional module, transport_source, transport_destination}); - table_t table; - table.insert("ruleno", - "label", - "rule"); - - for (const auto& [ruleno, label, rule] : response) - { - table.insert(ruleno, - label, - rule); - } - - table.print(); + FillAndPrintTable({"ruleno", "label", "rule"}, response); } } diff --git a/cli/balancer.h b/cli/balancer.h index 5ca6b260..5d7acd71 100644 --- a/cli/balancer.h +++ b/cli/balancer.h @@ -1,12 +1,12 @@ #pragma once +#include "cli/helper.h" #include "common/icontrolplane.h" -#include "common/icp_proto.h" #include "common/idataplane.h" #include "common/iproto_controlplane.h" #include "common/type.h" -#include "helper.h" +#include "table_printer.h" namespace balancer { @@ -16,25 +16,13 @@ void summary() interface::controlPlane controlPlane; const auto response = controlPlane.balancer_summary(); - table_t table; - table.insert("module", - "services", - "reals_enabled", - "reals", - "connections", - "next_module"); - - for (const auto& [module, services, reals_enabled, reals, connections, next_module] : response) - { - table.insert(module, - services, - reals_enabled, - reals, - connections, - next_module); - } - - table.print(); + FillAndPrintTable({"module", + "services", + "reals_enabled", + "reals", + "connections", + "next_module"}, + response); } void service(std::string module_string, @@ -67,16 +55,16 @@ void service(std::string module_string, interface::dataPlane dataplane; auto balancer_service_connections = dataplane.balancer_service_connections(); - table_t table; - table.insert("module", - "virtual_ip", - "proto", - "virtual_port", - "scheduler", - "connections", - "packets", - "bytes", - "version"); + TablePrinter table; + table.insert_row("module", + "virtual_ip", + "proto", + "virtual_port", + "scheduler", + "connections", + "packets", + "bytes", + "version"); for (const auto& [module, services] : response) { @@ -86,7 +74,7 @@ void service(std::string module_string, { const auto& [virtual_ip, proto, virtual_port] = service_key; const auto& [scheduler, version, nap_connections, packets, bytes] = service_value; - (void)nap_connections; ///< @todo: DELETE + YANET_GCC_BUG_UNUSED(nap_connections); ///< @todo: DELETE auto proto_string = controlplane::balancer::from_proto(proto); @@ -98,7 +86,7 @@ void service(std::string module_string, uint32_t connections = 0; for (auto& [socket_id, service_connections] : balancer_service_connections) { - (void)socket_id; + YANET_GCC_BUG_UNUSED(socket_id); const auto& socket_connections = service_connections[key].value; if (socket_connections > connections) @@ -107,19 +95,19 @@ void service(std::string module_string, } } - table.insert(module_name, - virtual_ip, - proto_string, - virtual_port, - scheduler, - connections, - packets, - bytes, - version); + table.insert_row(module_name, + virtual_ip, + proto_string, + virtual_port, + scheduler, + connections, + packets, + bytes, + version); } } - table.print(); + table.Print(); } inline void setip(common::icp_proto::IPAddr* pAddr, const common::ip_address_t& value) @@ -202,20 +190,20 @@ void real_find(std::string module_string, interface::dataPlane dataplane; auto balancer_real_connections = dataplane.balancer_real_connections(); - table_t table; - table.insert("module", - "virtual_ip", - "proto", - "virtual_port", - "scheduler", - "real_ip", - "real_port", - "enabled", - "weight", - "connections", - "packets", - "bytes", - "version"); + TablePrinter table; + table.insert_row("module", + "virtual_ip", + "proto", + "virtual_port", + "scheduler", + "real_ip", + "real_port", + "enabled", + "weight", + "connections", + "packets", + "bytes", + "version"); for (const auto& balancer : response.balancers()) { @@ -239,7 +227,7 @@ void real_find(std::string module_string, uint32_t connections = 0; for (auto& [socket_id, real_connections] : balancer_real_connections) { - (void)socket_id; + YANET_GCC_BUG_UNUSED(socket_id); const auto& socket_connections = real_connections[key].value; if (socket_connections > connections) @@ -248,24 +236,24 @@ void real_find(std::string module_string, } } - table.insert(balancer.module(), - virtual_ip, - proto_string, - service.key().port_opt_case() == common::icp_proto::BalancerRealFindResponse_ServiceKey::PortOptCase::kPort ? std::make_optional(service.key().port()) : std::nullopt, - service.scheduler(), - real_ip, - real.port_opt_case() == common::icp_proto::BalancerRealFindResponse_Real::PortOptCase::kPort ? std::make_optional(real.port()) : std::nullopt, - real.enabled(), - real.weight(), - connections, - real.packets(), - real.bytes(), - service.version_opt_case() == common::icp_proto::BalancerRealFindResponse_Service::VersionOptCase::kVersion ? std::make_optional(service.version()) : std::nullopt); + table.insert_row(balancer.module(), + virtual_ip, + proto_string, + service.key().port_opt_case() == common::icp_proto::BalancerRealFindResponse_ServiceKey::PortOptCase::kPort ? std::make_optional(service.key().port()) : std::nullopt, + service.scheduler(), + real_ip, + real.port_opt_case() == common::icp_proto::BalancerRealFindResponse_Real::PortOptCase::kPort ? std::make_optional(real.port()) : std::nullopt, + real.enabled(), + real.weight(), + connections, + real.packets(), + real.bytes(), + service.version_opt_case() == common::icp_proto::BalancerRealFindResponse_Service::VersionOptCase::kVersion ? std::make_optional(service.version()) : std::nullopt); } } } - table.print(); + table.Print(); } void state(std::string module, @@ -321,7 +309,7 @@ void state(std::string module, /// @todo: OPT for (const auto& [socket_id, services_real_connections] : response) { - (void)socket_id; + YANET_GCC_BUG_UNUSED(socket_id); for (const auto& [services_real, connections] : services_real_connections) { @@ -331,7 +319,7 @@ void state(std::string module, for (const auto& [client_ip, client_port, timestamp_create, timestamp_last_packet, timestamp_gc] : connections) { - (void)timestamp_gc; + YANET_GCC_BUG_UNUSED(timestamp_gc); auto it = map.find({client_ip, client_port}); if (it != map.end()) @@ -351,17 +339,17 @@ void state(std::string module, } } - table_t table; - table.insert("module", - "virtual_ip", - "proto", - "virtual_port", - "real_ip", - "real_port", - "client_ip", - "client_port", - "created", - "last_seen"); + TablePrinter table; + table.insert_row("module", + "virtual_ip", + "proto", + "virtual_port", + "real_ip", + "real_port", + "client_ip", + "client_port", + "created", + "last_seen"); uint32_t current_time = time(nullptr); @@ -388,22 +376,22 @@ void state(std::string module, const auto& [client_ip, client_port] = key; const auto& [timestamp_create, timestamp_last_packet] = value; - table.insert(module, - virtual_ip, - proto_string, - virtual_port, - real_ip, - real_port, - client_ip, - client_port, - (uint32_t)current_time - timestamp_create, - (uint16_t)current_time - timestamp_last_packet); + table.insert_row(module, + virtual_ip, + proto_string, + virtual_port, + real_ip, + real_port, + client_ip, + client_port, + (uint32_t)current_time - timestamp_create, + (uint16_t)current_time - timestamp_last_packet); } } } } - table.print(); + table.Print(); } namespace real @@ -490,17 +478,7 @@ void announce() interface::controlPlane controlPlane; const auto response = controlPlane.balancer_announce(); - table_t table; - table.insert("module", - "announces"); - - for (const auto& [module, announces] : response) - { - table.insert(module, - announces); - } - - table.print(); + FillAndPrintTable({"module", "announces"}, response); } } diff --git a/cli/bus.h b/cli/bus.h index e26c2456..ba8cefbb 100644 --- a/cli/bus.h +++ b/cli/bus.h @@ -2,6 +2,7 @@ #include "helper.h" #include "influxdb_format.h" +#include "table_printer.h" namespace bus { @@ -11,7 +12,7 @@ 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; + YANET_GCC_BUG_UNUSED(errors); std::map names = { {common::idp::requestType::updateGlobalBase, "updateGlobalBase"}, @@ -78,24 +79,24 @@ inline void bus_requests() OpenSharedMemoryDataplaneBuffers(sdp_data, false); auto requests = get_bus_requests(sdp_data); - table_t table; - table.insert("request", "count", "duration_ms"); + TablePrinter table; + table.insert_row("request", "count", "duration_ms"); for (const auto& [request, count, duration] : requests) { if ((count != 0) || (duration != 0)) { - table.insert(request, count, duration); + table.insert_row(request, count, duration); } } - table.print(); + 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; + YANET_GCC_BUG_UNUSED(requests); + YANET_GCC_BUG_UNUSED(durations); std::map names = { {common::idp::errorType::busRead, "busRead"}, @@ -119,14 +120,7 @@ inline void bus_errors() 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(); + FillAndPrintTable({"error", "count"}, errors); } inline void bus_telegraf() diff --git a/cli/config.cpp b/cli/config.cpp index 8d03d107..6e9aa403 100644 --- a/cli/config.cpp +++ b/cli/config.cpp @@ -139,16 +139,16 @@ bool allowPrefix(nlohmann::json& prefixes, } // check whether current announces includes announceRaw - for (auto announceIt = announces->begin(); announceIt != announces->end(); ++announceIt) + for (auto& announceIt : *announces) { // sanity check that announce has string type - if (!announceIt->is_string()) + if (!announceIt.is_string()) { throw std::string{"invalid type of prefix item announce. Should be string"}; } // announce already presented within the prefix - if (announceIt->get_ref() == announceRaw) + if (announceIt.get_ref() == announceRaw) { return false; } @@ -366,7 +366,7 @@ void allow(const std::string& module, checkModuleType(decap, "decap"); const auto& [prefixes, inserted] = decap.emplace("ipv6DestinationPrefixes", nlohmann::json::array_t{}); - (void)inserted; + YANET_GCC_BUG_UNUSED(inserted); if (allowPrefix(*prefixes, prefixRaw, announceRaw)) { @@ -436,7 +436,7 @@ static void allowAny(const std::string& module, checkModuleType(nat64, "nat64stateless"); const auto& [prefixes, inserted] = nat64.emplace("nat64_prefixes", nlohmann::json::array_t{}); - (void)inserted; + YANET_GCC_BUG_UNUSED(inserted); if (allowPrefix(*prefixes, prefixRaw, announceRaw)) { diff --git a/cli/convert.h b/cli/convert.h index 0c5795bb..a10fc6f1 100644 --- a/cli/convert.h +++ b/cli/convert.h @@ -2,6 +2,7 @@ #include "common/icontrolplane.h" #include "helper.h" +#include "table_printer.h" namespace convert { @@ -11,16 +12,7 @@ inline void logical_module() interface::controlPlane controlPlane; const auto response = controlPlane.convert("logical_module"); - table_t table; - table.insert("id", - "name"); - - for (const auto& [id, name] : response) - { - table.insert(id, name); - } - - table.print(); + FillAndPrintTable({"id", "name"}, response); } } /* namespace convert */ diff --git a/cli/converter.h b/cli/converter.h index 29043b32..b1db93eb 100644 --- a/cli/converter.h +++ b/cli/converter.h @@ -1,12 +1,13 @@ #pragma once -#include #include #include #include #include #include +#include "common/traits.h" + namespace converter { @@ -18,128 +19,73 @@ struct config_t std::string set_empty = "n/s"; }; -template -std::string to_string(const std::optional& value, const config_t config = {}); -template -std::string to_string(const std::variant& value, const config_t config = {}); -template -std::string to_string(const std::vector& vector, const config_t config = {}); -template -std::string to_string(const std::set& set, const config_t config = {}); -std::string to_string(const bool& value, const config_t config = {}); -std::string to_string(const std::string& string, const config_t config = {}); -template -std::string to_string(const arg_T& value, const config_t config = {}); - -template -std::string to_string(const std::optional& value, - const config_t config) +template +std::string to_string(const T& value, const config_t& config = {}) { - if (value) + if constexpr (std::is_same_v) { - return to_string(*value, config); + return value.empty() ? config.string_empty : value; } - else + else if constexpr (std::is_same_v) { - return config.optional_null; + return value.empty() ? config.string_empty : std::string(value); } -}; - -template -std::string to_string(const std::variant& value, - const config_t config) -{ - return std::visit([&config](const auto& value) -> std::string { return to_string(value, config); }, value); -}; - -template -std::string to_string(const std::vector& vector, - const config_t config) -{ - if (vector.empty()) + else if constexpr (std::is_constructible_v) { - return config.vector_empty; + return value; } - - bool first = true; - std::ostringstream result; - for (const auto& item : vector) + else if constexpr (std::is_same_v) { - if (!first) - { - result << ","; ///< @todo: config - } - - result << to_string(item, config); - first = false; + return value ? "true" : "false"; } - return result.str(); -} - -template -std::string to_string(const std::set& set, - const config_t config) -{ - if (set.empty()) + else if constexpr (std::is_arithmetic_v) { - return config.set_empty; + return std::to_string(value); } - - bool first = true; - std::ostringstream result; - for (const auto& item : set) + else if constexpr (traits::is_variant_v) { - if (!first) - { - result << ","; ///< @todo: config - } - - result << to_string(item, config); - first = false; + return std::visit([&config](const auto& val) { return to_string(val, config); }, value); } - return result.str(); -} - -std::string to_string(const bool& value, - const config_t config) -{ - (void)config; - if (value) + else if constexpr (traits::is_optional_v) { - return "true"; + return value ? to_string(*value, config) : config.optional_null; } - else + else if constexpr (traits::is_container_v) { - return "false"; - } -}; + if (value.empty()) + { + if constexpr (traits::is_vector_v) + { + return config.vector_empty; + } + else if constexpr (traits::is_set_v) + { + return config.set_empty; + } + else + { + static_assert(traits::always_false_v, + "Container does not have default empty representation in struct config_t"); + } + } -std::string to_string(const std::string& string, - const config_t config) -{ - if (string.empty()) - { - return config.string_empty; - } - else - { - return string; - } -}; + std::ostringstream oss; + auto it = std::begin(value); + oss << to_string(*it, config); + ++it; -template -std::string to_string(const arg_T& value, - const config_t config) -{ - (void)config; - if constexpr (std::is_constructible_v) - { - return value; + for (; it != std::end(value); ++it) + { + oss << ',' << to_string(*it, config); + } + + return oss.str(); } else { - return std::to_string(value); + static_assert(std::is_constructible_v, + "Type is not convertible to std::string and no overload of to_string is provided"); } -}; - } + +} // namespace converter diff --git a/cli/develop.h b/cli/develop.h index 46eba193..b9c3ca67 100644 --- a/cli/develop.h +++ b/cli/develop.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,198 +8,184 @@ #include #include -#include "common/icontrolplane.h" #include "common/idataplane.h" #include "common/sdpclient.h" +#include "common/shared_memory.h" #include "common/tsc_deltas.h" +#include "common/tuple.h" -#include "helper.h" +#include "table_printer.h" -namespace develop +namespace develop::dataplane { -namespace dataplane +static void printValue(const common::idp::value& value) { + const auto& [type, interface] = value; + std::ostringstream oss; + using common::globalBase::eNexthopType; -static inline void printValue(const common::idp::value& value) -{ - const auto& type = std::get<0>(value); - if (type == common::globalBase::eNexthopType::drop) - { - printf(" drop\n"); - } - else if (type == common::globalBase::eNexthopType::interface) + switch (type) { - for (const auto& iter : std::get<1>(value)) - { - if (std::get<0>(std::get<1>(iter)) != common::unlabelled) + case eNexthopType::drop: + oss << " drop\n"; + break; + case eNexthopType::interface: + for (const auto& [interfaceId, transport, service] : interface) { - if (std::get<0>(std::get<2>(iter)) != common::unlabelled) + const auto& [transport_label, transport_exp] = transport; + const auto& [service_label, service_exp] = service; + + if (transport_label != common::unlabelled) { - printf(" interfaceId: %u,\ttransport: [label: %u, exp: %u],\tservice: [label: %u, exp: %u]\n", - std::get<0>(iter), - std::get<0>(std::get<1>(iter)), - std::get<1>(std::get<1>(iter)), - std::get<0>(std::get<2>(iter)), - std::get<1>(std::get<2>(iter))); + if (service_label != common::unlabelled) + { + oss << " interfaceId: " << interfaceId + << ",\ttransport: [label: " << transport_label + << ", exp: " << transport_exp + << "],\tservice: [label: " << service_label + << ", exp: " << service_exp << "]\n"; + } + else + { + oss << " interfaceId: " << interfaceId + << ",\ttransport: [label: " << transport_label + << ", exp: " << transport_exp << "]\n"; + } } else { - printf(" interfaceId: %u,\ttransport: [label: %u, exp: %u]\n", - std::get<0>(iter), - std::get<0>(std::get<1>(iter)), - std::get<1>(std::get<1>(iter))); + oss << " interfaceId: " << interfaceId << "\n"; } } - else - { - printf(" interfaceId: %u\n", - std::get<0>(iter)); - } - } - } - else if (type == common::globalBase::eNexthopType::controlPlane) - { - printf(" controlPlane\n"); - } - else - { - printf(" error\n"); + break; + case eNexthopType::controlPlane: + oss << " controlPlane\n"; + break; + default: + oss << " error\n"; } + + std::cout << oss.str(); } -void lpm4LookupAddress(const common::ipv4_address_t& address) +template +static void lpmLookupAddress(const T& address) { interface::dataPlane dataPlane; - const auto response = dataPlane.lpm4LookupAddress(address); - for (const auto& iter : response) - { - const auto& socketId = iter.first; - const auto& found = std::get<0>(iter.second); - const auto& valueId = std::get<1>(iter.second); - const auto& value = std::get<2>(iter.second); - printf("[socketId: %u] %s -> ", socketId, common::ipv4_address_t(address).toString().data()); - if (found) + const auto& response = [&]() { + if constexpr (std::is_same_v) { - printf("valueId: %u\n", valueId); - printValue(value); + return dataPlane.lpm4LookupAddress(address); + } + else if constexpr (std::is_same_v) + { + return dataPlane.lpm6LookupAddress(address); } else { - printf("not found\n"); + static_assert(traits::always_false_v, + "lpmLookupAddress cannot be used with types other than ipv4/6_address"); } - } -} + }(); -void lpm6LookupAddress(const common::ipv6_address_t& ipv6Address) -{ - interface::dataPlane dataPlane; - const auto response = dataPlane.lpm6LookupAddress(ipv6Address); - for (const auto& iter : response) + for (const auto& [socketId, entry] : response) { - const auto& socketId = iter.first; - const auto& found = std::get<0>(iter.second); - const auto& valueId = std::get<1>(iter.second); - const auto& value = std::get<2>(iter.second); + const auto& [found, valueId, value] = entry; + std::cout << "[socketId: " << socketId << "] " << address.toString() << " -> "; - printf("[socketId: %u] %s -> ", socketId, common::ipv6_address_t(ipv6Address).toString().data()); if (found) { - printf("valueId: %u\n", valueId); + std::cout << "valueId: " << valueId << '\n'; printValue(value); } else { - printf("not found\n"); + std::cout << "not found\n"; } } } -void getErrors() +inline void lpm4LookupAddress(const common::ipv4_address_t& address) +{ + lpmLookupAddress(address); +} + +inline void lpm6LookupAddress(const common::ipv6_address_t& address) +{ + lpmLookupAddress(address); +} + +inline void getErrors() { interface::dataPlane dataPlane; - const auto response = dataPlane.getErrors(); - printf("errors:\n"); - for (const auto& iter : response) + std::cout << "errors:\n"; + for (const auto& [name, counter] : dataPlane.getErrors()) { - printf(" (%lu) %s\n", - iter.second.value, - iter.first.data()); + std::cout << " (" << counter.value << ") " << name << '\n'; } } -void getReport() +inline void getReport() { interface::dataPlane dataPlane; - const auto response = dataPlane.getReport(); - printf("%s\n", response.data()); + std::cout << dataPlane.getReport() << '\n'; } -void counter(const uint32_t& counter_id, - const std::optional& range_size) +inline void counter(uint32_t counter_id, const std::optional& range_size) { - interface::dataPlane dataplane; + std::vector counter_ids{counter_id}; - std::vector counter_ids = {counter_id}; - if (range_size && (*range_size) > 0) + if (range_size.has_value() && range_size.value() > 0) { - for (uint32_t offset = 0; - offset < (*range_size) - 1; - offset++) + for (uint32_t offset = 0; offset < range_size.value() - 1; offset++) { counter_ids.emplace_back(counter_id + offset + 1); } } - const auto response = common::sdp::SdpClient::GetCounters(counter_ids); + const auto& response = common::sdp::SdpClient::GetCounters(counter_ids); - table_t table; - table.insert("counter_id", - "value"); + TablePrinter table; + table.insert("counter_id", "value"); - for (uint32_t i = 0; - i < counter_ids.size(); - i++) + for (uint32_t i = 0; i < counter_ids.size(); i++) { - table.insert(counter_ids[i], - response[i]); + table.insert_row(counter_ids[i], response[i]); } - table.print(); + table.Print(); } using namespace ::dataplane::perf; -class tsc_monitoring_t +struct tsc_monitoring_t { -public: void connect_shm() { interface::dataPlane dataplane; - const auto response = dataplane.get_shm_tsc_info(); + const auto& response = dataplane.get_shm_tsc_info(); std::map ipc_cache; for (const auto& [core, socket, ipc_key, offset] : response) { - (void)socket; + YANET_GCC_BUG_UNUSED(socket); if (ipc_cache.find(ipc_key) == ipc_cache.end()) { - auto shmid = shmget(ipc_key, 0, 0); - if (shmid == -1) - { - throw std::string("shmget(") + std::to_string(ipc_key) + ", 0, 0) = " + std::strerror(errno); - } - auto shmaddr = shmat(shmid, NULL, SHM_RDONLY); - if (shmaddr == (void*)-1) + auto&& [shmaddr, size] = common::ipc::SharedMemory::OpenBufferKey(ipc_key, false); + YANET_GCC_BUG_UNUSED(size); + + if (shmaddr == nullptr) { - throw std::string("shmat(") + std::to_string(ipc_key) + ", NULL, 0) = " + std::strerror(errno); + throw std::system_error(errno, std::generic_category(), "Opening an existing buffer in shared memory failed"); } ipc_cache[ipc_key] = shmaddr; } - auto counter_addr = (tsc_deltas*)((intptr_t)ipc_cache[ipc_key] + offset); + auto counter_addr = reinterpret_cast( + reinterpret_cast(ipc_cache[ipc_key]) + offset); worker_counters.emplace_back(core, counter_addr, tsc_deltas{}, overflow_store{}); } } @@ -206,9 +193,13 @@ class tsc_monitoring_t void monitor() { connect_shm(); - for (auto iter = 0;; iter++) + const int header_interval = 4; + + for (int iter = 0;; ++iter) { - if (iter % 4 == 0) + bool render_header = (iter % header_interval == 0); + + if (render_header) { insert_header(); } @@ -216,10 +207,11 @@ class tsc_monitoring_t for (auto& [core_id, counter, previous_value, overflow_store] : worker_counters) { const auto& counter_copy = *counter; - for (auto bin = 0; bin < YANET_TSC_BINS_N; bin++) + for (int bin = 0; bin < YANET_TSC_BINS_N; ++bin) { overflow_store.handle_overflow(counter_copy, previous_value, bin); - if (iter % 4 == 0) + + if (render_header) { insert_bin(counter_copy, overflow_store, bin, core_id); } @@ -228,145 +220,157 @@ class tsc_monitoring_t previous_value = counter_copy; } - if (iter % 4 == 0) + if (render_header) { - table.render(); + table.Render(); } + std::this_thread::sleep_for(std::chrono::milliseconds(250)); } } -protected: - struct overflow_store; - - void insert_header() +private: + struct overflow_store { - table.insert("core_id", - "iter_num", - "logicalPort_ingress", - "acl_ingress4", - "acl_ingress6", - "tun64_ipv4", - "tun64_ipv6", - "route4", - "route6", - "decap", - "nat64stateful_lan", - "nat64stateful_wan", - "nat64stateless_egress", - "nat64stateless_ingress", - "nat46clat_lan", - "nat46clat_wan", - "balancer", - "balancer_icmp_reply", - "balancer_icmp_forward", - "route_tunnel4", - "route_tunnel6", - "acl_egress4", - "acl_egress6", - "logicalPort_egress", - "controlPlane"); - } + template + static auto make_tuple(T& obj) + { + return std::tie(obj.logicalPort_ingress_handle, + obj.acl_ingress_handle4, + obj.acl_ingress_handle6, + obj.tun64_ipv4_handle, + obj.tun64_ipv6_handle, + obj.route_handle4, + obj.route_handle6, + obj.decap_handle, + obj.nat64stateful_lan_handle, + obj.nat64stateful_wan_handle, + obj.nat64stateless_egress_handle, + obj.nat64stateless_ingress_handle, + obj.nat46clat_lan_handle, + obj.nat46clat_wan_handle, + obj.balancer_handle, + obj.balancer_icmp_reply_handle, + obj.balancer_icmp_forward_handle, + obj.route_tunnel_handle4, + obj.route_tunnel_handle6, + obj.acl_egress_handle4, + obj.acl_egress_handle6, + obj.logicalPort_egress_handle, + obj.controlPlane_handle); + } - void insert_bin(const tsc_deltas& cnt, const overflow_store& of_store, int bin, uint32_t core_id) - { - table.insert(bin == 0 ? std::to_string(core_id) : std::string{}, - bin == 0 ? std::to_string(cnt.iter_num) : std::string{}, - of_store.logicalPort_ingress_handle[bin] + cnt.logicalPort_ingress_handle[bin], - of_store.acl_ingress_handle4[bin] + cnt.acl_ingress_handle4[bin], - of_store.acl_ingress_handle6[bin] + cnt.acl_ingress_handle6[bin], - of_store.tun64_ipv4_handle[bin] + cnt.tun64_ipv4_handle[bin], - of_store.tun64_ipv6_handle[bin] + cnt.tun64_ipv6_handle[bin], - of_store.route_handle4[bin] + cnt.route_handle4[bin], - of_store.route_handle6[bin] + cnt.route_handle6[bin], - - of_store.decap_handle[bin] + cnt.decap_handle[bin], - of_store.nat64stateful_lan_handle[bin] + cnt.nat64stateful_lan_handle[bin], - of_store.nat64stateful_wan_handle[bin] + cnt.nat64stateful_wan_handle[bin], - of_store.nat64stateless_egress_handle[bin] + cnt.nat64stateless_egress_handle[bin], - of_store.nat64stateless_ingress_handle[bin] + cnt.nat64stateless_ingress_handle[bin], - of_store.nat46clat_lan_handle[bin] + cnt.nat46clat_lan_handle[bin], - of_store.nat46clat_wan_handle[bin] + cnt.nat46clat_wan_handle[bin], - of_store.balancer_handle[bin] + cnt.balancer_handle[bin], - - of_store.balancer_icmp_reply_handle[bin] + cnt.balancer_icmp_reply_handle[bin], - of_store.balancer_icmp_forward_handle[bin] + cnt.balancer_icmp_forward_handle[bin], - of_store.route_tunnel_handle4[bin] + cnt.route_tunnel_handle4[bin], - of_store.route_tunnel_handle6[bin] + cnt.route_tunnel_handle6[bin], - of_store.acl_egress_handle4[bin] + cnt.acl_egress_handle4[bin], - of_store.acl_egress_handle6[bin] + cnt.acl_egress_handle6[bin], - of_store.logicalPort_egress_handle[bin] + cnt.logicalPort_egress_handle[bin], - of_store.controlPlane_handle[bin] + cnt.controlPlane_handle[bin]); - } + using CountersArray = std::array; + + CountersArray logicalPort_ingress_handle{}; + CountersArray acl_ingress_handle4{}; + CountersArray acl_ingress_handle6{}; + CountersArray tun64_ipv4_handle{}; + CountersArray tun64_ipv6_handle{}; + CountersArray route_handle4{}; + CountersArray route_handle6{}; + + CountersArray decap_handle{}; + CountersArray nat64stateful_lan_handle{}; + CountersArray nat64stateful_wan_handle{}; + CountersArray nat64stateless_egress_handle{}; + CountersArray nat64stateless_ingress_handle{}; + CountersArray nat46clat_lan_handle{}; + CountersArray nat46clat_wan_handle{}; + CountersArray balancer_handle{}; + + CountersArray balancer_icmp_reply_handle{}; + CountersArray balancer_icmp_forward_handle{}; + CountersArray route_tunnel_handle4{}; + CountersArray route_tunnel_handle6{}; + CountersArray acl_egress_handle4{}; + CountersArray acl_egress_handle6{}; + CountersArray logicalPort_egress_handle{}; + CountersArray controlPlane_handle{}; + + auto as_tuple() + { + return make_tuple(*this); + } - struct overflow_store - { - uint64_t logicalPort_ingress_handle[YANET_TSC_BINS_N]; - uint64_t acl_ingress_handle4[YANET_TSC_BINS_N]; - uint64_t acl_ingress_handle6[YANET_TSC_BINS_N]; - uint64_t tun64_ipv4_handle[YANET_TSC_BINS_N]; - uint64_t tun64_ipv6_handle[YANET_TSC_BINS_N]; - uint64_t route_handle4[YANET_TSC_BINS_N]; - uint64_t route_handle6[YANET_TSC_BINS_N]; - - uint64_t decap_handle[YANET_TSC_BINS_N]; - uint64_t nat64stateful_lan_handle[YANET_TSC_BINS_N]; - uint64_t nat64stateful_wan_handle[YANET_TSC_BINS_N]; - uint64_t nat64stateless_egress_handle[YANET_TSC_BINS_N]; - uint64_t nat64stateless_ingress_handle[YANET_TSC_BINS_N]; - uint64_t nat46clat_lan_handle[YANET_TSC_BINS_N]; - uint64_t nat46clat_wan_handle[YANET_TSC_BINS_N]; - uint64_t balancer_handle[YANET_TSC_BINS_N]; - - uint64_t balancer_icmp_reply_handle[YANET_TSC_BINS_N]; - uint64_t balancer_icmp_forward_handle[YANET_TSC_BINS_N]; - uint64_t route_tunnel_handle4[YANET_TSC_BINS_N]; - uint64_t route_tunnel_handle6[YANET_TSC_BINS_N]; - uint64_t acl_egress_handle4[YANET_TSC_BINS_N]; - uint64_t acl_egress_handle6[YANET_TSC_BINS_N]; - uint64_t logicalPort_egress_handle[YANET_TSC_BINS_N]; - uint64_t controlPlane_handle[YANET_TSC_BINS_N]; + [[nodiscard]] auto as_tuple() const + { + return make_tuple(*this); + } void handle_overflow(const tsc_deltas& cnt, const tsc_deltas& prev, int bin) { - logicalPort_ingress_handle[bin] += (prev.logicalPort_ingress_handle[bin] > cnt.logicalPort_ingress_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - acl_ingress_handle4[bin] += (prev.acl_ingress_handle4[bin] > cnt.acl_ingress_handle4[bin]) << sizeof(uint16_t) * CHAR_BIT; - acl_ingress_handle6[bin] += (prev.acl_ingress_handle6[bin] > cnt.acl_ingress_handle6[bin]) << sizeof(uint16_t) * CHAR_BIT; - tun64_ipv4_handle[bin] += (prev.tun64_ipv4_handle[bin] > cnt.tun64_ipv4_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - tun64_ipv6_handle[bin] += (prev.tun64_ipv6_handle[bin] > cnt.tun64_ipv6_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - route_handle4[bin] += (prev.route_handle4[bin] > cnt.route_handle4[bin]) << sizeof(uint16_t) * CHAR_BIT; - route_handle6[bin] += (prev.route_handle6[bin] > cnt.route_handle6[bin]) << sizeof(uint16_t) * CHAR_BIT; - - decap_handle[bin] += (prev.decap_handle[bin] > cnt.decap_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat64stateful_lan_handle[bin] += (prev.nat64stateful_lan_handle[bin] > cnt.nat64stateful_lan_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat64stateful_wan_handle[bin] += (prev.nat64stateful_wan_handle[bin] > cnt.nat64stateful_wan_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat64stateless_egress_handle[bin] += (prev.nat64stateless_egress_handle[bin] > cnt.nat64stateless_egress_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat64stateless_ingress_handle[bin] += (prev.nat64stateless_ingress_handle[bin] > cnt.nat64stateless_ingress_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat46clat_lan_handle[bin] += (prev.nat46clat_lan_handle[bin] > cnt.nat46clat_lan_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - nat46clat_wan_handle[bin] += (prev.nat46clat_wan_handle[bin] > cnt.nat46clat_wan_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - balancer_handle[bin] += (prev.balancer_handle[bin] > cnt.balancer_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - - balancer_icmp_reply_handle[bin] += (prev.balancer_icmp_reply_handle[bin] > cnt.balancer_icmp_reply_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - balancer_icmp_forward_handle[bin] += (prev.balancer_icmp_forward_handle[bin] > cnt.balancer_icmp_forward_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - route_tunnel_handle4[bin] += (prev.route_tunnel_handle4[bin] > cnt.route_tunnel_handle4[bin]) << sizeof(uint16_t) * CHAR_BIT; - route_tunnel_handle6[bin] += (prev.route_tunnel_handle6[bin] > cnt.route_tunnel_handle6[bin]) << sizeof(uint16_t) * CHAR_BIT; - acl_egress_handle4[bin] += (prev.acl_egress_handle4[bin] > cnt.acl_egress_handle4[bin]) << sizeof(uint16_t) * CHAR_BIT; - acl_egress_handle6[bin] += (prev.acl_egress_handle6[bin] > cnt.acl_egress_handle6[bin]) << sizeof(uint16_t) * CHAR_BIT; - logicalPort_egress_handle[bin] += (prev.logicalPort_egress_handle[bin] > cnt.logicalPort_egress_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; - controlPlane_handle[bin] += (prev.controlPlane_handle[bin] > cnt.controlPlane_handle[bin]) << sizeof(uint16_t) * CHAR_BIT; + auto this_tuple = as_tuple(); + auto cnt_tuple = cnt.as_tuple(); + auto prev_tuple = prev.as_tuple(); + + auto op = [&](auto& this_member, const auto& cnt_member, const auto& prev_member) { + this_member[bin] += (prev_member[bin] > cnt_member[bin]) << (sizeof(uint16_t) * CHAR_BIT); + }; + + utils::zip_apply(op, this_tuple, cnt_tuple, prev_tuple); } }; std::vector> worker_counters; - table_t table; + TablePrinter table; + + void insert_header() + { + table.insert_row("core_id", + "iter_num", + "logicalPort_ingress", + "acl_ingress4", + "acl_ingress6", + "tun64_ipv4", + "tun64_ipv6", + "route4", + "route6", + "decap", + "nat64stateful_lan", + "nat64stateful_wan", + "nat64stateless_egress", + "nat64stateless_ingress", + "nat46clat_lan", + "nat46clat_wan", + "balancer", + "balancer_icmp_reply", + "balancer_icmp_forward", + "route_tunnel4", + "route_tunnel6", + "acl_egress4", + "acl_egress6", + "logicalPort_egress", + "controlPlane"); + } + + void insert_bin(const tsc_deltas& cnt, const overflow_store& of_store, int bin, uint32_t core_id) + { + constexpr std::size_t tuple_size = std::tuple_size_v; + // The total size of the row will be 2 fixed elements (core_id and iter_num) plus tuple_size + std::array row; + + row[0] = (bin == 0) ? std::to_string(core_id) : std::string{}; + row[1] = (bin == 0) ? std::to_string(cnt.iter_num) : std::string{}; + + auto cnt_tuple = cnt.as_tuple(); + auto of_store_tuple = of_store.as_tuple(); + + std::size_t index = 2; // Start after core_id and iter_num + auto op = [&](const auto& of_store_member, const auto& cnt_member) mutable { + row[index++] = std::to_string(of_store_member[bin] + cnt_member[bin]); + }; + + utils::zip_apply(op, of_store_tuple, cnt_tuple); + + table.insert_row(row.begin(), row.end()); + } }; -void tsc_monitoring() +inline void tsc_monitoring() { tsc_monitoring_t monitoring{}; monitoring.monitor(); } } - -} diff --git a/cli/dregress.h b/cli/dregress.h index e97b659b..2aa2727e 100644 --- a/cli/dregress.h +++ b/cli/dregress.h @@ -2,7 +2,7 @@ #include "common/icontrolplane.h" -#include "helper.h" +#include "table_printer.h" namespace dregress { @@ -12,29 +12,29 @@ void summary() interface::controlPlane controlPlane; const auto response = controlPlane.dregress_config(); - table_t table; - table.insert("module", - "ipv6_sources", - "ipv6_destination", - "ipv4_address", - "ipv6_address", - "udp_destination_port", - "only_longest", - "next_module"); + TablePrinter table; + table.insert_row("module", + "ipv6_sources", + "ipv6_destination", + "ipv4_address", + "ipv6_address", + "udp_destination_port", + "only_longest", + "next_module"); for (const auto& [module_name, dregress] : response) { - table.insert(module_name, - dregress.ipv6SourcePrefixes, - dregress.ipv6DestinationPrefix, - dregress.ipv4SourceAddress, - dregress.ipv6SourceAddress, - dregress.udpDestinationPort, - dregress.onlyLongest, - dregress.nextModule); + table.insert_row(module_name, + dregress.ipv6SourcePrefixes, + dregress.ipv6DestinationPrefix, + dregress.ipv4SourceAddress, + dregress.ipv6SourceAddress, + dregress.udpDestinationPort, + dregress.onlyLongest, + dregress.nextModule); } - table.print(); + table.Print(); } void announce() @@ -42,17 +42,17 @@ void announce() interface::controlPlane controlPlane; const auto response = controlPlane.dregress_config(); - table_t table; + TablePrinter table; table.insert("module", "announces"); for (const auto& [module_name, dregress] : response) { - table.insert(module_name, - dregress.announces); + table.insert_row(module_name, + dregress.announces); } - table.print(); + table.Print(); } /** @todo diff --git a/cli/helper.h b/cli/helper.h index 4d4ceea6..7e9ba0db 100644 --- a/cli/helper.h +++ b/cli/helper.h @@ -1,474 +1,100 @@ #pragma once -#include #include -#include -#include -#include #include #include #include #include -#include - #include "common/sdpclient.h" -#include "converter.h" +#include "common/traits.h" +#include "table_printer.h" -template -static std::string to_percent(const type current, const type maximum) -{ - double percent = 0.0; - if (maximum) - { - percent = (double)current / (double)maximum; - percent *= (double)100; - } +#if __cpp_lib_charconv >= 201606L && !defined(__GNUC__) || __GNUC__ >= 8 +#define USE_FROM_CHARS +#endif - std::stringstream stream; - stream << std::fixed << std::setprecision(2) << percent; - return stream.str(); -} - -std::vector split(const char* string, - const char delimiter) -{ - std::vector result; - std::stringstream ss(string); - - std::string part; - while (std::getline(ss, part, delimiter)) - { - result.emplace_back(part); - } - - return result; -} - -void fillValue(std::optional& value, const std::string& string) -{ - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = std::stoull(string, nullptr, 0); - ; - } - else - { - value = std::nullopt; - } -} - -void fillValue(std::optional& value, const std::string& string) -{ - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = std::stoull(string, nullptr, 0); - ; - } - else - { - value = std::nullopt; - } -} - -void fillValue(std::optional& value, const std::string& string) -{ - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = std::stoull(string, nullptr, 0); - ; - } - else - { - value = std::nullopt; - } -} - -template -void fillValue(std::optional& value, const std::string& string) -{ - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = string; - } - else - { - value = std::nullopt; - } -} +#if defined(USE_FROM_CHARS) +#include +#else +#include +#endif -void fillValue(bool& value, const std::string& string) +template +static void fill(T& value, const std::string& str) { - if (string == "false" || string == "true") + if constexpr (std::is_same_v) { - value = string == "true"; + if (str == "true") + value = true; + else if (str == "false") + value = false; + else + throw std::invalid_argument("Invalid boolean value"); } - else + else if constexpr (std::is_integral_v || std::is_floating_point_v) { - throw std::string("invalid argument, must be true or false"); +#ifdef USE_FROM_CHARS + auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value); + if (ec != std::errc{}) + throw std::invalid_argument("Invalid numeric value: '" + str + "'"); +#else + std::istringstream iss(str); + if (!(iss >> value) || !iss.eof()) + throw std::invalid_argument("Invalid numeric value: '" + str + "'"); +#endif } -} - -void fillValue(uint8_t& value, const std::string& string) -{ - value = std::stoull(string, nullptr, 0); -} - -void fillValue(uint16_t& value, const std::string& string) -{ - value = std::stoull(string, nullptr, 0); -} - -void fillValue(uint32_t& value, const std::string& string) -{ - value = std::stoull(string, nullptr, 0); -} - -template -void fillValue(TArg& value, const std::string& string) -{ - value = string; -} - -template -void fillValue(std::optional& value) -{ - value = std::nullopt; -} - -template -void fillValue(TArg& value) -{ - (void)value; - throw std::string("invalid arguments count"); -} - -template -void fillTuple(TTuple& tuple, const std::vector& stringArgs) -{ - if constexpr (TIndex < TSize) + else if constexpr (traits::is_optional_v) { - if (TIndex < stringArgs.size()) + if (str == "any" || str.empty()) { - fillValue(std::get(tuple), stringArgs[TIndex]); + value.reset(); } else { - fillValue(std::get(tuple)); + typename T::value_type temp; + fill(temp, str); + value = std::move(temp); } - - fillTuple(tuple, stringArgs); } -} - -template -void call(void (*func)(TArgs... args), - const std::vector& stringArgs) -{ - if (stringArgs.size() > sizeof...(TArgs)) + else { - throw std::string("invalid arguments count: '") + std::to_string(stringArgs.size()) + "', need: '" + std::to_string(sizeof...(TArgs)) + "'"; + value = str; } - std::tuple...> tuple; - fillTuple<0, sizeof...(TArgs)>(tuple, stringArgs); - std::apply(func, tuple); } -template -void getDiffTuple(TDiffTuple& diff, - const TTuple& curr, - const TTuple& prev) +// Fill a tuple with values from a vector of strings +template +static void fillTupleImpl(Tuple& tuple, const std::vector& args, std::index_sequence) { - if constexpr (TIndex < TSize) - { - std::get(diff) = std::get(curr) - std::get(prev); - getDiffTuple(diff, curr, prev); - } + (..., fill(std::get(tuple), Is < args.size() ? args[Is] : std::string{})); } -template -std::map> getDiff(const std::map>& curr, - const std::map>& prev) +template +static void fillTuple(std::tuple& tuple, const std::vector& args) { - std::map> result; - - for (const auto& iter : curr) - { - if (prev.find(iter.first) != prev.end()) - { - std::array diff; - getDiffTuple<0, sizeof...(TSecondArgs)>(diff, iter.second, prev.find(iter.first)->second); - result[iter.first] = diff; - } - } - - return result; + fillTupleImpl(tuple, args, std::index_sequence_for{}); } -class table_t +// Call function using string arguments +template +inline void Call(F&& func, const std::vector& string_args) { -public: - table_t(const converter::config_t config = {}) : - config(config) - { - } + using ArgsTuple = typename traits::function::args; + constexpr auto arity = std::tuple_size_v; - template - void insert(const args_T&... args) + if (string_args.size() > arity) { - std::vector row = {converter::to_string(args, config)...}; - - if (row.size() > columnLengths.size()) - { - columnLengths.resize(row.size(), 0); - } - - for (uint32_t string_i = 0; - string_i < row.size(); - string_i++) - { - if (columnLengths[string_i] < row[string_i].size()) - { - columnLengths[string_i] = row[string_i].size(); - } - } - - table.emplace_back(row); + throw std::invalid_argument("Invalid arguments count: '" + std::to_string(string_args.size()) + + "', expected at most: '" + std::to_string(arity) + "'"); } - void print_json() - { - std::vector format_keys; - std::map format_keys_i; - if (const char* format_keys_pointer = std::getenv("YANET_FORMAT_KEYS")) - { - format_keys = split(format_keys_pointer, ','); - } - - std::vector keys; - - bool header = true; - nlohmann::json json_root; - for (auto& row : table) - { - if (header) - { - for (uint32_t string_i = 0; - string_i < row.size(); - string_i++) - { - for (uint32_t format_i = 0; - format_i < format_keys.size(); - format_i++) - { - if (row[string_i] == format_keys[format_i]) - { - format_keys_i[string_i] = format_i; - } - } - } - - keys = row; - header = false; - continue; - } - - std::vector tree; - tree.resize(format_keys.size()); - - nlohmann::json json_row; - for (uint32_t string_i = 0; - string_i < row.size(); - string_i++) - { - if (format_keys_i.count(string_i)) - { - tree[format_keys_i[string_i]] = row[string_i]; - } - else - { - json_row[keys[string_i]] = row[string_i]; - } - } - - auto* json_current = &json_root; - for (const auto& key : tree) - { - json_current = &((*json_current)[key]); - } - (*json_current).emplace_back(json_row); - } - - printf("%s\n", json_root.dump(2).data()); - } - - void print_default() - { - if (table.size() == 0 || - columnLengths.size() == 0) - { - return; - } - - std::vector user_selected_col_names; - bool print_selected_cols_only = false; - if (const char* columns_pointer = std::getenv("YANET_FORMAT_COLUMNS")) - { - user_selected_col_names = split(columns_pointer, ','); - print_selected_cols_only = true; - } - - /* header row contains table's column names */ - auto& header_row = table[0]; - - /* If the user listed only specific columns of the table to be printed in specific order, - need to build a relation between index of column in user-provided order and its index in the table (only if it does exist in the table): - This relation: columns_order[col_idx_in_user_selection] = col_idx_in_table - - Otherwise, when no custom columns' selection and/or order is provided by the user, - print all columns of the table in the table's order: - columns_order[col_idx_in_table] = col_idx_in_table */ - std::vector columns_order; - if (print_selected_cols_only) - { - uint32_t col_idx_in_user_selection = 0; - while (columns_order.size() < user_selected_col_names.size()) - { - bool selected_col_name_found = false; - for (uint32_t col_idx_in_table = 0; col_idx_in_table < header_row.size(); ++col_idx_in_table) - { - if (user_selected_col_names[col_idx_in_user_selection] == header_row[col_idx_in_table]) - { - // col_idx_in_user_selection must be equal to columns_order.size() prior to insertion (check?) - columns_order.push_back(col_idx_in_table); - selected_col_name_found = true; - ++col_idx_in_user_selection; - break; - } - } - - if (!selected_col_name_found) - { - // evidently, user provided such a column name, which does not exist in the table, cannot print it - // shifting tail of user_selected_col_names to the left by erasing non-existent user-provided column name - user_selected_col_names.erase(user_selected_col_names.begin() + col_idx_in_user_selection); - } - } - } - else - { - columns_order.resize(header_row.size()); - std::iota(columns_order.begin(), columns_order.end(), 0); - } - - if (columns_order.size() == 0) - { - /* column names provided by user do not match any column names of the table, - or the table does not have any columns at all (what?!) */ - return; - } - - bool header = true; - for (auto& row : table) - { - printf("%-*s", - columnLengths[columns_order[0]], - row[columns_order[0]].data()); - - for (uint32_t string_i = 1; - string_i < columns_order.size(); - string_i++) - { - if (string_i != columns_order.size() - 1) - { - printf(" %-*s", - columnLengths[columns_order[string_i]], - row[columns_order[string_i]].data()); - } - else - { - // Do not explode the last column with padding whitespace bytes. - printf(" %s", - row[columns_order[string_i]].data()); - } - } - - printf("\n"); - - if (header) - { - printf("%s", std::string(columnLengths[columns_order[0]], '-').data()); - - for (uint32_t string_i = 1; - string_i < columns_order.size(); - string_i++) - { - printf(" %s", std::string(columnLengths[columns_order[string_i]], '-').data()); - } - - printf("\n"); - - header = false; - } - } - } - - void print() - { - std::string format; - if (const char* format_pointer = std::getenv("YANET_FORMAT")) - { - format = format_pointer; - } - - if (format == "json") - { - print_json(); - } - else - { - print_default(); - } - } - - void render() - { - printf("\033[H\033[2J"); - fflush(stdout); - - print_default(); - table.clear(); - } - -protected: - converter::config_t config; - std::vector> table; - std::vector columnLengths; -}; + utils::decay_tuple args_tuple; + fillTuple(args_tuple, string_args); + std::apply(std::forward(func), args_tuple); +} -void OpenSharedMemoryDataplaneBuffers(common::sdp::DataPlaneInSharedMemory& sdp_data, bool open_workers_data) +inline void OpenSharedMemoryDataplaneBuffers(common::sdp::DataPlaneInSharedMemory& sdp_data, bool open_workers_data) { if (common::sdp::SdpClient::ReadSharedMemoryData(sdp_data, open_workers_data) != eResult::success) { @@ -476,3 +102,13 @@ void OpenSharedMemoryDataplaneBuffers(common::sdp::DataPlaneInSharedMemory& sdp_ std::exit(1); } } + +template +inline void FillAndPrintTable(const std::initializer_list& headers, const Container& data, const converter::config_t config = {}) +{ + TablePrinter table(config); + + table.insert_row(headers.begin(), headers.end()); + table.insert(data.begin(), data.end()); + table.Print(); +} diff --git a/cli/influxdb_format.h b/cli/influxdb_format.h index ff95b706..544fec6b 100644 --- a/cli/influxdb_format.h +++ b/cli/influxdb_format.h @@ -88,11 +88,9 @@ std::string to_string(const char* key, class base_t { public: - virtual ~base_t() - { - } + virtual ~base_t() = default; - const std::string& to_string() const + [[nodiscard]] const std::string& to_string() const { return string; } @@ -183,7 +181,7 @@ void print_histogram(const char* name, const index_T start, const index_T end) { - for (unsigned int i = (unsigned int)start; + for (auto i = (unsigned int)start; i <= (unsigned int)end; i++) { diff --git a/cli/latch.h b/cli/latch.h index 1302378c..841ed303 100644 --- a/cli/latch.h +++ b/cli/latch.h @@ -1,7 +1,10 @@ #pragma once +#include "common/idataplane.h" +#include "common/idp.h" #include #include +#include namespace latch { diff --git a/cli/limit.h b/cli/limit.h index 13f60db7..437c9976 100644 --- a/cli/limit.h +++ b/cli/limit.h @@ -1,10 +1,9 @@ #pragma once -#include - #include "common/icontrolplane.h" -#include "helper.h" +#include "common/utils.h" +#include "table_printer.h" namespace limit { @@ -14,34 +13,14 @@ void summary() interface::controlPlane controlPlane; const auto response = controlPlane.limit_summary(); - table_t table; - table.insert("name", - "socket_id", - "current", - "maximum", - "percent"); + TablePrinter table; for (const auto& [name, socket_id, current, maximum] : response) { - double percent = 0.0; - if (maximum) - { - percent = (double)current / (double)maximum; - percent *= (double)100; - } - - std::stringstream stream; - stream << std::fixed << std::setprecision(2) << percent; - std::string percent_string = stream.str(); - - table.insert(name, - socket_id, - current, - maximum, - percent_string); + table.insert_row(name, socket_id, current, maximum, utils::to_percent(current, maximum)); } - table.print(); + table.Print(); } } diff --git a/cli/main.cpp b/cli/main.cpp index 0cd2acb3..c13d3577 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -36,124 +36,124 @@ void help() std::vector&)>>> - commands = {{"help", "", [](const auto& args) { call(help, args); }}, + commands = {{"help", "", [](const auto& args) { Call(help, args); }}, {}, - {"physicalPort", "", [](const auto& args) { call(show::physicalPort, args); }}, - {"logicalPort", "", [](const auto& args) { call(show::logicalPort, args); }}, - {"acl unwind", "[module] ", [](const auto& args) { call(acl::unwind, args); }}, - {"acl lookup", " ", [](const auto& args) { call(acl::lookup, args); }}, - {"decap", "", [](const auto& args) { call(show::decap::summary, args); }}, - {"decap announce", "", [](const auto& args) { call(show::decap::announce, args); }}, - {"decap prefix allow", "[module] [ipv6_prefix] [ipv6_prefix]", [](const auto& args) { call(config::decap::allow, args); }}, - {"decap prefix disallow", "[module] [ipv6_prefix] [ipv6_prefix]", [](const auto& args) { call(config::decap::disallow, args); }}, - {"decap prefix remove", "[module] [ipv6_prefix]", [](const auto& args) { call(config::decap::remove, args); }}, - {"tun64", "[module]", [](const auto& args) { call(show::tun64::summary, args); }}, - {"tun64 announce", "[module]", [](const auto& args) { call(show::tun64::announce, args); }}, - {"tun64 mappings list", "[module]", [](const auto& args) { call(show::tun64::mappings, args); }}, - {"nat64stateful", "", [](const auto& args) { call(nat64stateful::summary, args); }}, - {"nat64stateful state", "", [](const auto& args) { call(nat64stateful::state, args); }}, - {"nat64stateful announce", "", [](const auto& args) { call(nat64stateful::announce, args); }}, - {"nat64stateless", "", [](const auto& args) { call(show::nat64stateless::summary, args); }}, - {"nat64stateless translation", "", [](const auto& args) { call(show::nat64stateless::translation, args); }}, - {"nat64stateless announce", "", [](const auto& args) { call(show::nat64stateless::announce, args); }}, - {"nat64stateless prefix allow4", "[module] [ipv4_prefix] [ipv4_prefix]", [](const auto& args) { call(config::nat64stateless::allow4, args); }}, - {"nat64stateless prefix disallow4", "[module] [ipv4_prefix] [ipv4_prefix]", [](const auto& args) { call(config::nat64stateless::disallow4, args); }}, - {"nat64stateless prefix remove4", "[module] [ipv4_prefix]", [](const auto& args) { call(config::nat64stateless::remove4, args); }}, - {"nat64stateless prefix allow6", "[module] [ipv6_prefix] [ipv6_prefix]", [](const auto& args) { call(config::nat64stateless::allow6, args); }}, - {"nat64stateless prefix disallow6", "[module] [ipv6_prefix] [ipv6_prefix]", [](const auto& args) { call(config::nat64stateless::disallow6, args); }}, - {"nat64stateless prefix remove6", "[module] [ipv6_prefix]", [](const auto& args) { call(config::nat64stateless::remove6, args); }}, - {"nat46clat", "", [](const auto& args) { call(nat46clat::summary, args); }}, - {"nat46clat announce", "", [](const auto& args) { call(nat46clat::announce, args); }}, - {"balancer", "", [](const auto& args) { call(balancer::summary, args); }}, - {"balancer service", "[module] ", [](const auto& args) { call(balancer::service, args); }}, - {"balancer real", "[module] ", [](const auto& args) { call(balancer::real_find, args); }}, - {"balancer state", "[module] ", [](const auto& args) { call(balancer::state, args); }}, - {"balancer real enable", "[module] [virtual_ip] [proto] [virtual_port] [real_ip] [real_port] ", [](const auto& args) { call(balancer::real::enable, args); }}, - {"balancer real disable", "[module] [virtual_ip] [proto] [virtual_port] [real_ip] [real_port]", [](const auto& args) { call(balancer::real::disable, args); }}, - {"balancer real flush", "", [](const auto& args) { call(balancer::real::flush, args); }}, - {"balancer announce", "", [](const auto& args) { call(balancer::announce, args); }}, - {"route", "", [](const auto& args) { call(route::summary, args); }}, - {"route interface", "", [](const auto& args) { call(route::interface, args); }}, - {"route lookup", "[module] [ip_address]", [](const auto& args) { call(route::lookup, args); }}, - {"route get", "[module] [ip_prefix]", [](const auto& args) { call(route::get, args); }}, - {"route tunnel lookup", "[module] [ip_address]", [](const auto& args) { call(route::tunnel::lookup, args); }}, - {"route tunnel get", "[module] [ip_prefix]", [](const auto& args) { call(route::tunnel::get, args); }}, - {"route counters", "", [](const auto& args) { call(route::counters, args); }}, - {"route tunnel counters", "", [](const auto& args) { call(route::tunnel::counters, args); }}, - {"neighbor show", "", [](const auto& args) { call(neighbor::show, args); }}, - {"neighbor insert", "[route_name] [interface_name] [ip_address] [mac_address]", [](const auto& args) { call(neighbor::insert, args); }}, - {"neighbor remove", "[route_name] [interface_name] [ip_address]", [](const auto& args) { call(neighbor::remove, args); }}, - {"neighbor flush", "", [](const auto& args) { call(neighbor::flush, args); }}, - {"rib", "", [](const auto& args) { call(rib::summary, args); }}, - {"rib prefixes", "", [](const auto& args) { call(rib::prefixes, args); }}, - {"rib lookup", "[vrf] [ip_address]", [](const auto& args) { call(rib::lookup, args); }}, - {"rib get", "[vrf] [ip_prefix]", [](const auto& args) { call(rib::get, args); }}, - {"rib static insert", "[vrf] [ip_prefix] [nexthop]