diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 2301c70c..f4db89f5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -14,24 +14,11 @@ 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-image-builder: - needs: formatting-check - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v3 - - name: Build the yanetplatform/builder - run: | - cd image - # todo - - build-unittest: - needs: build-image-builder + needs: formatting-check runs-on: ubuntu-latest container: image: yanetplatform/builder-lite @@ -51,8 +38,8 @@ jobs: retention-days: 1 build-autotest: - needs: build-image-builder - runs-on: builder + needs: formatting-check + runs-on: ubuntu-latest container: image: yanetplatform/builder-lite steps: @@ -72,7 +59,7 @@ jobs: retention-days: 1 build: - needs: build-image-builder + needs: formatting-check runs-on: ubuntu-latest container: image: yanetplatform/builder-lite @@ -87,7 +74,7 @@ jobs: build-ubuntu1804: name: build (Ubuntu 18.04) - needs: build-image-builder + needs: formatting-check runs-on: ubuntu-latest container: image: yanetplatform/builder_ubuntu18.04-lite @@ -117,7 +104,7 @@ jobs: autotest-001_one_port: name: 001_one_port needs: build-autotest - runs-on: autotest + runs-on: ubuntu-latest container: image: yanetplatform/builder-lite steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90407dd6..6abc23de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,15 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive + - name: version + run: | + export YANET_VERSION=${{github.ref_name}} + export YANET_VERSION=${YANET_VERSION} + export YANET_VERSION_MAJOR=${YANET_VERSION%.*} + export YANET_VERSION_MINOR=${YANET_VERSION#*.} + export YANET_VERSION_REVISION=${{github.run_number}} + export YANET_VERSION_HASH=${{github.sha}} + export YANET_VERSION_CUSTOM=stable - name: Docker meta id: meta uses: docker/metadata-action@v5 diff --git a/README.md b/README.md index 932559c1..97d99004 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ docker pull yanetplatform/builder Add alias for run commands on docker: ``` alias yanet-builder="docker run --rm -it -v /run/yanet:/run/yanet -v \$PWD:/project yanetplatform/builder" +(for Mac: alias yanet-builder="docker run --platform linux/amd64 --rm -it -v /run/yanet:/run/yanet -v \$PWD:/project yanetplatform/builder") ``` Once setup `build_autotest` directory: @@ -59,6 +60,31 @@ For more information about the autotests run: ``` yanet-builder ./autotest/yanet-autotest-run.py -h ``` + +## Running Unit Tests + +To run the unit tests for the project, follow these steps: + +Setup the build directory for unittest targeting: +```sh +meson setup -Dtarget=unittest build_unittest +``` +Next, compile the project within the setup build directory: + +```sh +meson compile -C build_unittest +``` + +After compilation, run all the unit tests with: + +```sh +meson test -C build_unittest +``` +- To view more detailed output, you can run the tests with -v flag: + +```sh +meson test -C build_unittest -v +``` ## Dependencies - [DPDK](https://github.com/DPDK/dpdk) - [JSON](https://github.com/nlohmann/json) diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index 1930d955..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; @@ -78,6 +77,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; } @@ -121,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) { @@ -136,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; } @@ -163,7 +167,7 @@ eResult tAutotest::initSharedMemory() for (const auto& shmInfo : dataPlaneSharedMemory) { - std::string tag = std::get<1>(shmInfo); + std::string name = std::get<0>(shmInfo); unsigned int unitSize = std::get<2>(shmInfo); unsigned int unitsNumber = std::get<3>(shmInfo); key_t ipcKey = std::get<6>(shmInfo); @@ -171,7 +175,7 @@ eResult tAutotest::initSharedMemory() void* shm = shm_by_key[ipcKey]; auto memaddr = (void*)((intptr_t)shm + offset); - dumpRings[tag] = common::bufferring(memaddr, unitSize, unitsNumber); + dumpRings[name] = common::bufferring(memaddr, unitSize, unitsNumber); } return eResult::success; @@ -235,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]; @@ -406,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"); @@ -436,7 +440,7 @@ class PcapDumper pcap_dump((u_char*)dumper, header, data); } - std::string path() const + [[nodiscard]] std::string path() const { return tmpFilePath; } @@ -474,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); @@ -504,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)); @@ -524,7 +528,7 @@ class pcap_expectation } } - bool has_unmatched_packets() const + [[nodiscard]] bool has_unmatched_packets() const { return has_packet; } @@ -536,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; } @@ -566,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; }; @@ -715,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; @@ -738,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()) @@ -868,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; } } @@ -890,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"]) { @@ -1193,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)); @@ -1354,7 +1343,12 @@ void tAutotest::mainThread() { bool result = true; - if (yamlStep["ipv4Update"]) + if (yamlStep["subtest"]) + { + auto test_name = yamlStep["subtest"].as(); + YANET_LOG_PRINT(ANSI_COLOR_BLUE "Running subtest: '%s'\n" ANSI_COLOR_RESET, test_name.c_str()); + } + else if (yamlStep["ipv4Update"]) { YANET_LOG_DEBUG("step: ipv4Update\n"); @@ -1527,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, @@ -1564,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); @@ -1608,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, @@ -1625,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); @@ -1741,7 +1735,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()) { @@ -1800,7 +1794,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()) { @@ -1854,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; } @@ -1906,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; } @@ -1916,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()) @@ -1931,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); @@ -1943,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 @@ -1988,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); } } @@ -2013,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 edd2c840..1725a16c 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/sdpcommon.h" namespace nAutotest { @@ -35,7 +36,7 @@ class tAutotest { public: tAutotest(); - ~tAutotest(); + ~tAutotest() = default; eResult init(const std::string& binaryPath, bool dumpPackets, @@ -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/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/autotest/units/001_one_port/036_firewall_keepstate/autotest.yaml b/autotest/units/001_one_port/036_firewall_keepstate/autotest.yaml index f79a3246..79c2772d 100644 --- a/autotest/units/001_one_port/036_firewall_keepstate/autotest.yaml +++ b/autotest/units/001_one_port/036_firewall_keepstate/autotest.yaml @@ -1,6 +1,21 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/036_firewall_keepstate/controlplane_keepstate.conf b/autotest/units/001_one_port/036_firewall_keepstate/controlplane_keepstate.conf new file mode 100644 index 00000000..98d3dfec --- /dev/null +++ b/autotest/units/001_one_port/036_firewall_keepstate/controlplane_keepstate.conf @@ -0,0 +1,42 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/036_firewall_keepstate/firewall.txt b/autotest/units/001_one_port/036_firewall_keepstate/firewall.txt index 38585f7c..dd8d6708 100644 --- a/autotest/units/001_one_port/036_firewall_keepstate/firewall.txt +++ b/autotest/units/001_one_port/036_firewall_keepstate/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow udp from 11.0.0.0/24 to any 53 keep-state -add allow udp from any to 2a03:6b8:ff1c:2030::/60 53 keep-state +add allow udp from 11.0.0.0/24 to any 53 record-state +add allow udp from any to 2a03:6b8:ff1c:2030::/60 53 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/036_firewall_keepstate/firewall_keepstate.txt b/autotest/units/001_one_port/036_firewall_keepstate/firewall_keepstate.txt new file mode 100644 index 00000000..38585f7c --- /dev/null +++ b/autotest/units/001_one_port/036_firewall_keepstate/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow udp from 11.0.0.0/24 to any 53 keep-state +add allow udp from any to 2a03:6b8:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/autotest.yaml b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/autotest.yaml index d035a819..4796b30e 100644 --- a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/autotest.yaml +++ b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/autotest.yaml @@ -1,6 +1,40 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/controlplane_keepstate.conf b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/controlplane_keepstate.conf new file mode 100644 index 00000000..9e4cc575 --- /dev/null +++ b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/controlplane_keepstate.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall.txt b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall.txt index aabcef63..ffaa4284 100644 --- a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall.txt +++ b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow udp from 10.0.0.0/24 to any 53 keep-state -add allow udp from any to 2121:bbb8:ff1c:2030::/60 53 keep-state +add allow udp from 10.0.0.0/24 to any 53 record-state +add allow udp from any to 2121:bbb8:ff1c:2030::/60 53 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall_keepstate.txt b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall_keepstate.txt new file mode 100644 index 00000000..aabcef63 --- /dev/null +++ b/autotest/units/001_one_port/037_firewall_keepstate_with_sync/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow udp from 10.0.0.0/24 to any 53 keep-state +add allow udp from any to 2121:bbb8:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/autotest.yaml b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/autotest.yaml index 03cef021..811d356b 100644 --- a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/autotest.yaml +++ b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/autotest.yaml @@ -1,6 +1,46 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: 007-expect.pcap +- cli: "fw list states | grep 'allow tcp from 2a22:6b8:ff1c:2030::1 12345 to 1111:2222::1 777' | grep 'flags SAF:SAF'" +- cli: "fw list states | grep 'allow tcp from 1.1.1.10 54321 to 12.0.0.10 10000' | grep 'flags S:S'" +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/controlplane_keepstate.conf b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/controlplane_keepstate.conf new file mode 100644 index 00000000..9e4cc575 --- /dev/null +++ b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/controlplane_keepstate.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall.txt b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall.txt index f23b28e8..084006e1 100644 --- a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall.txt +++ b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow tcp from 12.0.0.0/24 to any 12345 keep-state -add allow tcp from any to 2a22:6b8:ff1c:2030::/60 12345 keep-state +add allow tcp from 12.0.0.0/24 to any 12345 record-state +add allow tcp from any to 2a22:6b8:ff1c:2030::/60 12345 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall_keepstate.txt b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall_keepstate.txt new file mode 100644 index 00000000..f23b28e8 --- /dev/null +++ b/autotest/units/001_one_port/039_firewall_keepstate_with_sync_tcp/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 12.0.0.0/24 to any 12345 keep-state +add allow tcp from any to 2a22:6b8:ff1c:2030::/60 12345 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/autotest.yaml b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/autotest.yaml index 14d809f0..a053c054 100644 --- a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/autotest.yaml +++ b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/autotest.yaml @@ -1,6 +1,44 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: 007-expect.pcap +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/controlplane_keepstate.conf b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/controlplane_keepstate.conf new file mode 100644 index 00000000..9e4cc575 --- /dev/null +++ b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/controlplane_keepstate.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall.txt b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall.txt index 7ba1b01a..c68ee906 100644 --- a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall.txt +++ b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall.txt @@ -2,7 +2,8 @@ add skipto :IN ip from any to any in :IN -add allow ip from 13.0.0.0/24 to any keep-state -add allow ip from any to 2332:898:ff1c:2030::/64 keep-state -add allow tcp from 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: to 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: 10053 keep-state +add allow ip from 13.0.0.0/24 to any record-state +add allow ip from any to 2332:898:ff1c:2030::/64 record-state +add allow tcp from 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: to 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: 10053 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall_keepstate.txt b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall_keepstate.txt new file mode 100644 index 00000000..7ba1b01a --- /dev/null +++ b/autotest/units/001_one_port/040_firewall_keepstate_with_sync_mixed/firewall_keepstate.txt @@ -0,0 +1,8 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow ip from 13.0.0.0/24 to any keep-state +add allow ip from any to 2332:898:ff1c:2030::/64 keep-state +add allow tcp from 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: to 2332:898:ffee:0:0:5678::/ffff:ffff:ffff:0000:ffff:ffff:: 10053 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/autotest.yaml b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/autotest.yaml index 5bb93d47..d2263f5e 100644 --- a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/autotest.yaml +++ b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/autotest.yaml @@ -1,6 +1,8 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state - sendPackets: - port: kni0 send: 001-send.pcap @@ -10,3 +12,18 @@ steps: - port: kni0 send: 002-send.pcap expect: 002-expect.pcap +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- clearFWState: 1 diff --git a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/controlplane_keepstate.conf b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/controlplane_keepstate.conf new file mode 100644 index 00000000..9e4cc575 --- /dev/null +++ b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/controlplane_keepstate.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall.txt b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall.txt index b26438d7..75176e15 100644 --- a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall.txt +++ b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall.txt @@ -1,3 +1,4 @@ :BEGIN +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall_keepstate.txt b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall_keepstate.txt new file mode 100644 index 00000000..8c1fb879 --- /dev/null +++ b/autotest/units/001_one_port/041_firewall_keepstate_with_sync_multi_state_in_single_packet/firewall_keepstate.txt @@ -0,0 +1,3 @@ +:BEGIN +add deny ip from any to any keep-state + diff --git a/autotest/units/001_one_port/045_firewall_out/firewall.txt b/autotest/units/001_one_port/045_firewall_out/firewall.txt index 39d1f64b..2f4949f6 100644 --- a/autotest/units/001_one_port/045_firewall_out/firewall.txt +++ b/autotest/units/001_one_port/045_firewall_out/firewall.txt @@ -38,7 +38,7 @@ add deny ip from any to any :SKP2 add allow tcp from f805@2222:898:c00::/40 to { 2222:898:bf00:400::1 } 443 -add allow tcp from f805@2222:898:c00::/40 to { 2222:898:bf00:400::2 } 443 keep-state +add allow tcp from f805@2222:898:c00::/40 to { 2222:898:bf00:400::2 } 443 record-state add allow ip from any to any frag add deny tcp from any to any tcpflags rst diff --git a/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml b/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml index d7eafc9a..43d17796 100644 --- a/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml +++ b/autotest/units/001_one_port/050_firewall_state_resend/autotest.yaml @@ -1,6 +1,70 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 10 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 9 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: 007-expect.pcap +- sendPackets: + - port: kni0 + send: 008-send.pcap + expect: 008-expect.pcap +- sleep: 10 +- sendPackets: + - port: kni0 + send: 009-send.pcap + expect: 009-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 010-send.pcap + expect: 010-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 011-send.pcap + expect: 011-expect.pcap +- sleep: 9 +- sendPackets: + - port: kni0 + send: 012-send.pcap + expect: 012-expect.pcap +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/050_firewall_state_resend/controlplane_keepstate.conf b/autotest/units/001_one_port/050_firewall_state_resend/controlplane_keepstate.conf new file mode 100644 index 00000000..9e4cc575 --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/controlplane_keepstate.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "multicastDestinationPort": 11995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt b/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt index 9554503a..1959f6e5 100644 --- a/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt +++ b/autotest/units/001_one_port/050_firewall_state_resend/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow udp from 10.0.0.0/24 to any 53 keep-state -add allow udp from any to 2020:ddd:ff1c:2030::/60 53 keep-state +add allow udp from 10.0.0.0/24 to any 53 record-state +add allow udp from any to 2020:ddd:ff1c:2030::/60 53 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/050_firewall_state_resend/firewall_keepstate.txt b/autotest/units/001_one_port/050_firewall_state_resend/firewall_keepstate.txt new file mode 100644 index 00000000..9554503a --- /dev/null +++ b/autotest/units/001_one_port/050_firewall_state_resend/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow udp from 10.0.0.0/24 to any 53 keep-state +add allow udp from any to 2020:ddd:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/autotest.yaml b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/autotest.yaml index 9f1cc3e0..2b09840a 100644 --- a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/autotest.yaml +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/autotest.yaml @@ -1,6 +1,47 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap +- clearFWState: 1 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap +- sendPackets: + - port: kni0 + send: 005-send.pcap + expect: 005-expect.pcap +- sleep: 1 +- sendPackets: + - port: kni0 + send: 006-send.pcap + expect: 006-expect.pcap +- sendPackets: + - port: kni0 + send: 007-send.pcap + expect: + - 007-expect-tcp.pcap + - 007-expect-tech.pcap +- cli: "fw list states | grep 'allow tcp from 2220:ddd:ff1c:2030::1 12345 to 1111:2222::1 777' | grep 'flags SAF:SAF'" +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane_keepstate.conf b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane_keepstate.conf new file mode 100644 index 00000000..33910b06 --- /dev/null +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/controlplane_keepstate.conf @@ -0,0 +1,67 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.2000": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "2000", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "synchronization": { + "ipv6SourceAddress": "fe80::f1", + "multicastIpv6Address": "ff02::1", + "unicastIpv6SourceAddress": "3333::4444", + "unicastIpv6Address": "2222::1111", + "multicastDestinationPort": 11995, + "unicastDestinationPort": 21995, + "logicalPorts": [ + "lp0.2000" + ], + "ingressNextModule": "vrf0" + }, + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + }, + "kni0.2000": { + "ipAddresses": ["ff02::2000"], + "neighborIPv6Address": "fe80::2000", + "neighborMacAddress": "00:00:00:33:33:33", + "nextModule": "lp0.2000" + } + } + } + } +} diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt index 539109ae..dc5cdb30 100644 --- a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow tcp from 12.0.0.0/24 to any 12345 keep-state -add allow tcp from any to 2220:ddd:ff1c:2030::/60 12345 keep-state +add allow tcp from 12.0.0.0/24 to any 12345 record-state +add allow tcp from any to 2220:ddd:ff1c:2030::/60 12345 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall_keepstate.txt b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall_keepstate.txt new file mode 100644 index 00000000..539109ae --- /dev/null +++ b/autotest/units/001_one_port/051_firewall_keepstate_with_sync_unicast/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 12.0.0.0/24 to any 12345 keep-state +add allow tcp from any to 2220:ddd:ff1c:2030::/60 12345 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/052_firewall_samples/autotest.yaml b/autotest/units/001_one_port/052_firewall_samples/autotest.yaml index 1abe1fd5..a383fb56 100644 --- a/autotest/units/001_one_port/052_firewall_samples/autotest.yaml +++ b/autotest/units/001_one_port/052_firewall_samples/autotest.yaml @@ -1,6 +1,32 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" - ipv6Update: "::/0 -> fe80::1" + +- subtest: with check-state and record-state +- sleep: 1 +- cli: "samples show" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap +- cli: "samples dump | diff - TESTDIR/samples.json" +- clearFWState: 1 + +- reload: controlplane_keepstate.conf + +- subtest: with just keep-state - sleep: 1 - cli: "samples show" - sendPackets: diff --git a/autotest/units/001_one_port/052_firewall_samples/controlplane_keepstate.conf b/autotest/units/001_one_port/052_firewall_samples/controlplane_keepstate.conf new file mode 100644 index 00000000..ca255bcc --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/controlplane_keepstate.conf @@ -0,0 +1,43 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall_keepstate.txt", + "nextModules": [ + "vrf0" + ], + "storeSamples": true + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/052_firewall_samples/firewall.txt b/autotest/units/001_one_port/052_firewall_samples/firewall.txt index d9986a09..8659e613 100644 --- a/autotest/units/001_one_port/052_firewall_samples/firewall.txt +++ b/autotest/units/001_one_port/052_firewall_samples/firewall.txt @@ -2,6 +2,7 @@ add skipto :IN ip from any to any in :IN -add allow tcp from 11.0.0.0/24 to any 53 keep-state -add allow tcp from any to 2111:aaa:ff1c:2030::/60 53 keep-state +add allow tcp from 11.0.0.0/24 to any 53 record-state +add allow tcp from any to 2111:aaa:ff1c:2030::/60 53 record-state +add check-state add deny ip from any to any diff --git a/autotest/units/001_one_port/052_firewall_samples/firewall_keepstate.txt b/autotest/units/001_one_port/052_firewall_samples/firewall_keepstate.txt new file mode 100644 index 00000000..d9986a09 --- /dev/null +++ b/autotest/units/001_one_port/052_firewall_samples/firewall_keepstate.txt @@ -0,0 +1,7 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add allow tcp from 11.0.0.0/24 to any 53 keep-state +add allow tcp from any to 2111:aaa:ff1c:2030::/60 53 keep-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml b/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml index 41862999..f1b4ae9d 100644 --- a/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml +++ b/autotest/units/001_one_port/059_firewall_tablearg/autotest.yaml @@ -1,7 +1,8 @@ steps: - ipv4Update: "0.0.0.0/0 -> 200.0.0.1" -- clearFWState: +- clearFWState: 1 - sendPackets: - port: kni0 send: 001-send.pcap expect: 001-expect.pcap +- clearFWState: 1 diff --git a/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt b/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt index e8c2346d..66f4d26d 100644 --- a/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt +++ b/autotest/units/001_one_port/059_firewall_tablearg/firewall.conf.txt @@ -35,5 +35,5 @@ add deny log logamount 500 all from any to any :TUN64_SKP5 add deny tcp from any to any setup add allow udp from any src-port 53 to any dst-port 1025-65535 -add allow ip from any to any keep-state in +add allow ip from any to any record-state in add deny log logamount 500 all from any to any diff --git a/autotest/units/001_one_port/067_dump_after_term/autotest.yaml b/autotest/units/001_one_port/067_dump_after_term/autotest.yaml index e6eb3fca..5a50389d 100644 --- a/autotest/units/001_one_port/067_dump_after_term/autotest.yaml +++ b/autotest/units/001_one_port/067_dump_after_term/autotest.yaml @@ -6,5 +6,5 @@ steps: send: 001-send.pcap expect: 001-expect.pcap - dumpPackets: - - ringTag: ring1 + - ringTag: shm_2_0 expect: 001-expect-dump-ring1.pcap diff --git a/autotest/units/001_one_port/067_dump_default/autotest.yaml b/autotest/units/001_one_port/067_dump_default/autotest.yaml index e6eb3fca..5a50389d 100644 --- a/autotest/units/001_one_port/067_dump_default/autotest.yaml +++ b/autotest/units/001_one_port/067_dump_default/autotest.yaml @@ -6,5 +6,5 @@ steps: send: 001-send.pcap expect: 001-expect.pcap - dumpPackets: - - ringTag: ring1 + - ringTag: shm_2_0 expect: 001-expect-dump-ring1.pcap diff --git a/autotest/units/001_one_port/067_dump_with_deny/autotest.yaml b/autotest/units/001_one_port/067_dump_with_deny/autotest.yaml index e6eb3fca..5a50389d 100644 --- a/autotest/units/001_one_port/067_dump_with_deny/autotest.yaml +++ b/autotest/units/001_one_port/067_dump_with_deny/autotest.yaml @@ -6,5 +6,5 @@ steps: send: 001-send.pcap expect: 001-expect.pcap - dumpPackets: - - ringTag: ring1 + - ringTag: shm_2_0 expect: 001-expect-dump-ring1.pcap diff --git a/autotest/units/001_one_port/067_intersecting_dump_rules/autotest.yaml b/autotest/units/001_one_port/067_intersecting_dump_rules/autotest.yaml index 0cdfb29e..d9204293 100644 --- a/autotest/units/001_one_port/067_intersecting_dump_rules/autotest.yaml +++ b/autotest/units/001_one_port/067_intersecting_dump_rules/autotest.yaml @@ -6,7 +6,7 @@ steps: send: 001-send.pcap expect: 001-expect.pcap - dumpPackets: - - ringTag: ring1 + - ringTag: shm_2_0 expect: 001-expect-dump-ring1.pcap - - ringTag: ring2 + - ringTag: shm_2_1 expect: 001-expect-dump-ring2.pcap diff --git a/autotest/units/001_one_port/075_counters_route/autotest.yaml b/autotest/units/001_one_port/075_counters_route/autotest.yaml new file mode 100644 index 00000000..f9f81f55 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route/autotest.yaml @@ -0,0 +1,89 @@ +steps: + +# default (see neighbor in controlplane.conf) +- cli: | + rib static insert default 0.0.0.0/0 200.0.2.1 + +################################################################################################################# +# 1 prepare rib +################################################################################################################# +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 10.10.10.1 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 200.0.3.1 + prefix: 1.0.0.0/24 + path_information: 200.0.2.1:10001 + labels: + - 1100 + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 200.0.4.1 + prefix: 2.0.0.0/24 + path_information: 200.0.3.1:10002 + labels: + - 1100 + - table_name: ipv4 mpls-vpn + peer: 10.10.10.2 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 200.0.5.1 + prefix: 3.0.0.0/24 + path_information: 200.0.3.1:10003 + labels: + - 1100 + +- cli_check: | + rib + vrf priority protocol peer table_name prefixes paths eor + ------- -------- -------- ---------- ------------- -------- ----- ----- + default 10000 autotest 10.10.10.1 ipv4 mpls-vpn 1 1 false + default 10000 autotest 10.10.10.2 ipv4 mpls-vpn 2 2 false + default 10000 static :: 2 2 true + +- cli_check: | + rib prefixes + vrf priority prefix protocol peer table_name path_information nexthop labels local_preference aspath origin med communities large_communities + ------- -------- ---------- -------- ---------- ------------- ---------------- --------- ------ ---------------- ------ ---------- --- ----------- ----------------- + default 10000 0.0.0.0/0 static :: 200.0.2.1 200.0.2.1 0 0 n/s n/s + default 10000 1.0.0.0/24 autotest 10.10.10.1 ipv4 mpls-vpn 200.0.2.1:10001 200.0.3.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 2.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 200.0.3.1:10002 200.0.4.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 3.0.0.0/24 autotest 10.10.10.2 ipv4 mpls-vpn 200.0.3.1:10003 200.0.5.1 1100 0 incomplete 0 n/s 13238:1:1 + default 10000 fe80::/64 static :: :: 0 0 n/s n/s + +- cli_check: | + route tunnel get route0 1.0.0.0/24 + ingress_physical_ports nexthop label egress_interface peer weight (%) + ---------------------- --------- ----- ---------------- ---- ---------- + kni0 200.0.3.1 1100 kni0.200 100.00 + +################################################################################################################# +# 2 send packets and check route counters +################################################################################################################# + +- sendPackets: + - port: kni0 + send: send.pcap + expect: expect.pcap + +- cli: + - route counters + +- cli: + - telegraf route + +# cleanup +- cli: | + rib static remove default 0.0.0.0/0 200.0.2.1 diff --git a/autotest/units/001_one_port/075_counters_route/controlplane.conf b/autotest/units/001_one_port/075_counters_route/controlplane.conf new file mode 100644 index 00000000..2808ddc2 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route/controlplane.conf @@ -0,0 +1,64 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.300": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "300", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "lp0.400": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "400", + "macAddress": "00:11:22:33:44:55", + "nextModule": "route0" + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.2.0/24", + "neighborIPv4Address": "200.0.2.1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.200" + }, + "kni0.300": { + "ipv4Prefix": "200.0.2.0/24", + "neighborIPv4Address": "200.0.3.1", + "neighborMacAddress": "00:00:00:11:11:22", + "nextModule": "lp0.300" + }, + "kni0.400": { + "ipv4Prefix": "200.0.3.0/24", + "neighborIPv4Address": "200.0.4.1", + "neighborMacAddress": "00:00:00:11:11:33", + "nextModule": "lp0.400" + }, + "kni0.500": { + "ipv4Prefix": "200.0.3.0/24", + "neighborIPv4Address": "200.0.5.1", + "neighborMacAddress": "00:00:00:11:11:55", + "nextModule": "lp0.400" + } + } + } + } +} diff --git a/autotest/units/001_one_port/075_counters_route/expect.pcap b/autotest/units/001_one_port/075_counters_route/expect.pcap new file mode 100644 index 00000000..65c6e28e Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route/expect.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route/gen.py b/autotest/units/001_one_port/075_counters_route/gen.py new file mode 100644 index 00000000..15288f2f --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route/gen.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + +load_contrib("mpls") + +write_pcap("send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.2", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="1.0.0.3", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="2.0.0.4", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="2.0.0.5", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="3.0.0.6", src="111.222.111.222", ttl=64)/TCP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="4.0.0.7", src="111.222.111.222", ttl=64)/TCP()) + +write_pcap("expect.pcap", + Ether(dst="00:00:00:11:11:22", src="00:11:22:33:44:55")/Dot1Q(vlan=300)/MPLS(label=1100, ttl=0xff)/IP(dst="1.0.0.1", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:22", src="00:11:22:33:44:55")/Dot1Q(vlan=300)/MPLS(label=1100, ttl=0xff)/IP(dst="1.0.0.2", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:22", src="00:11:22:33:44:55")/Dot1Q(vlan=300)/MPLS(label=1100, ttl=0xff)/IP(dst="1.0.0.3", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:33", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/MPLS(label=1100, ttl=0xff)/IP(dst="2.0.0.4", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:33", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/MPLS(label=1100, ttl=0xff)/IP(dst="2.0.0.5", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:55", src="00:11:22:33:44:55")/Dot1Q(vlan=400)/MPLS(label=1100, ttl=0xff)/IP(dst="3.0.0.6", src="111.222.111.222", ttl=63)/TCP(), + Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="4.0.0.7", src="111.222.111.222", ttl=63)/TCP()) diff --git a/autotest/units/001_one_port/075_counters_route/send.pcap b/autotest/units/001_one_port/075_counters_route/send.pcap new file mode 100644 index 00000000..9aa4bf0f Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route/send.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/001-expect.pcap b/autotest/units/001_one_port/075_counters_route_tunnel/001-expect.pcap new file mode 100644 index 00000000..dbc9c061 Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route_tunnel/001-expect.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/001-send.pcap b/autotest/units/001_one_port/075_counters_route_tunnel/001-send.pcap new file mode 100644 index 00000000..83750c84 Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route_tunnel/001-send.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/002-expect.pcap b/autotest/units/001_one_port/075_counters_route_tunnel/002-expect.pcap new file mode 100644 index 00000000..909e6e61 Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route_tunnel/002-expect.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/002-send.pcap b/autotest/units/001_one_port/075_counters_route_tunnel/002-send.pcap new file mode 100644 index 00000000..85f10e3f Binary files /dev/null and b/autotest/units/001_one_port/075_counters_route_tunnel/002-send.pcap differ diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/autotest.yaml b/autotest/units/001_one_port/075_counters_route_tunnel/autotest.yaml new file mode 100644 index 00000000..db8f93ac --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route_tunnel/autotest.yaml @@ -0,0 +1,133 @@ +steps: +- rib_insert: + attribute: + protocol: autotest + tables: + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.0/24 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.0/24 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.254/32 + path_information: 88.88.88.1:11000 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.254/32 + path_information: 88.88.88.2:11001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:1 + prefixes: + - nexthop: 8888::1 + prefix: 7e57::/64 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::/64 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - nexthop: 8888::1 + prefix: 7e57::fffe/128 + path_information: 88.88.88.1:9999 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffe/128 + path_information: 88.88.88.2:15000 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + large_communities: + - 13238:1:0 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.253/32 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.253/32 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv4 mpls-vpn + peer: 0.0.0.0 + med: 0 + prefixes: + - nexthop: 88.88.88.1 + prefix: 1.0.0.252/32 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 88.88.88.2 + prefix: 1.0.0.252/32 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + large_communities: + - 13238:1:0 + prefixes: + - nexthop: 8888::1 + prefix: 7e57::fffd/128 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffd/128 + path_information: 88.88.88.2:10001 + labels: + - 1200 + - table_name: ipv6 mpls-vpn + prefixes: + - nexthop: 8888::1 + prefix: 7e57::fffc/128 + path_information: 88.88.88.1:10001 + labels: + - 1100 + - nexthop: 8888::2 + prefix: 7e57::fffc/128 + path_information: 88.88.88.2:10001 + labels: + - 1200 +- ipv4Update: + - "0.0.0.0/0 -> 100.0.0.1 200.0.0.1" +- ipv6Update: + - "::/0 -> c0de::100:1 c0de::200:1" +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +- cli: + - route tunnel counters + +- cli: + - telegraf route tunnel diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/controlplane.conf b/autotest/units/001_one_port/075_counters_route_tunnel/controlplane.conf new file mode 100644 index 00000000..224078a3 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route_tunnel/controlplane.conf @@ -0,0 +1,69 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "decap0", + "decap1" + ] + }, + "decap0": { + "type": "decap", + "ipv6DestinationPrefixes": [ + "2222::aaaa/128" + ], + "nextModule": "route0" + }, + "decap1": { + "type": "decap", + "ipv6DestinationPrefixes": [ + "2222::cccc/128" + ], + "ipv6_enabled": true, + "nextModule": "route0:tunnel" + }, + "route0": { + "type": "route", + "ipv4SourceAddress": "10.50.0.1", + "ipv6SourceAddress": "2222:1111:0:1234:5678:0101:ca11:ca11", + "udpDestinationPort": 6635, + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "100.0.0.1", + "neighborIPv6Address": "c0de::100:1", + "neighborMacAddress": "00:00:00:00:00:01", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv4Address": "200.0.0.1", + "neighborIPv6Address": "c0de::200:1", + "neighborMacAddress": "00:00:00:00:00:02", + "nextModule": "lp0.200" + } + }, + "localPrefixes": [ + "1.0.0.255/32", + "7e57::ffff/128" + ], + "peers": { + "1": "A", + "2": "B", + "3": "C" + } + } + } +} diff --git a/autotest/units/001_one_port/075_counters_route_tunnel/gen.py b/autotest/units/001_one_port/075_counters_route_tunnel/gen.py new file mode 100755 index 00000000..0629de99 --- /dev/null +++ b/autotest/units/001_one_port/075_counters_route_tunnel/gen.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * +from scapy.contrib.mpls import MPLS + + +def write_pcap(filename, *packetsList): + if len(packetsList) == 0: + PcapWriter(filename)._write_header(Ether()) + return + + PcapWriter(filename) + + for packets in packetsList: + if type(packets) == list: + for packet in packets: + packet.time = 0 + wrpcap(filename, [p for p in packet], append=True) + else: + packets.time = 0 + wrpcap(filename, [p for p in packets], append=True) + + +write_pcap("001-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::2", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::3", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::4", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::5", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::6", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::7", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::8", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::9", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::10", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::11", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::12", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::13", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::14", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::15", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::16", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP()) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP()) + +write_pcap("002-send.pcap", + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=1)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=2)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=3)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=4)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=5)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=6)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=7)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=8)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=9)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=10)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=11)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=12)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=13)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=14)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=15)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP(), + Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:01")/Dot1Q(vlan=100)/IPv6(dst="2222::cccc", src="::1", fl=16)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=64)/ICMP()) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x00d4 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x89ed | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x2355 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x9b9f | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x3127 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xb81e | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x12a6 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xc98a | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x6332 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xea0b | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.2", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x40b3 | 0xc000, chksum=0)/MPLS(label=1200, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xf879 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x52c1 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xdbf8 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x7140 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP(), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="88.88.88.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x1b51 | 0xc000, chksum=0)/MPLS(label=1100, ttl=255)/IP(dst="1.0.0.1", src="0.0.0.0", ttl=63)/ICMP()) + + 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/units/001_one_port/077_state_timeout/001-expect.pcap b/autotest/units/001_one_port/077_state_timeout/001-expect.pcap new file mode 100644 index 00000000..fddb8179 Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout/001-expect.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout/001-send.pcap b/autotest/units/001_one_port/077_state_timeout/001-send.pcap new file mode 100644 index 00000000..6bd24cbe Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout/001-send.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout/autotest.yaml b/autotest/units/001_one_port/077_state_timeout/autotest.yaml new file mode 100644 index 00000000..3f62be71 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout/autotest.yaml @@ -0,0 +1,36 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 10.0.0.2" + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +- cli: fw list states | grep -q "allow tcp from 10.0.0.1 80 to 10.0.0.2 12345" + +- sleep: 6 # Wait for state to expire + +- cli_check: | + fw list states + id ruleno label rule + -- ------ ----- ---- + +- clearFWState: 1 + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +- cli: fw list states | grep -q "allow tcp from 10.0.0.1 80 to 10.0.0.2 12345" + +- sleep: 3 # Wait but state should still be present + +- cli: fw list states | grep -q "allow tcp from 10.0.0.1 80 to 10.0.0.2 12345" + +- sleep: 3 # Wait for state to expire + +- cli_check: | + fw list states + id ruleno label rule + -- ------ ----- ---- diff --git a/autotest/units/001_one_port/077_state_timeout/controlplane.conf b/autotest/units/001_one_port/077_state_timeout/controlplane.conf new file mode 100644 index 00000000..7cbab619 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout/controlplane.conf @@ -0,0 +1,26 @@ +{ + "modules": { + "lp0": { + "type": "logicalPort", + "physicalPort": "kni0", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": ["vrf0"] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0": { + "ipv4Prefix": "10.0.0.1/24", + "neighborIPv4Address": "10.0.0.2", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0" + } + } + } + } +} diff --git a/autotest/units/001_one_port/077_state_timeout/firewall.txt b/autotest/units/001_one_port/077_state_timeout/firewall.txt new file mode 100644 index 00000000..a719ec80 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout/firewall.txt @@ -0,0 +1,9 @@ +:BEGIN +add state-timeout 1 ip from any to any +add state-timeout 2 ip from any to any +add state-timeout 3 ip from any to any +add state-timeout 4 ip from any to any +add state-timeout 5 ip from any to any +# only the last occurence matters +add allow ip from any to any keep-state + diff --git a/autotest/units/001_one_port/077_state_timeout/gen.py b/autotest/units/001_one_port/077_state_timeout/gen.py new file mode 100644 index 00000000..1c886159 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout/gen.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List + +from scapy.layers.inet import IP, TCP +from scapy.layers.l2 import Ether +from scapy.packet import Packet +from scapy.utils import PcapWriter + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path, sync=True) as fh: + for p in packets: + fh.write(p) + +def ipv4_send(src: str, dst: str) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / IP(src=src, dst=dst, ttl=64) + +def ipv4_recv(src: str, dst: str) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / IP(src=src, dst=dst, ttl=63) + +# Send packet from 10.0.0.2 to 10.0.0.1 +write_pcap("001-send.pcap", [ + ipv4_send("10.0.0.2", "10.0.0.1") / TCP(sport=12345, dport=80, flags="S"), +]) + +# Expect the packet forwarded +write_pcap("001-expect.pcap", [ + ipv4_recv("10.0.0.2", "10.0.0.1") / TCP(sport=12345, dport=80, flags="S"), +]) diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/001-expect.pcap b/autotest/units/001_one_port/077_state_timeout_different_groups/001-expect.pcap new file mode 100644 index 00000000..0eeb4fa9 Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_different_groups/001-expect.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/001-send.pcap b/autotest/units/001_one_port/077_state_timeout_different_groups/001-send.pcap new file mode 100644 index 00000000..6f39337a Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_different_groups/001-send.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/autotest.yaml b/autotest/units/001_one_port/077_state_timeout_different_groups/autotest.yaml new file mode 100644 index 00000000..5a6d588b --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_different_groups/autotest.yaml @@ -0,0 +1,38 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 10.0.0.2" + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +- cli_check: | + fw list states + id ruleno label rule + -------- -------- ----- ------------------------------------------------------------------------------------------------ + 16777215 16777215 allow tcp from 10.0.0.1 80 to 192.168.1.10 12345 [own, last seen: 2s ago flags S:][packets: 0/0] + 16777216 16777215 allow tcp from 10.0.0.1 80 to 192.168.2.20 12346 [own, last seen: 2s ago flags S:][packets: 0/0] + +- sleep: 3 # Wait, states should still be present + +- cli_check: | + fw list states + id ruleno label rule + -------- -------- ----- ------------------------------------------------------------------------------------------------ + 16777215 16777215 allow tcp from 10.0.0.1 80 to 192.168.1.10 12345 [own, last seen: 5s ago flags S:][packets: 0/0] + 16777216 16777215 allow tcp from 10.0.0.1 80 to 192.168.2.20 12346 [own, last seen: 5s ago flags S:][packets: 0/0] + +- sleep: 3 # Wait for first state to expire (total sleep 6s) + +- cli_check: | + fw list states + id ruleno label rule + -------- -------- ----- ------------------------------------------------------------------------------------------------ + 16777215 16777215 allow tcp from 10.0.0.1 80 to 192.168.2.20 12346 [own, last seen: 8s ago flags S:][packets: 0/0] + +- sleep: 3 # Wait for second state to expire (total sleep 9s) + +- cli_check: | + fw list states + id ruleno label rule + -- ------ ----- ---- diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/controlplane.conf b/autotest/units/001_one_port/077_state_timeout_different_groups/controlplane.conf new file mode 100644 index 00000000..7cbab619 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_different_groups/controlplane.conf @@ -0,0 +1,26 @@ +{ + "modules": { + "lp0": { + "type": "logicalPort", + "physicalPort": "kni0", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": ["vrf0"] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0": { + "ipv4Prefix": "10.0.0.1/24", + "neighborIPv4Address": "10.0.0.2", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0" + } + } + } + } +} diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/firewall.txt b/autotest/units/001_one_port/077_state_timeout_different_groups/firewall.txt new file mode 100644 index 00000000..673febc8 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_different_groups/firewall.txt @@ -0,0 +1,4 @@ +:BEGIN +add state-timeout 5 ip from 192.168.1.0/24 to any +add state-timeout 10 ip from 192.168.2.0/24 to any +add allow ip from any to any keep-state diff --git a/autotest/units/001_one_port/077_state_timeout_different_groups/gen.py b/autotest/units/001_one_port/077_state_timeout_different_groups/gen.py new file mode 100644 index 00000000..9b7bc692 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_different_groups/gen.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List + +from scapy.layers.inet import IP, TCP +from scapy.layers.l2 import Ether +from scapy.packet import Packet +from scapy.utils import PcapWriter + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path, sync=True) as fh: + for p in packets: + fh.write(p) + +def ipv4_send(src: str, dst: str, ttl: int = 64) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / IP(src=src, dst=dst, ttl=ttl) + +def ipv4_recv(src: str, dst: str, ttl: int = 63) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / IP(src=src, dst=dst, ttl=ttl) + +# Send packets from two different subnets +write_pcap("001-send.pcap", [ + ipv4_send("192.168.1.10", "10.0.0.1") / TCP(sport=12345, dport=80, flags="S"), + ipv4_send("192.168.2.20", "10.0.0.1") / TCP(sport=12346, dport=80, flags="S"), +]) + +# Expect the same packets forwarded +write_pcap("001-expect.pcap", [ + ipv4_recv("192.168.1.10", "10.0.0.1") / TCP(sport=12345, dport=80, flags="S"), + ipv4_recv("192.168.2.20", "10.0.0.1") / TCP(sport=12346, dport=80, flags="S"), +]) diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect-dump-ring1.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect-dump-ring1.pcap new file mode 100644 index 00000000..c0cc6615 Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect-dump-ring1.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect.pcap new file mode 100644 index 00000000..535358ac Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/001-expect.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/001-send.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/001-send.pcap new file mode 100644 index 00000000..4ea57dfb Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/001-send.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect-dump-ring1.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect-dump-ring1.pcap new file mode 100644 index 00000000..8c9d89d8 Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect-dump-ring1.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect.pcap new file mode 100644 index 00000000..bcd52bf0 Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/002-expect.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/002-send.pcap b/autotest/units/001_one_port/077_state_timeout_with_dump/002-send.pcap new file mode 100644 index 00000000..bc24465e Binary files /dev/null and b/autotest/units/001_one_port/077_state_timeout_with_dump/002-send.pcap differ diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/autotest.yaml b/autotest/units/001_one_port/077_state_timeout_with_dump/autotest.yaml new file mode 100644 index 00000000..0f7310a8 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_with_dump/autotest.yaml @@ -0,0 +1,47 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 10.0.0.2" + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +- dumpPackets: + - ringTag: shm_2_0 + expect: 001-expect-dump-ring1.pcap + +- cli: fw list states | grep -q "allow udp from 10.0.0.1 53 to 10.0.0.10 1024" + +- sleep: 3 # Wait, state should still be present + +- cli: fw list states | grep -q "allow udp from 10.0.0.1 53 to 10.0.0.10 1024" + +- sleep: 3 # Wait for state to expire (total sleep 6s) + +- cli_check: | + fw list states + id ruleno label rule + -- ------ ----- ---- + +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +- dumpPackets: + - ringTag: shm_2_0 + expect: 002-expect-dump-ring1.pcap + +- cli: fw list states | grep -q "allow udp from 10.0.0.1 53 to 10.0.0.10 1024" + +- sleep: 3 # Wait, state should still be present + +- cli: fw list states | grep -q "allow udp from 10.0.0.1 53 to 10.0.0.10 1024" + +- sleep: 3 # Wait for state to expire (total sleep 6s) + +- cli_check: | + fw list states + id ruleno label rule + -- ------ ----- ---- + diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/controlplane.conf b/autotest/units/001_one_port/077_state_timeout_with_dump/controlplane.conf new file mode 100644 index 00000000..7cbab619 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_with_dump/controlplane.conf @@ -0,0 +1,26 @@ +{ + "modules": { + "lp0": { + "type": "logicalPort", + "physicalPort": "kni0", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": ["vrf0"] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0": { + "ipv4Prefix": "10.0.0.1/24", + "neighborIPv4Address": "10.0.0.2", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0" + } + } + } + } +} diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/firewall.txt b/autotest/units/001_one_port/077_state_timeout_with_dump/firewall.txt new file mode 100644 index 00000000..1bec0169 --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_with_dump/firewall.txt @@ -0,0 +1,6 @@ +:BEGIN +add state-timeout 5 ip from any to any +add check-state +add dump ring1 ip from any to any +add allow udp from 10.0.0.0/24 to any 53 record-state +add deny ip from any to any diff --git a/autotest/units/001_one_port/077_state_timeout_with_dump/gen.py b/autotest/units/001_one_port/077_state_timeout_with_dump/gen.py new file mode 100644 index 00000000..83ce705a --- /dev/null +++ b/autotest/units/001_one_port/077_state_timeout_with_dump/gen.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List + +from scapy.layers.inet import IP, UDP +from scapy.layers.l2 import Ether +from scapy.packet import Packet +from scapy.utils import PcapWriter + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path, sync=True) as fh: + for p in packets: + fh.write(p) + +def ipv4_send(src: str, dst: str, ttl: int = 64) -> Packet: + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / IP(src=src, dst=dst, ttl=ttl) + +def ipv4_recv(src: str, dst: str, ttl: int = 63) -> Packet: + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / IP(src=src, dst=dst, ttl=ttl) + +# Initial packet to create state +write_pcap("001-send.pcap", [ + ipv4_send("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) + +# Expect the packet to be forwarded +write_pcap("001-expect.pcap", [ + ipv4_recv("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) + +# Expected dump (initial packet) +write_pcap("001-expect-dump-ring1.pcap", [ + ipv4_send("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) + +# Packet after state expiration +write_pcap("002-send.pcap", [ + ipv4_send("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) + +# Expect the packet to be forwarded +write_pcap("002-expect.pcap", [ + ipv4_recv("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) + +# Expected dump after state expiration +write_pcap("002-expect-dump-ring1.pcap", [ + ipv4_send("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), #result of a first dump (the ring is the same) + ipv4_send("10.0.0.10", "10.0.0.1") / UDP(sport=1024, dport=53), +]) diff --git a/autotest/units/001_one_port/078_hitcount_one/001-expect.pcap b/autotest/units/001_one_port/078_hitcount_one/001-expect.pcap new file mode 100644 index 00000000..8c851b70 Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/001-expect.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/001-send.pcap b/autotest/units/001_one_port/078_hitcount_one/001-send.pcap new file mode 100644 index 00000000..9bb180df Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/001-send.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/002-expect.pcap b/autotest/units/001_one_port/078_hitcount_one/002-expect.pcap new file mode 100644 index 00000000..d2b8041f Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/002-expect.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/002-send.pcap b/autotest/units/001_one_port/078_hitcount_one/002-send.pcap new file mode 100644 index 00000000..c20089e4 Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/002-send.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/003-expect.pcap b/autotest/units/001_one_port/078_hitcount_one/003-expect.pcap new file mode 100644 index 00000000..2a5d13a2 Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/003-expect.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/003-send.pcap b/autotest/units/001_one_port/078_hitcount_one/003-send.pcap new file mode 100644 index 00000000..be00839c Binary files /dev/null and b/autotest/units/001_one_port/078_hitcount_one/003-send.pcap differ diff --git a/autotest/units/001_one_port/078_hitcount_one/autotest.yaml b/autotest/units/001_one_port/078_hitcount_one/autotest.yaml new file mode 100644 index 00000000..f99a66e8 --- /dev/null +++ b/autotest/units/001_one_port/078_hitcount_one/autotest.yaml @@ -0,0 +1,45 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 10.0.0.2" + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + + # Check hitcount dump. The single packet matches "c1". + # Packet size calculation: + # - Ethernet Header: 14 bytes + # - IPv4 Header: 20 bytes + # - TCP Header: 20 bytes + # - Payload: 50 bytes + # Total: 14 + 20 + 20 + 50 = 104 bytes +- cli_check: | + hitcount dump acl + [ + c1: 1, 104 + ] + +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + + # Check hitcount dump. Two packets now match "c1". + # Byte count increments by 104 (packet size) for each additional packet. +- cli_check: | + hitcount dump acl + [ + c1: 2, 208 + ] + +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap + + # Check hitcount dump. Three packets now match "c1". +- cli_check: | + hitcount dump acl + [ + c1: 3, 312 + ] diff --git a/autotest/units/001_one_port/078_hitcount_one/controlplane.conf b/autotest/units/001_one_port/078_hitcount_one/controlplane.conf new file mode 100644 index 00000000..891769de --- /dev/null +++ b/autotest/units/001_one_port/078_hitcount_one/controlplane.conf @@ -0,0 +1,27 @@ +{ + "modules": { + "lp0": { + "type": "logicalPort", + "physicalPort": "kni0", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": ["vrf0"] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0": { + "ipv4Prefix": "10.0.0.1/24", + "neighborIPv4Address": "10.0.0.2", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0" + } + } + } + } +} + diff --git a/autotest/units/001_one_port/078_hitcount_one/firewall.txt b/autotest/units/001_one_port/078_hitcount_one/firewall.txt new file mode 100644 index 00000000..43638574 --- /dev/null +++ b/autotest/units/001_one_port/078_hitcount_one/firewall.txt @@ -0,0 +1,3 @@ +:BEGIN +add hitcount c1 ip from 10.0.0.2 to 10.0.0.1 +add allow ip from any to any keep-state diff --git a/autotest/units/001_one_port/078_hitcount_one/gen.py b/autotest/units/001_one_port/078_hitcount_one/gen.py new file mode 100644 index 00000000..0342e1c8 --- /dev/null +++ b/autotest/units/001_one_port/078_hitcount_one/gen.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List +from scapy.layers.inet import IP, TCP +from scapy.layers.l2 import Ether +from scapy.packet import Packet +from scapy.utils import PcapWriter + +def write_pcap(path: str, packets: List[Packet]) -> None: + with PcapWriter(path, sync=True) as fh: + for p in packets: + fh.write(p) + +def ipv4_send(src: str, dst: str, size: int) -> Packet: + payload = b"A" * size + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / IP(src=src, dst=dst, ttl=64) / TCP(sport=12345, dport=80, flags="S") / payload + +def ipv4_recv(src: str, dst: str, size: int) -> Packet: + payload = b"A" * size + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / IP(src=src, dst=dst, ttl=63) / TCP(sport=12345, dport=80, flags="S") / payload + +# Send packet from 10.0.0.2 to 10.0.0.1 +write_pcap("001-send.pcap", [ipv4_send("10.0.0.2", "10.0.0.1", 50)]) +write_pcap("001-expect.pcap", [ipv4_recv("10.0.0.2", "10.0.0.1", 50)]) + +# Send packet from 10.0.0.2 to 10.0.0.1 +write_pcap("002-send.pcap", [ipv4_send("10.0.0.2", "10.0.0.1", 50)]) +write_pcap("002-expect.pcap", [ipv4_recv("10.0.0.2", "10.0.0.1", 50)]) + +# Send packet from 10.0.0.2 to 10.0.0.1 +write_pcap("003-send.pcap", [ipv4_send("10.0.0.2", "10.0.0.1", 50)]) +write_pcap("003-expect.pcap", [ipv4_recv("10.0.0.2", "10.0.0.1", 50)]) + diff --git a/autotest/units/001_one_port/079_hitcount_many/001-expect.pcap b/autotest/units/001_one_port/079_hitcount_many/001-expect.pcap new file mode 100644 index 00000000..db887352 Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/001-expect.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/001-send.pcap b/autotest/units/001_one_port/079_hitcount_many/001-send.pcap new file mode 100644 index 00000000..7eefc865 Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/001-send.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/002-expect.pcap b/autotest/units/001_one_port/079_hitcount_many/002-expect.pcap new file mode 100644 index 00000000..75dd7ae5 Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/002-expect.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/002-send.pcap b/autotest/units/001_one_port/079_hitcount_many/002-send.pcap new file mode 100644 index 00000000..c6bf88d7 Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/002-send.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/003-expect.pcap b/autotest/units/001_one_port/079_hitcount_many/003-expect.pcap new file mode 100644 index 00000000..a3243045 Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/003-expect.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/003-send.pcap b/autotest/units/001_one_port/079_hitcount_many/003-send.pcap new file mode 100644 index 00000000..42cbbced Binary files /dev/null and b/autotest/units/001_one_port/079_hitcount_many/003-send.pcap differ diff --git a/autotest/units/001_one_port/079_hitcount_many/autotest.yaml b/autotest/units/001_one_port/079_hitcount_many/autotest.yaml new file mode 100644 index 00000000..e569beb0 --- /dev/null +++ b/autotest/units/001_one_port/079_hitcount_many/autotest.yaml @@ -0,0 +1,22 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" + +- sleep: 1 + +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap + +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap + +- sendPackets: + - port: kni0 + send: 003-send.pcap + expect: 003-expect.pcap + +- cli: "hitcount dump acl | diff - TESTDIR/hitcount_expected.txt" diff --git a/autotest/units/001_one_port/079_hitcount_many/controlplane.conf b/autotest/units/001_one_port/079_hitcount_many/controlplane.conf new file mode 100644 index 00000000..3c0da4fd --- /dev/null +++ b/autotest/units/001_one_port/079_hitcount_many/controlplane.conf @@ -0,0 +1,42 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:11:22:33:44:55", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "firewall": "firewall.txt", + "nextModules": [ + "vrf0" + ] + }, + "vrf0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipv6Prefix": "fe80::2/64", + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:00:11:11:11", + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipv4Prefix": "200.0.0.2/24", + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:00:22:22:22", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/079_hitcount_many/firewall.txt b/autotest/units/001_one_port/079_hitcount_many/firewall.txt new file mode 100644 index 00000000..3575c17c --- /dev/null +++ b/autotest/units/001_one_port/079_hitcount_many/firewall.txt @@ -0,0 +1,16 @@ +:BEGIN +add skipto :IN ip from any to any in + +:IN +add hitcount allow_tcp_from_11_0_0_0_24_to_any_53 tcp from 11.0.0.0/24 to any 53 +add allow tcp from 11.0.0.0/24 to any 53 record-state + +add hitcount allow_tcp_from_any_to_2111_aaa_ff1c_2030_60_53 tcp from any to 2111:aaa:ff1c:2030::/60 53 +add allow tcp from any to 2111:aaa:ff1c:2030::/60 53 record-state + +add hitcount check_state_ip_from_any_to_any ip from any to any +add check-state + +add hitcount deny_ip_from_any_to_any ip from any to any +add deny ip from any to any + diff --git a/autotest/units/001_one_port/079_hitcount_many/gen.py b/autotest/units/001_one_port/079_hitcount_many/gen.py new file mode 100644 index 00000000..e09e88d2 --- /dev/null +++ b/autotest/units/001_one_port/079_hitcount_many/gen.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import List, Optional + +from scapy.layers.inet import TCP, UDP, IP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Packet +from scapy.utils import PcapWriter + + +def write_pcap(path: str, packets: List[Packet], linktype: Optional[int] = None) -> None: + with PcapWriter(path, sync=True, linktype=linktype) as fh: + for p in packets: + fh.write(p) + + +def ipv4_send(src: str, dst: str, proto: Packet, payload_size: int) -> Packet: + payload = b"A" * payload_size + return Ether(dst="00:11:22:33:44:55", src="00:00:00:11:11:11") / \ + Dot1Q(vlan=100) / \ + IP(src=src, dst=dst, ttl=64) / \ + proto / \ + payload + + +def ipv4_recv(src: str, dst: str, proto: Packet, payload_size: int) -> Packet: + payload = b"A" * payload_size + return Ether(dst="00:00:00:22:22:22", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=200) / \ + IP(src=src, dst=dst, ttl=63) / \ + proto / \ + payload + + +def ipv6_send(src: str, dst: str, proto: Packet, payload_size: int) -> Packet: + payload = b"B" * payload_size + return Ether(dst="00:11:22:33:44:55", src="00:00:00:22:22:22") / \ + Dot1Q(vlan=200) / \ + IPv6(src=src, dst=dst, hlim=64, fl=0) / \ + proto / \ + payload + + +def ipv6_recv(src: str, dst: str, proto: Packet, payload_size: int) -> Packet: + payload = b"B" * payload_size + return Ether(dst="00:00:00:11:11:11", src="00:11:22:33:44:55") / \ + Dot1Q(vlan=100) / \ + IPv6(src=src, dst=dst, hlim=63, fl=0) / \ + proto / \ + payload + +write_pcap("001-send.pcap", [ + ipv4_send("11.0.0.1", "1.1.1.1", TCP(sport=1024, dport=53, flags="S"), payload_size=50), + ipv4_send("1.1.1.1", "11.0.0.1", TCP(sport=53, dport=1024, flags="S"), payload_size=30), +]) + +write_pcap("001-expect.pcap", [ + ipv4_recv("11.0.0.1", "1.1.1.1", TCP(sport=1024, dport=53, flags="S"), payload_size=50), + ipv4_recv("1.1.1.1", "11.0.0.1", TCP(sport=53, dport=1024, flags="S"), payload_size=30), +]) + +write_pcap("002-send.pcap", [ + ipv6_send("1111:2222::1", "2111:aaa:ff1c:2030::1", TCP(sport=1024, dport=53, flags="S"), payload_size=60), + ipv6_send("2111:aaa:ff1c:2030::1", "1111:2222::1", TCP(sport=53, dport=1024, flags="S"), payload_size=40), +]) + +write_pcap("002-expect.pcap", [ + ipv6_recv("1111:2222::1", "2111:aaa:ff1c:2030::1", TCP(sport=1024, dport=53, flags="S"), payload_size=60), + ipv6_recv("2111:aaa:ff1c:2030::1", "1111:2222::1", TCP(sport=53, dport=1024, flags="S"), payload_size=40), +]) + +write_pcap("003-send.pcap", [ + ipv4_send("2.2.2.2", "3.3.3.3", UDP(sport=1024, dport=80), payload_size=70), +]) + +write_pcap("003-expect.pcap", []) + + diff --git a/autotest/units/001_one_port/079_hitcount_many/hitcount_expected.txt b/autotest/units/001_one_port/079_hitcount_many/hitcount_expected.txt new file mode 100644 index 00000000..b808d3fa --- /dev/null +++ b/autotest/units/001_one_port/079_hitcount_many/hitcount_expected.txt @@ -0,0 +1,6 @@ +[ + allow_tcp_from_11_0_0_0_24_to_any_53: 1, 108 + check_state_ip_from_any_to_any: 3, 322 + allow_tcp_from_any_to_2111_aaa_ff1c_2030_60_53: 1, 138 + deny_ip_from_any_to_any: 1, 116 +] 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/build.sh b/build.sh index c2b352b6..214072c3 100755 --- a/build.sh +++ b/build.sh @@ -1,56 +1,80 @@ #!/bin/bash output="packages" -release="22.04" -version="64.0.0" +ubuntu_release="22.04" +yanet_version="64.0.0" usage() { - echo "Usage: $0 [ -o ARTIFACTS_DIR ] [ -r RELEASE ] [ -v VERSION ] -t package|image" + cat < transport_source, std::optional transport_destination, std::optional transport_flags, - std::optional keepstate) + std::optional recordstate) { std::optional module = in_module; @@ -38,7 +39,7 @@ void unwind(const std::string& in_module, optional_helper(transport_source); optional_helper(transport_destination); optional_helper(transport_flags); - optional_helper(keepstate); + optional_helper(recordstate); interface::controlPlane controlplane; auto response = controlplane.acl_unwind({module, @@ -50,41 +51,23 @@ void unwind(const std::string& in_module, transport_source, transport_destination, transport_flags, - keepstate}); - - table_t table({.optional_null = "any"}); - table.insert("module", - "direction", - "network_source", - "network_destination", - "fragment", - "protocol", - "transport_source", - "transport_destination", - "transport_flags", - "keepstate", - "next_module", - "ids", - "log"); - - for (const auto& [module, direction, network_source, network_destination, fragment, protocol, transport_source, transport_destination, transport_flags, keepstate, next_module, ids, log] : response) - { - table.insert(module, - direction, - network_source, - network_destination, - fragment, - protocol, - transport_source, - transport_destination, - transport_flags, - keepstate, - next_module, - ids, - log); - } - - table.print(); + recordstate}); + + 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 new file mode 100644 index 00000000..807c54ac --- /dev/null +++ b/cli/bus.h @@ -0,0 +1,155 @@ +#pragma once + +#include "helper.h" +#include "influxdb_format.h" +#include "table_printer.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(); + YANET_GCC_BUG_UNUSED(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::hitcount_dump, "hitcount_dump"}, + {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); + + TablePrinter table; + table.insert_row("request", "count", "duration_ms"); + for (const auto& [request, count, duration] : requests) + { + if ((count != 0) || (duration != 0)) + { + table.insert_row(request, count, duration); + } + } + + table.Print(); +} + +inline std::vector> get_bus_errors(const common::sdp::DataPlaneInSharedMemory& sdp_data) +{ + auto [requests, errors, durations] = sdp_data.BuffersBus(); + YANET_GCC_BUG_UNUSED(requests); + YANET_GCC_BUG_UNUSED(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); + + FillAndPrintTable({"error", "count"}, errors); +} + +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/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 88c4e0b7..b9c3ca67 100644 --- a/cli/develop.h +++ b/cli/develop.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,197 +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 = dataplane.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{}); } } @@ -205,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(); } @@ -215,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); } @@ -227,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 66890a57..7e9ba0db 100644 --- a/cli/helper.h +++ b/cli/helper.h @@ -1,468 +1,114 @@ #pragma once -#include #include -#include -#include -#include #include #include #include #include -#include - -#include "converter.h" +#include "common/sdpclient.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(); -} +#if defined(USE_FROM_CHARS) +#include +#else +#include +#endif -std::vector split(const char* string, - const char delimiter) +template +static void fill(T& value, const std::string& str) { - std::vector result; - std::stringstream ss(string); - - std::string part; - while (std::getline(ss, part, delimiter)) + if constexpr (std::is_same_v) { - result.emplace_back(part); + if (str == "true") + value = true; + else if (str == "false") + value = false; + else + throw std::invalid_argument("Invalid boolean value"); } - - return result; -} - -void fillValue(std::optional& value, const std::string& string) -{ - if (string == "any") + else if constexpr (std::is_integral_v || std::is_floating_point_v) { - value = std::nullopt; +#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 } - else if (string != "") + else if constexpr (traits::is_optional_v) { - value = std::stoull(string, nullptr, 0); - ; + if (str == "any" || str.empty()) + { + value.reset(); + } + else + { + typename T::value_type temp; + fill(temp, str); + value = std::move(temp); + } } else { - value = std::nullopt; + value = str; } } -void fillValue(std::optional& value, const std::string& string) +// Fill a tuple with values from a vector of strings +template +static void fillTupleImpl(Tuple& tuple, const std::vector& args, std::index_sequence) { - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = std::stoull(string, nullptr, 0); - ; - } - else - { - value = std::nullopt; - } + (..., fill(std::get(tuple), Is < args.size() ? args[Is] : std::string{})); } -void fillValue(std::optional& value, const std::string& string) +template +static void fillTuple(std::tuple& tuple, const std::vector& args) { - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = std::stoull(string, nullptr, 0); - ; - } - else - { - value = std::nullopt; - } + fillTupleImpl(tuple, args, std::index_sequence_for{}); } -template -void fillValue(std::optional& value, const std::string& string) +// Call function using string arguments +template +inline void Call(F&& func, const std::vector& string_args) { - if (string == "any") - { - value = std::nullopt; - } - else if (string != "") - { - value = string; - } - else - { - value = std::nullopt; - } -} + using ArgsTuple = typename traits::function::args; + constexpr auto arity = std::tuple_size_v; -void fillValue(bool& value, const std::string& string) -{ - if (string == "false" || string == "true") - { - value = string == "true"; - } - else + if (string_args.size() > arity) { - throw std::string("invalid argument, must be true or false"); + throw std::invalid_argument("Invalid arguments count: '" + std::to_string(string_args.size()) + + "', expected at most: '" + std::to_string(arity) + "'"); } -} - -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; + utils::decay_tuple args_tuple; + fillTuple(args_tuple, string_args); + std::apply(std::forward(func), args_tuple); } -template -void fillValue(std::optional& value) +inline void OpenSharedMemoryDataplaneBuffers(common::sdp::DataPlaneInSharedMemory& sdp_data, bool open_workers_data) { - 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) + if (common::sdp::SdpClient::ReadSharedMemoryData(sdp_data, open_workers_data) != eResult::success) { - if (TIndex < stringArgs.size()) - { - fillValue(std::get(tuple), stringArgs[TIndex]); - } - else - { - fillValue(std::get(tuple)); - } - - fillTuple(tuple, stringArgs); + YANET_LOG_ERROR("Error openning shared memory dataplane buffers\n"); + std::exit(1); } } -template -void call(void (*func)(TArgs... args), - const std::vector& stringArgs) +template +inline void FillAndPrintTable(const std::initializer_list& headers, const Container& data, const converter::config_t config = {}) { - if (stringArgs.size() > sizeof...(TArgs)) - { - throw std::string("invalid arguments count: '") + std::to_string(stringArgs.size()) + "', need: '" + std::to_string(sizeof...(TArgs)) + "'"; - } - std::tuple...> tuple; - fillTuple<0, sizeof...(TArgs)>(tuple, stringArgs); - std::apply(func, tuple); -} + TablePrinter table(config); -template -void getDiffTuple(TDiffTuple& diff, - const TTuple& curr, - const TTuple& prev) -{ - if constexpr (TIndex < TSize) - { - std::get(diff) = std::get(curr) - std::get(prev); - getDiffTuple(diff, curr, prev); - } + table.insert_row(headers.begin(), headers.end()); + table.insert(data.begin(), data.end()); + table.Print(); } - -template -std::map> getDiff(const std::map>& curr, - const std::map>& prev) -{ - 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; -} - -class table_t -{ -public: - table_t(const converter::config_t config = {}) : - config(config) - { - } - - template - void insert(const args_T&... args) - { - 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); - } - - 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; -}; 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 414c2f1d..4d20e965 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" @@ -35,113 +36,126 @@ 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); }}, - {"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]