From 3face905a47ec89676a20bc536db6bbb9e51d474 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 11:35:56 +0300 Subject: [PATCH 01/12] add neighbor table. use neighbor_hashtable in worker for resolve IP to MAC. use netlink_neighbor_monitor for dump neighbor's MAC from Linux. use neighbor_resolve table for pass resolve neighbor MAC. --- autotest/autotest.cpp | 3 + cli/main.cpp | 4 + cli/neighbor.h | 61 ++++ cli/telegraf.h | 10 + common/generation.h | 58 +++- common/idataplane.h | 35 ++ common/idp.h | 64 +++- common/neighbor.h | 18 ++ controlplane/route.cpp | 80 +++-- controlplane/route.h | 7 +- dataplane/base.h | 5 +- dataplane/bus.cpp | 29 +- dataplane/controlplane.cpp | 24 +- dataplane/dataplane.cpp | 91 ++++++ dataplane/dataplane.h | 54 ++-- dataplane/globalbase.cpp | 26 +- dataplane/hashtable.h | 600 +++++++++++++++++++++++++++++++++++ dataplane/meson.build | 1 + dataplane/neighbor.cpp | 634 +++++++++++++++++++++++++++++++++++++ dataplane/neighbor.h | 98 ++++++ dataplane/report.cpp | 4 +- dataplane/type.h | 20 +- dataplane/worker.cpp | 96 ++++-- dataplane/worker.h | 12 +- dataplane/worker_gc.h | 1 + 25 files changed, 1884 insertions(+), 151 deletions(-) create mode 100644 cli/neighbor.h create mode 100644 common/neighbor.h create mode 100644 dataplane/neighbor.cpp create mode 100644 dataplane/neighbor.h diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index 92697443..aa809ded 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -1301,6 +1301,8 @@ void tAutotest::mainThread() this->request.swap(request); } + dataPlane.neighbor_flush(); + YAML::Node yamlRoot = YAML::LoadFile(configFilePath + "/autotest.yaml"); for (const YAML::Node& yamlStep : yamlRoot["steps"]) @@ -1467,6 +1469,7 @@ void tAutotest::mainThread() /// clear dataplane states { dataPlane.balancer_state_clear(); + dataPlane.neighbor_clear(); } YANET_LOG_PRINT(ANSI_COLOR_GREEN "done '%s'\n\n" ANSI_COLOR_RESET, configFilePath.data()); diff --git a/cli/main.cpp b/cli/main.cpp index ab750298..8d024253 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -16,6 +16,7 @@ #include "limit.h" #include "nat46clat.h" #include "nat64stateful.h" +#include "neighbor.h" #include "rib.h" #include "route.h" #include "show.h" @@ -77,6 +78,9 @@ std::vector #include +#include #include #include +#include -template +template class generation_manager { public: @@ -156,16 +159,69 @@ class generation_manager generations[id ^ 1] = {}; ///< @todo: gc } + void switch_generation_without_gc() + { + std::unique_lock current_lock(current_mutex); + id ^= 1; + } + /** @todo void gc() { } */ + /// apply function for both generation + template + void fill(const function_t& function) + { + next_lock(); + function(next()); + switch_generation_without_gc(); + function(next()); + next_unlock(); + } + + /// apply function for next generation and insert in requests queue + template + Type_Update_Result update(const function_t& function) + { + next_lock(); + auto result = function(next()); + requests.emplace_back(function); + next_unlock(); + return result; + } + + /// switch generation and apply all previous requests for next generation + template + void switch_generation_with_update(const wait_function_t& wait_function) + { + next_lock(); + if (requests.size()) + { + /// update current pointer + switch_generation_without_gc(); + + /// wait all thread who used previous generation + wait_function(); + + /// apply all previous requests for next generation + for (const auto& function : requests) + { + function(next()); + } + requests.clear(); + } + next_unlock(); + } + protected: mutable std::shared_mutex current_mutex; mutable std::shared_mutex next_mutex; std::atomic id; std::array generations; + + std::vector> requests; }; diff --git a/common/idataplane.h b/common/idataplane.h index dec08bf3..227196da 100644 --- a/common/idataplane.h +++ b/common/idataplane.h @@ -218,6 +218,41 @@ class dataPlane return get(); } + auto neighbor_show() const + { + return get(); + } + + auto neighbor_insert(const common::idp::neighbor_insert::request& request) const + { + return get(request); + } + + auto neighbor_remove(const common::idp::neighbor_remove::request& request) const + { + return get(request); + } + + auto neighbor_clear() const + { + return get(); + } + + auto neighbor_flush() const + { + return get(); + } + + auto neighbor_update_interfaces(const common::idp::neighbor_update_interfaces::request& request) const + { + return get(request); + } + + auto neighbor_stats() const + { + return get(); + } + protected: void connectToDataPlane() const { diff --git a/common/idp.h b/common/idp.h index 3425cd77..bdcbb1f7 100644 --- a/common/idp.h +++ b/common/idp.h @@ -15,6 +15,7 @@ #include "acl.h" #include "balancer.h" #include "config.h" +#include "neighbor.h" #include "result.h" #include "scheduler.h" #include "type.h" @@ -72,6 +73,13 @@ enum class requestType : uint32_t get_shm_info, dump_physical_port, balancer_state_clear, + neighbor_show, + neighbor_insert, + neighbor_remove, + neighbor_clear, + neighbor_flush, + neighbor_update_interfaces, + neighbor_stats, size, // size should always be at the bottom of the list, this enum allows us to find out the size of the enum list }; @@ -199,8 +207,6 @@ using request = std::tuple, ///< neighbor_ether_address_v4 - std::optional, ///< neighbor_ether_address_v6 tAclId, common::globalBase::tFlow>; } @@ -372,7 +378,8 @@ using request = lpm::request; namespace route_value_update { using interface = std::vector>>; + std::vector, + ip_address_t>>; ///< neighbor_address using request = std::tuple>>; ///< nexthop_address + ip_address_t, ///< nexthop_address + ip_address_t>>>; ///< neighbor_address using request = std::tuple>; ///< last_update_timestamp +} + +namespace neighbor_insert +{ +using request = std::tuple; ///< mac_address +} + +namespace neighbor_remove +{ +using request = std::tuple; ///< ip_address +} + +namespace neighbor_update_interfaces +{ +using request = std::vector>; ///< interface_name +} + +namespace neighbor_stats +{ +using response = common::neighbor::stats; +} + +// + using request = std::tuple, updateGlobalBase::request, @@ -929,7 +975,10 @@ using request = std::tuple>; + dump_physical_port::request, + neighbor_insert::request, + neighbor_remove::request, + neighbor_update_interfaces::request>>; using response = std::variant, updateGlobalBase::response, ///< + others which have eResult as response @@ -960,6 +1009,7 @@ using response = std::variant, limits::response, samples::response, get_counter_by_name::response, - get_shm_info::response>; - + get_shm_info::response, + neighbor_show::response, + neighbor_stats::response>; } diff --git a/common/neighbor.h b/common/neighbor.h new file mode 100644 index 00000000..01032091 --- /dev/null +++ b/common/neighbor.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace common::neighbor +{ + +struct stats +{ + uint64_t hashtable_insert_success; + uint64_t hashtable_insert_error; + uint64_t hashtable_remove_success; + uint64_t hashtable_remove_error; + uint64_t netlink_neighbor_update; + uint64_t resolve; +}; + +} diff --git a/controlplane/route.cpp b/controlplane/route.cpp index 61462ca4..6fde5558 100644 --- a/controlplane/route.cpp +++ b/controlplane/route.cpp @@ -746,6 +746,20 @@ void route_t::compile_interface(common::idp::updateGlobalBase::request& globalba const route::generation_t& generation, route::generation_neighbors_t& generation_neighbors) { + { + common::idp::neighbor_update_interfaces::request request; + for (const auto& [route_name, route] : generation.routes) + { + for (auto& [interface_name, interface] : route.interfaces) + { + request.emplace_back(interface.interfaceId, + route_name, + interface_name); + } + } + dataplane.neighbor_update_interfaces(request); + } + for (const auto& [route_name, route] : generation.routes) { for (auto& [interface_name, interface] : route.interfaces) @@ -780,17 +794,23 @@ void route_t::compile_interface(common::idp::updateGlobalBase::request& globalba if (neighbor_mac_address_v4) { generation_neighbors.mac_addresses[{route_name, interface_name, *interface.neighborIPv4Address}] = *neighbor_mac_address_v4; + dataplane.neighbor_insert({route_name, + interface_name, + *interface.neighborIPv4Address, + *neighbor_mac_address_v4}); } if (neighbor_mac_address_v6) { generation_neighbors.mac_addresses[{route_name, interface_name, *interface.neighborIPv6Address}] = *neighbor_mac_address_v6; + dataplane.neighbor_insert({route_name, + interface_name, + *interface.neighborIPv6Address, + *neighbor_mac_address_v6}); } globalbase.emplace_back(common::idp::updateGlobalBase::requestType::updateInterface, common::idp::updateGlobalBase::updateInterface::request{interface.interfaceId, - neighbor_mac_address_v4, - neighbor_mac_address_v6, interface.aclId, interface.flow}); } @@ -901,22 +921,6 @@ void route_t::reload_after() generations.next_unlock(); } -void route_t::mac_addresses_changed() -{ - common::idp::updateGlobalBase::request globalbase; - - generations.next_lock(); - generations_neighbors.next_lock(); - - compile_interface(globalbase, generations.current(), generations_neighbors.next()); - dataplane.updateGlobalBase(globalbase); ///< может вызвать исключение, которое никто не поймает, и это приведёт к abort() - - generations_neighbors.switch_generation(); - - generations_neighbors.next_unlock(); - generations.next_unlock(); -} - void route_t::prefix_flush_prefixes(common::idp::updateGlobalBase::request& globalbase) { common::idp::lpm::request lpm_request; @@ -1129,7 +1133,8 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, request_interface.emplace_back(nexthop, interface_id, interface_name, - labels); + labels, + nexthop); continue; } @@ -1224,11 +1229,11 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, /// same numa for (const auto& item : request_interface) { - const auto& [nexthop, egress_interface_id, egress_interface_name, labels] = item; + const auto& [nexthop, egress_interface_id, egress_interface_name, labels, neighbor_address] = item; if (exist(interfaces, egress_interface_id)) { - update_interface.emplace_back(egress_interface_id, labels); + update_interface.emplace_back(egress_interface_id, labels, neighbor_address); value_lookup[value_id][socket_id].emplace_back(nexthop, egress_interface_name, @@ -1241,9 +1246,9 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, { for (const auto& item : request_interface) { - const auto& [nexthop, egress_interface_id, egress_interface_name, labels] = item; + const auto& [nexthop, egress_interface_id, egress_interface_name, labels, neighbor_address] = item; - update_interface.emplace_back(egress_interface_id, labels); + update_interface.emplace_back(egress_interface_id, labels, neighbor_address); value_lookup[value_id][socket_id].emplace_back(nexthop, egress_interface_name, @@ -1301,7 +1306,8 @@ void route_t::value_compile_label(common::idp::updateGlobalBase::request& global request_interface.emplace_back(first_nexthop, interface_id, interface_name, - labels); + labels, + nexthop); } else { @@ -1347,7 +1353,8 @@ void route_t::value_compile_fallback(common::idp::updateGlobalBase::request& glo request_interface.emplace_back(nexthop, interface_id, interface_name, - labels); + labels, + nexthop); } } } @@ -1457,7 +1464,8 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa interface_name, peer_id, origin_as, - weight); + weight, + default_nexthop); } } } @@ -1476,7 +1484,8 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa interface_name, peer_id, origin_as, - weight); + weight, + default_nexthop); } } } @@ -1517,7 +1526,8 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa interface_name, 0, 0, - 1); + 1, + nexthop); } } } @@ -1557,7 +1567,8 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa interface_name, 0, 0, - 1); + 1, + default_nexthop); } } } @@ -1576,7 +1587,8 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa interface_name, 0, 0, - 1); + 1, + default_nexthop); } } } @@ -1619,14 +1631,14 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa /// same numa for (const auto& item : request_interface) { - const auto& [nexthop, egress_interface_id, label, egress_interface_name, peer_id, origin_as, weight] = item; + const auto& [nexthop, egress_interface_id, label, egress_interface_name, peer_id, origin_as, weight, neighbor_address] = item; (void)egress_interface_name; if (exist(interfaces, egress_interface_id)) { const auto counter_ids = tunnel_counter.get_ids({fallback.is_ipv4(), peer_id, nexthop, origin_as}); - update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop); + update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address); weights.emplace_back(weight); tunnel_value_lookup[value_id][socket_id].emplace_back(nexthop, @@ -1645,12 +1657,12 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa { for (const auto& item : request_interface) { - const auto& [nexthop, egress_interface_id, label, egress_interface_name, peer_id, origin_as, weight] = item; + const auto& [nexthop, egress_interface_id, label, egress_interface_name, peer_id, origin_as, weight, neighbor_address] = item; (void)egress_interface_name; const auto counter_ids = tunnel_counter.get_ids({fallback.is_ipv4(), peer_id, nexthop, origin_as}); - update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop); + update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address); weights.emplace_back(weight); tunnel_value_lookup[value_id][socket_id].emplace_back(nexthop, diff --git a/controlplane/route.h b/controlplane/route.h index 11c81121..09f653a3 100644 --- a/controlplane/route.h +++ b/controlplane/route.h @@ -27,7 +27,8 @@ using value_key_t = std::tuple>; + std::vector, + ip_address_t>; ///< neighbor_address using lookup_t = std::tuple; ///< weight + uint32_t, ///< weight + ip_address_t>; ///< neighbor_address using tunnel_lookup_t = std::tuple& vrf_priority, const ip_prefix_t& prefix, const std::vector& pptns, const std::variant& value); void tunnel_prefix_update(const std::tuple& vrf_priority_orig, const ip_prefix_t& prefix, const std::variant>& value); diff --git a/dataplane/base.h b/dataplane/base.h index 9bc7c709..7924576d 100644 --- a/dataplane/base.h +++ b/dataplane/base.h @@ -8,6 +8,7 @@ #include #include +#include "neighbor.h" #include "type.h" namespace dataplane::base @@ -78,11 +79,13 @@ class generation { public: generation() : - globalBase(nullptr) + globalBase(nullptr), + neighbor_hashtable(nullptr) { } dataplane::globalBase::generation* globalBase; + dataplane::neighbor::hashtable const* neighbor_hashtable; } __rte_aligned(2 * RTE_CACHE_LINE_SIZE); } diff --git a/dataplane/bus.cpp b/dataplane/bus.cpp index c9209c31..169843cc 100644 --- a/dataplane/bus.cpp +++ b/dataplane/bus.cpp @@ -153,7 +153,6 @@ void cBus::clientThread(int clientSocket) } auto startTime = std::chrono::system_clock::now(); - ; if (messageSize > BigMessage) { @@ -347,6 +346,34 @@ void cBus::clientThread(int clientSocket) { response = callWithResponse(&cControlPlane::balancer_state_clear, request); } + else if (type == common::idp::requestType::neighbor_show) + { + response = dataPlane->neighbor.neighbor_show(); + } + else if (type == common::idp::requestType::neighbor_insert) + { + response = dataPlane->neighbor.neighbor_insert(std::get(std::get<1>(request))); + } + else if (type == common::idp::requestType::neighbor_remove) + { + response = dataPlane->neighbor.neighbor_remove(std::get(std::get<1>(request))); + } + else if (type == common::idp::requestType::neighbor_clear) + { + response = dataPlane->neighbor.neighbor_clear(); + } + else if (type == common::idp::requestType::neighbor_flush) + { + response = dataPlane->neighbor.neighbor_flush(); + } + else if (type == common::idp::requestType::neighbor_update_interfaces) + { + response = dataPlane->neighbor.neighbor_update_interfaces(std::get(std::get<1>(request))); + } + else if (type == common::idp::requestType::neighbor_stats) + { + response = dataPlane->neighbor.neighbor_stats(); + } else { stats.errors[(uint32_t)common::idp::errorType::busParse]++; diff --git a/dataplane/controlplane.cpp b/dataplane/controlplane.cpp index ec6dab8a..bc4d4ae2 100644 --- a/dataplane/controlplane.cpp +++ b/dataplane/controlplane.cpp @@ -1358,29 +1358,7 @@ void cControlPlane::switchGlobalBase() { YADECAP_MEMORY_BARRIER_COMPILE; - for (auto& iter : dataPlane->workers) - { - const auto& coreId = iter.first; - auto* worker = iter.second; - auto& baseNext = worker->bases[worker->currentBaseId ^ 1]; - auto* globalBaseNext = dataPlane->globalBases[rte_lcore_to_socket_id(coreId)][dataPlane->currentGlobalBaseId ^ 1]; - - baseNext.globalBase = globalBaseNext; - } - - for (auto& iter : dataPlane->worker_gcs) - { - const auto& coreId = iter.first; - auto* worker = iter.second; - auto& baseNext = worker->bases[worker->current_base_id ^ 1]; - auto* globalBaseNext = dataPlane->globalBases[rte_lcore_to_socket_id(coreId)][dataPlane->currentGlobalBaseId ^ 1]; - - baseNext.globalBase = globalBaseNext; - } - - YADECAP_MEMORY_BARRIER_COMPILE; - - switchBase(); + dataPlane->switch_worker_base(); YADECAP_MEMORY_BARRIER_COMPILE; diff --git a/dataplane/dataplane.cpp b/dataplane/dataplane.cpp index 4e4b8aeb..7e26e382 100644 --- a/dataplane/dataplane.cpp +++ b/dataplane/dataplane.cpp @@ -237,6 +237,14 @@ eResult cDataPlane::init(const std::string& binaryPath, return result; } + result = neighbor.init(this); + if (result != eResult::success) + { + return result; + } + + init_worker_base(); + /// init sync barrier int rc = pthread_barrier_init(&initPortBarrier, nullptr, workers.size()); if (rc != 0) @@ -780,6 +788,8 @@ eResult cDataPlane::initGlobalBases() { return result; } + + socket_ids.emplace(socketId); } for (const auto& configWorkerIter : config.workers) @@ -798,6 +808,8 @@ eResult cDataPlane::initGlobalBases() { return result; } + + socket_ids.emplace(socketId); } return result; @@ -842,6 +854,7 @@ eResult cDataPlane::initWorkers() workers[coreId] = worker; controlPlane->slowWorker = worker; + workers_vector.emplace_back(worker); outQueueId++; } @@ -992,6 +1005,7 @@ eResult cDataPlane::initWorkers() worker->fillStatsNamesToAddrsTable(coreId_to_stats_tables[coreId]); workers[coreId] = worker; + workers_vector.emplace_back(worker); outQueueId++; } @@ -1071,6 +1085,7 @@ eResult cDataPlane::initWorkers() worker->fillStatsNamesToAddrsTable(coreId_to_stats_tables[core_id]); worker_gcs[core_id] = worker; + socket_worker_gcs[socket_id] = worker; } return eResult::success; @@ -1120,6 +1135,31 @@ eResult cDataPlane::initQueues() return eResult::success; } +void cDataPlane::init_worker_base() +{ + std::vector> base_nexts; + for (auto& [core_id, worker] : workers) + { + (void)core_id; + + auto* base = &worker->bases[worker->currentBaseId]; + auto* base_next = &worker->bases[worker->currentBaseId ^ 1]; + base_nexts.emplace_back(worker->socketId, base); + base_nexts.emplace_back(worker->socketId, base_next); + } + for (auto& [core_id, worker] : worker_gcs) + { + (void)core_id; + + auto* base = &worker->bases[worker->current_base_id]; + auto* base_next = &worker->bases[worker->current_base_id ^ 1]; + base_nexts.emplace_back(worker->socket_id, base); + base_nexts.emplace_back(worker->socket_id, base_next); + } + + neighbor.update_worker_base(base_nexts); +} + void cDataPlane::hugepage_destroy(void* pointer) { auto it = hugepage_pointers.find(pointer); @@ -1190,6 +1230,22 @@ void cDataPlane::join() bus.join(); } +const std::set& cDataPlane::get_socket_ids() const +{ + return socket_ids; +} + +const std::vector& cDataPlane::get_workers() const +{ + return workers_vector; +} + +void cDataPlane::run_on_worker_gc(const tSocketId socket_id, + const std::function& callback) +{ + socket_worker_gcs.find(socket_id)->second->run_on_this_thread(callback); +} + uint64_t cDataPlane::getConfigValue(const eConfigType& type) const { if (configValues.find(type) == configValues.end()) @@ -1471,6 +1527,41 @@ std::optional cDataPlane::interface_name_to_port_id(const std::string& return std::nullopt; } +void cDataPlane::switch_worker_base() +{ + std::lock_guard guard(switch_worker_base_mutex); + + /// collect all base_next + std::vector> base_nexts; + for (auto& [core_id, worker] : workers) + { + (void)core_id; + + auto* base_next = &worker->bases[worker->currentBaseId ^ 1]; + base_nexts.emplace_back(worker->socketId, base_next); + } + for (auto& [core_id, worker] : worker_gcs) + { + (void)core_id; + + auto* base_next = &worker->bases[worker->current_base_id ^ 1]; + base_nexts.emplace_back(worker->socket_id, base_next); + } + + /// update base_next + { + std::lock_guard guard(currentGlobalBaseId_mutex); + for (const auto& [socket_id, base_next] : base_nexts) + { + base_next->globalBase = globalBases[socket_id][currentGlobalBaseId ^ 1]; + } + } + neighbor.update_worker_base(base_nexts); + + /// switch + controlPlane->switchBase(); +} + eResult cDataPlane::parseConfig(const std::string& configFilePath) { eResult result = eResult::success; diff --git a/dataplane/dataplane.h b/dataplane/dataplane.h index cfd7949b..6c3b2912 100644 --- a/dataplane/dataplane.h +++ b/dataplane/dataplane.h @@ -21,6 +21,7 @@ #include "bus.h" #include "controlplane.h" #include "globalbase.h" +#include "neighbor.h" #include "report.h" #include "type.h" #include "worker_gc.h" @@ -124,27 +125,11 @@ class cDataPlane uint64_t getConfigValue(const eConfigType& type) const; std::map getPortStats(const tPortId& portId) const; std::optional interface_name_to_port_id(const std::string& interface_name); + const std::set& get_socket_ids() const; + const std::vector& get_workers() const; + void run_on_worker_gc(const tSocketId socket_id, const std::function& callback); -protected: - eResult parseConfig(const std::string& configFilePath); - eResult parseJsonPorts(const nlohmann::json& json); - eResult parseConfigValues(const nlohmann::json& json); - eResult parseRateLimits(const nlohmann::json& json); - eResult parseSharedMemory(const nlohmann::json& json); - eResult checkConfig(); - - eResult initEal(const std::string& binaryPath, const std::string& filePrefix); - eResult initPorts(); - eResult initRingPorts(); - eResult initGlobalBases(); - eResult initWorkers(); - eResult initQueues(); - - eResult allocateSharedMemory(); - eResult splitSharedMemoryPerWorkers(); - - std::optional getCounterValueByName(const std::string& counter_name, uint32_t coreId); - common::idp::get_shm_info::response getShmInfo(); + void switch_worker_base(); template @@ -282,6 +267,28 @@ class cDataPlane void hugepage_destroy(void* pointer); void hugepage_debug(tSocketId socket_id); +protected: + eResult parseConfig(const std::string& configFilePath); + eResult parseJsonPorts(const nlohmann::json& json); + eResult parseConfigValues(const nlohmann::json& json); + eResult parseRateLimits(const nlohmann::json& json); + eResult parseSharedMemory(const nlohmann::json& json); + eResult checkConfig(); + + eResult initEal(const std::string& binaryPath, const std::string& filePrefix); + eResult initPorts(); + eResult initRingPorts(); + eResult initGlobalBases(); + eResult initWorkers(); + eResult initQueues(); + void init_worker_base(); + + eResult allocateSharedMemory(); + eResult splitSharedMemoryPerWorkers(); + + std::optional getCounterValueByName(const std::string& counter_name, uint32_t coreId); + common::idp::get_shm_info::response getShmInfo(); + static int lcoreThread(void* args); protected: @@ -333,6 +340,7 @@ class cDataPlane cReport report; std::unique_ptr controlPlane; cBus bus; + dataplane::neighbor::module neighbor; // array instead of the table - how many coreIds can be there? std::unordered_map> coreId_to_stats_tables; @@ -341,4 +349,10 @@ class cDataPlane std::mutex hugepage_pointers_mutex; std::map hugepage_pointers; + + std::set socket_ids; + std::map socket_worker_gcs; + std::vector workers_vector; + + std::mutex switch_worker_base_mutex; }; diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index 7291c5d4..5cfdfe0e 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -867,7 +867,7 @@ eResult generation::update_route(const common::idp::updateGlobalBase::update_rou eResult generation::updateInterface(const common::idp::updateGlobalBase::updateInterface::request& request) { - const auto& [interfaceId, neighbor_ether_address_v4, neighbor_ether_address_v6, aclId, flow] = request; + const auto& [interfaceId, aclId, flow] = request; if (interfaceId >= CONFIG_YADECAP_INTERFACES_SIZE) { @@ -896,24 +896,6 @@ eResult generation::updateInterface(const common::idp::updateGlobalBase::updateI return eResult::invalidAclId; } - if (neighbor_ether_address_v4) - { - memcpy(interface.neighbor_ether_address_v4.addr_bytes, (*neighbor_ether_address_v4).data(), 6); ///< @todo: convert - } - else - { - interface.neighbor_ether_address_v4.addr_bytes[0] = 1; - } - - if (neighbor_ether_address_v6) - { - memcpy(interface.neighbor_ether_address_v6.addr_bytes, (*neighbor_ether_address_v6).data(), 6); ///< @todo: convert - } - else - { - interface.neighbor_ether_address_v6.addr_bytes[0] = 1; - } - interface.flow = flow; interface.aclId = aclId; @@ -1618,7 +1600,7 @@ eResult generation::route_value_update(const common::idp::updateGlobalBase::rout ecmp_i < request_interface.size(); ecmp_i++) { - const auto& [interface_id, labels] = request_interface[ecmp_i]; + const auto& [interface_id, labels, neighbor_address] = request_interface[ecmp_i]; if (interface_id >= CONFIG_YADECAP_INTERFACES_SIZE) { @@ -1627,6 +1609,7 @@ eResult generation::route_value_update(const common::idp::updateGlobalBase::rout } route_value.interface.nexthops[ecmp_i].interfaceId = interface_id; + route_value.interface.nexthops[ecmp_i].neighbor_address = ipv6_address_t::convert(neighbor_address); if (labels.size() == 0) { @@ -1803,7 +1786,7 @@ eResult generation::route_tunnel_value_update(const common::idp::updateGlobalBas ecmp_i < nexthops.size(); ecmp_i++) { - const auto& [interface_id, counter_id, label, nexthop_address] = nexthops[ecmp_i]; + const auto& [interface_id, counter_id, label, nexthop_address, neighbor_address] = nexthops[ecmp_i]; if (interface_id >= CONFIG_YADECAP_INTERFACES_SIZE) { @@ -1815,6 +1798,7 @@ eResult generation::route_tunnel_value_update(const common::idp::updateGlobalBas route_tunnel_value.interface.nexthops[ecmp_i].counter_id = counter_id; route_tunnel_value.interface.nexthops[ecmp_i].label = label; route_tunnel_value.interface.nexthops[ecmp_i].nexthop_address = ipv6_address_t::convert(nexthop_address); + route_tunnel_value.interface.nexthops[ecmp_i].neighbor_address = ipv6_address_t::convert(neighbor_address); } route_tunnel_value.interface.weight_start = weight_start; diff --git a/dataplane/hashtable.h b/dataplane/hashtable.h index 4ba7e65f..01e95cc9 100644 --- a/dataplane/hashtable.h +++ b/dataplane/hashtable.h @@ -2423,6 +2423,12 @@ class hashtable_mod_spinlock return result; } + range_t range() + { + range_t result(this, 0, total_size); + return result; + } + protected: struct chunk_t { @@ -2998,4 +3004,598 @@ class hashtable_mod_spinlock_dynamic } }; +/// hashtable. only single thread. runtime allocation. +/// +/// chunk +/// [ +/// valid_mask +/// key | value <-- hash == 0 +/// key | value <-- hash == 1 +/// key | value <-- hash == 2 +/// key | value <-- hash == 3 (chunk_size) +/// ] +/// chunk +/// [ +/// valid_mask +/// key | value <-- hash == 4 +/// key | value <-- hash == 5 +/// key | value <-- hash == 6 +/// key | value <-- hash == 7 +/// ] +/// chunk +/// [ +/// valid_mask +/// key | value <-- hash == 8 +/// key | value <-- hash == 9 +/// key | value <-- hash == 10 +/// key | value <-- hash == 11 (total_size) +/// ] +template +class hashtable_mod_dynamic +{ +public: + using hashtable_t = hashtable_mod_dynamic; + + constexpr static uint32_t valid_mask_full = 0xFFFFFFFFu >> (32 - chunk_size); + constexpr static uint64_t keys_in_chunk_size = chunk_size; + + static_assert(__builtin_popcount(chunk_size) == 1); + static_assert(chunk_size <= 32); + +public: + class iterator_t; + class range_t; + + class stats_t + { + public: + stats_t() + { + memset(this, 0, sizeof(*this)); + } + + uint32_t keys_count; + std::array keys_in_chunks; + uint32_t longest_chain; + }; + + class updater + { + public: + void update_pointer(hashtable_t* hashtable, + const tSocketId socket_id, + const uint32_t total_size) + { + this->hashtable = hashtable; + this->socket_id = socket_id; + this->total_size = total_size; + + hashtable->total_mask = (total_size / chunk_size) - 1; + hashtable->total_shift = __builtin_popcount(total_size / chunk_size - 1); + } + + hashtable_t* get_pointer() + { + return hashtable; + } + + const hashtable_t* get_pointer() const + { + return hashtable; + } + + public: + range_t range(uint32_t& offset, + const uint32_t step) + { + range_t result(hashtable, total_size, offset, step); + + offset += step; + if (offset >= total_size) + { + offset = 0; + } + + return result; + } + + range_t range(uint32_t& offset, + const uint32_t step) const + { + range_t result(hashtable, total_size, offset, step); + + offset += step; + if (offset >= total_size) + { + offset = 0; + } + + return result; + } + + range_t range() + { + return range_t(hashtable, total_size, 0, total_size); + } + + range_t range() const + { + return range_t(hashtable, total_size, 0, total_size); + } + + range_t gc(uint32_t& offset, + const uint32_t step) + { + range_t result(hashtable, total_size, offset, step); + + /// calculate_stats + uint32_t from = offset; + uint32_t to = offset + step; + for (uint32_t chunk_id = (from / chunk_size) + !!(from % chunk_size); + chunk_id < RTE_MIN(to / chunk_size + !!(to % chunk_size), + total_size / chunk_size); + chunk_id++) + { + const auto& chunk = hashtable->chunks[chunk_id]; + + uint32_t pairs_in_chunk = __builtin_popcount(chunk.valid_mask); + + auto& stats_next = stats.next(); + stats_next.keys_count += pairs_in_chunk; + stats_next.keys_in_chunks[pairs_in_chunk]++; + stats_next.longest_chain = std::max(stats_next.longest_chain, pairs_in_chunk); + } + + offset += step; + if (offset >= total_size) + { + stats.switch_generation(); + offset = 0; + } + + return result; + } + + stats_t get_stats() + { + auto current_guard = stats.current_lock_guard(); + return stats.current(); + } + + template ///< @todo: common::idp::limits::response + void limits(list_T& list, + const std::string& name) const + { + auto current_guard = stats.current_lock_guard(); + + list.emplace_back(name + ".keys", + socket_id, + stats.current().keys_count, + total_size); + list.emplace_back(name + ".longest_collision", + socket_id, + stats.current().longest_chain, + chunk_size); + } + + template ///< @todo: nlohmann::json + void report(json_t& json) const + { + auto current_guard = stats.current_lock_guard(); + + json["total_size"] = total_size; + json["keys_count"] = stats.current().keys_count; + for (unsigned int i = 0; + i < stats.current().keys_in_chunks.size(); + i++) + { + json["keys_in_chunks"][i] = stats.current().keys_in_chunks[i]; + } + json["longest_chain"] = stats.current().longest_chain; + } + + protected: + hashtable_t* hashtable; + tSocketId socket_id; + uint32_t total_size; + generation_manager stats; + }; + +public: + static size_t calculate_sizeof(const uint32_t total_size) + { + if (!(total_size / chunk_size)) + { + YANET_LOG_ERROR("wrong total_size: %u\n", total_size); + return 0; + } + + if (__builtin_popcount(total_size) != 1) + { + YANET_LOG_ERROR("wrong total_size: %u is non power of 2\n", total_size); + return 0; + } + + return sizeof(hashtable_t) + (size_t)(total_size / chunk_size) * sizeof(chunk_t); + } + +public: + inline uint32_t lookup(const key_t& key, + value_t*& value) + { + uint32_t hash = calculate_hash(key); + auto& chunk = chunks[hash & total_mask]; + + value = nullptr; + + const uint32_t pair_index = (hash >> total_shift) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + value = &chunk.pairs[pair_index].value; + return hash; + } + + if (chunk_size == 1) + { + return hash; + } + + /// check collision + uint32_t valid_mask = chunk.valid_mask; + for (unsigned int try_i = 1; + try_i < chunk_size && valid_mask; + try_i++) + { + const uint32_t pair_index = ((hash >> total_shift) + try_i) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + value = &chunk.pairs[pair_index].value; + return hash; + } + valid_mask &= 0xFFFFFFFFu ^ (1u << pair_index); + } + + /// not found + return hash; + } + + inline uint32_t lookup(const key_t& key, + value_t const*& value) const + { + uint32_t hash = calculate_hash(key); + auto& chunk = chunks[hash & total_mask]; + + value = nullptr; + + const uint32_t pair_index = (hash >> total_shift) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + value = &chunk.pairs[pair_index].value; + return hash; + } + + if (chunk_size == 1) + { + return hash; + } + + /// check collision + uint32_t valid_mask = chunk.valid_mask; + for (unsigned int try_i = 1; + try_i < chunk_size && valid_mask; + try_i++) + { + const uint32_t pair_index = ((hash >> total_shift) + try_i) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + value = &chunk.pairs[pair_index].value; + return hash; + } + valid_mask &= 0xFFFFFFFFu ^ (1u << pair_index); + } + + /// not found + return hash; + } + + inline bool insert(const uint32_t hash, + const key_t& key, + const value_t& value) + { + auto& chunk = chunks[hash & total_mask]; + + const uint32_t pair_index = (hash >> total_shift) & (chunk_size - 1); + if (!is_valid(chunk, pair_index)) + { + memcpy(&chunk.pairs[pair_index].key, &key, sizeof(key_t)); + memcpy(&chunk.pairs[pair_index].value, &value, sizeof(value_t)); + chunk.valid_mask |= 1u << pair_index; + + return true; + } + /* else if (is_equal(chunk, pair_index, key)) + { + /// hashtable is broken + } */ + + if (chunk_size == 1) + { + return false; + } + + /// collision + if (chunk.valid_mask == valid_mask_full) + { + /// chunk is full + return false; + } + + for (unsigned int try_i = 1; + try_i < chunk_size; + try_i++) + { + const uint32_t pair_index = ((hash >> total_shift) + try_i) & (chunk_size - 1); + if (!is_valid(chunk, pair_index)) + { + memcpy(&chunk.pairs[pair_index].key, &key, sizeof(key_t)); + memcpy(&chunk.pairs[pair_index].value, &value, sizeof(value_t)); + chunk.valid_mask |= 1u << pair_index; + + return true; + } + /* else if (is_equal(chunk, pair_index, key)) + { + /// hashtable is broken + } */ + } + + /// chunk is full + return false; + } + + inline bool insert_or_update(const key_t& key, + const value_t& value) + { + bool result = true; + + value_t* ht_value; + + uint32_t hash = lookup(key, ht_value); + if (ht_value) + { + *ht_value = value; + } + else + { + result = insert(hash, key, value); + } + + return result; + } + + inline bool remove(const key_t& key) + { + uint32_t hash = calculate_hash(key); + auto& chunk = chunks[hash & total_mask]; + + const uint32_t pair_index = (hash >> total_shift) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + chunk.valid_mask ^= 1u << pair_index; + return true; + } + + if (chunk_size == 1) + { + /// not found + return false; + } + + /// check collision + uint32_t valid_mask = chunk.valid_mask; + for (unsigned int try_i = 1; + try_i < chunk_size && valid_mask; + try_i++) + { + const uint32_t pair_index = ((hash >> total_shift) + try_i) & (chunk_size - 1); + if (is_valid_and_equal(chunk, pair_index, key)) + { + chunk.valid_mask ^= 1u << pair_index; + return true; + } + valid_mask &= 0xFFFFFFFFu ^ (1u << pair_index); + } + + /// not found + return false; + } + + void clear() + { + for (uint32_t i = 0; + i <= total_mask; + i++) + { + auto& chunk = chunks[i]; + chunk.valid_mask = 0; + } + } + + inline static uint32_t calculate_hash(const key_t& key) + { + uint32_t result = 0; + + unsigned int offset = 0; + + for (unsigned int i = 0; + i < sizeof(key_t) / 8; + i++) + { + result = rte_hash_crc_8byte(*(((const uint64_t*)&key) + offset / 8), result); + offset += 8; + } + + if (sizeof(key_t) & 0x4) + { + result = rte_hash_crc_4byte(*(((const uint32_t*)&key) + offset / 4), result); + offset += 4; + } + + if (sizeof(key_t) & 0x2) + { + result = rte_hash_crc_2byte(*(((const uint16_t*)&key) + offset / 2), result); + offset += 2; + } + + if (sizeof(key_t) & 0x1) + { + result = rte_hash_crc_1byte(*(((const uint8_t*)&key) + offset), result); + } + + return result; + } + +public: + class iterator_t + { + public: + iterator_t(hashtable_t* hashtable, + const uint32_t index) : + hashtable(hashtable), + index(index) + { + } + + iterator_t operator++() + { + index++; + return *this; + } + + bool operator!=(const iterator_t& second) const + { + return index != second.index; + } + + iterator_t& operator*() + { + return *this; + } + + public: + bool is_valid() + { + const uint32_t pair_index = index % chunk_size; + return chunk().valid_mask & (1u << pair_index); + } + + void unset_valid() + { + const uint32_t pair_index = index % chunk_size; + chunk().valid_mask &= 0xFFFFFFFFu ^ (1u << pair_index); + } + + const key_t* key() + { + const uint32_t pair_index = index % chunk_size; + return &chunk().pairs[pair_index].key; + } + + value_t* value() + { + const uint32_t pair_index = index % chunk_size; + return &chunk().pairs[pair_index].value; + } + + auto& chunk() + { + return hashtable->chunks[index / chunk_size]; + } + + protected: + friend class updater; + hashtable_t* hashtable; + uint32_t index; + }; + + class range_t + { + public: + range_t(hashtable_t* hashtable, + const uint32_t total_size, + const uint32_t offset, + const uint32_t step) : + hashtable(hashtable), + total_size(total_size), + offset(offset), + step(step) + { + } + + iterator_t begin() const + { + return {hashtable, + RTE_MIN(offset, total_size)}; + } + + iterator_t end() const + { + return {hashtable, + RTE_MIN(offset + step, total_size)}; + } + + protected: + hashtable_t* hashtable; + uint32_t total_size; + uint32_t offset; + uint32_t step; + }; + + range_t range(const updater& updater, + uint32_t& offset, + const uint32_t step) + { + range_t result(this, updater.total_size, offset, step); + + offset += step; + if (offset >= updater.total_size) + { + offset = 0; + } + + return result; + } + +protected: + uint32_t total_mask; + uint32_t total_shift; + + struct chunk_t + { + uint64_t valid_mask; + struct + { + key_t key; + value_t value; + } pairs[chunk_size]; + } chunks[]; + + inline bool is_valid(const chunk_t& chunk, const uint32_t pair_index) const + { + return (chunk.valid_mask >> pair_index) & 1; + } + + inline bool is_equal(const chunk_t& chunk, const uint32_t pair_index, const key_t& key) const + { + return !memcmp(&chunk.pairs[pair_index].key, &key, sizeof(key_t)); + } + + inline bool is_valid_and_equal(const chunk_t& chunk, const uint32_t pair_index, const key_t& key) const + { + return is_valid(chunk, pair_index) && is_equal(chunk, pair_index, key); + } +}; + } diff --git a/dataplane/meson.build b/dataplane/meson.build index 75672592..d886657e 100644 --- a/dataplane/meson.build +++ b/dataplane/meson.build @@ -11,6 +11,7 @@ sources = files('bus.cpp', 'fragmentation.cpp', 'globalbase.cpp', 'main.cpp', + 'neighbor.cpp', 'report.cpp', 'sharedmemory.cpp', 'sock_dev.cpp', diff --git a/dataplane/neighbor.cpp b/dataplane/neighbor.cpp new file mode 100644 index 00000000..6c88e690 --- /dev/null +++ b/dataplane/neighbor.cpp @@ -0,0 +1,634 @@ +#include +#include +#include +#include + +#include "dataplane.h" +#include "neighbor.h" +#include "worker.h" + +using namespace dataplane::neighbor; + +static void parse_rt_attributes(rtattr* rt_attributes[], + unsigned int rt_attributes_size, + rtattr* rta, + int length) +{ + memset(rt_attributes, 0, sizeof(rtattr*) * (rt_attributes_size + 1)); + while (RTA_OK(rta, length)) + { + if ((rta->rta_type <= rt_attributes_size) && + (!rt_attributes[rta->rta_type])) + { + rt_attributes[rta->rta_type] = rta; + } + + rta = RTA_NEXT(rta, length); + } + + if (length) + { + YANET_LOG_WARNING("invalid length: %u of %u\n", length, rta->rta_len); + } +} + +static std::string iface_id_to_name(unsigned int iface_id) +{ + char buffer[IFNAMSIZ]; + if (if_indextoname(iface_id, buffer) == nullptr) + { + snprintf(buffer, IFNAMSIZ, "unknown_%u", iface_id); + } + return buffer; +} + +static void netlink_parse(const std::function& callback, + const char* buffer, + const unsigned int buffer_length) +{ + rtattr* rt_attributes[NDA_MAX + 1]; + + unsigned int offset = 0; + while (offset + sizeof(nlmsghdr) <= buffer_length) + { + nlmsghdr* nl_message_header = (nlmsghdr*)(buffer + offset); + uint32_t length = nl_message_header->nlmsg_len; + + ndmsg* nl_message = (ndmsg*)NLMSG_DATA(nl_message_header); + parse_rt_attributes(rt_attributes, + NDA_MAX, + (rtattr*)(((char*)(nl_message)) + NLMSG_ALIGN(sizeof(ndmsg))), + nl_message_header->nlmsg_len - NLMSG_LENGTH(sizeof(*nl_message))); + + if (rt_attributes[NDA_DST] && + rt_attributes[NDA_LLADDR] && + nl_message->ndm_ifindex) + { + std::string interface_name = iface_id_to_name(nl_message->ndm_ifindex); + + unsigned int family = nl_message->ndm_family; + if (family == AF_BRIDGE) + { + if (RTA_PAYLOAD(rt_attributes[NDA_DST]) == sizeof(in6_addr)) + { + family = AF_INET6; + } + else + { + family = AF_INET; + } + } + + common::ip_address_t ip_address; + if (family == AF_INET) + { + ip_address = common::ipv4_address_t(rte_be_to_cpu_32(*(const uint32_t*)RTA_DATA(rt_attributes[NDA_DST]))); + } + else + { + ip_address = common::ipv6_address_t((const uint8_t*)RTA_DATA(rt_attributes[NDA_DST])); + } + + common::mac_address_t mac_address((const uint8_t*)RTA_DATA(rt_attributes[NDA_LLADDR])); + + callback(interface_name, ip_address, mac_address); + } + + offset += NLMSG_ALIGN(length); + } + + if (buffer_length - offset) + { + YANET_LOG_WARNING("extra buffer_length: %u of %u\n", offset, buffer_length); + } +} + +static void netlink_neighbor_monitor(const std::function& callback) +{ + int nl_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (nl_socket < 0) + { + YANET_LOG_ERROR("socket(): %s\n", strerror(errno)); + return; + } + + sockaddr_nl nl_sockaddr; + memset(&nl_sockaddr, 0, sizeof(nl_sockaddr)); + nl_sockaddr.nl_family = AF_NETLINK; + nl_sockaddr.nl_groups = 1u << (RTNLGRP_NEIGH - 1); + + if (bind(nl_socket, (sockaddr*)&nl_sockaddr, sizeof(nl_sockaddr)) < 0) + { + YANET_LOG_ERROR("bind(): %s\n", strerror(errno)); + return; + } + + char buffer[4096]; + for (;;) + { + int buffer_length = recv(nl_socket, buffer, sizeof(buffer), 0); + if (buffer_length > 0) + { + netlink_parse(callback, buffer, buffer_length); + } + else + { + break; + } + } + + close(nl_socket); +} + +module::module() : + dataplane(nullptr) +{ + memset(&stats, 0, sizeof(stats)); +} + +eResult module::init(cDataPlane* dataplane) +{ + this->dataplane = dataplane; + + generation_hashtable.fill([&](neighbor::generation_hashtable& hashtable) { + for (const auto socket_id : dataplane->get_socket_ids()) + { + dataplane->hugepage_create_dynamic(socket_id, + 64 * 1024, + hashtable.hashtable_updater[socket_id]); + } + }); + + threads.emplace_back([this]() { + main_thread(); + }); + + threads.emplace_back([this]() { + netlink_thread(); + }); + + return eResult::success; +} + +void module::update_worker_base(const std::vector>& base_nexts) +{ + auto lock = generation_hashtable.current_lock_guard(); + for (auto& [socket_id, base_next] : base_nexts) + { + const auto& hashtable_updater = generation_hashtable.current().hashtable_updater; + base_next->neighbor_hashtable = hashtable_updater.find(socket_id)->second.get_pointer(); + } +} + +common::idp::neighbor_show::response module::neighbor_show() const +{ + common::idp::neighbor_show::response response; + + generation_interface.current_lock(); + auto interface_id_to_name = generation_interface.current().interface_id_to_name; + generation_interface.current_unlock(); + + { + auto lock = generation_hashtable.current_lock_guard(); + + const auto& hashtable_updater = generation_hashtable.current().hashtable_updater.begin()->second; + for (auto iter : hashtable_updater.range()) + { + if (iter.is_valid()) + { + auto& key = *iter.key(); + auto& value = *iter.value(); + + const auto& interface_id_to_name = generation_interface.current().interface_id_to_name; + auto it = interface_id_to_name.find(key.interface_id); + if (it == interface_id_to_name.end()) + { + continue; + } + + const auto& [route_name, interface_name] = it->second; + + response.emplace_back(route_name, + interface_name, + common::ip_address_t(key.flags & flag_is_ipv6 ? 6 : 4, key.address.bytes), + common::mac_address_t(value.ether_address.addr_bytes), + value.last_update_timestamp); + } + } + } + + return response; +} + +eResult module::neighbor_insert(const common::idp::neighbor_insert::request& request) +{ + const auto& [route_name, interface_name, ip_address, mac_address] = request; + (void)route_name; ///< @todo + + tInterfaceId interface_id = 0; + { + auto lock = generation_interface.current_lock_guard(); + + const auto& interface_name_to_id = generation_interface.current().interface_name_to_id; + auto it = interface_name_to_id.find(interface_name); + if (it == interface_name_to_id.end()) + { + return eResult::invalidInterfaceName; + } + + interface_id = it->second; + } + + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = interface_id; + key.flags = 0; + + if (ip_address.is_ipv4()) + { + key.address.mapped_ipv4_address = ipv4_address_t::convert(ip_address.get_ipv4()); + } + else + { + key.address = ipv6_address_t::convert(ip_address.get_ipv6()); + key.flags |= flag_is_ipv6; + } + + dataplane::neighbor::value value; + memcpy(value.ether_address.addr_bytes, mac_address.data(), 6); + + auto response = generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { + eResult result = eResult::success; + for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) + { + (void)socket_id; + if (!hashtable_updater.get_pointer()->insert_or_update(key, value)) + { + result = eResult::isFull; + stats.hashtable_insert_error++; + } + else + { + stats.hashtable_insert_success++; + } + } + return result; + }); + + return response; +} + +eResult module::neighbor_remove(const common::idp::neighbor_remove::request& request) +{ + const auto& [route_name, interface_name, ip_address] = request; + (void)route_name; ///< @todo + + tInterfaceId interface_id = 0; + { + auto lock = generation_interface.current_lock_guard(); + + const auto& interface_name_to_id = generation_interface.current().interface_name_to_id; + auto it = interface_name_to_id.find(interface_name); + if (it == interface_name_to_id.end()) + { + return eResult::invalidInterfaceName; + } + + interface_id = it->second; + } + + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = interface_id; + key.flags = 0; + + if (ip_address.is_ipv4()) + { + key.address.mapped_ipv4_address = ipv4_address_t::convert(ip_address.get_ipv4()); + } + else + { + key.address = ipv6_address_t::convert(ip_address.get_ipv6()); + key.flags |= flag_is_ipv6; + } + + auto response = generation_hashtable.update([this, key](neighbor::generation_hashtable& hashtable) { + eResult result = eResult::success; + for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) + { + (void)socket_id; + if (!hashtable_updater.get_pointer()->remove(key)) + { + result = eResult::invalidArguments; + stats.hashtable_remove_error++; + } + else + { + stats.hashtable_remove_success++; + } + } + return result; + }); + + return response; +} + +eResult module::neighbor_clear() +{ + auto response = generation_hashtable.update([](neighbor::generation_hashtable& hashtable) { + for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) + { + (void)socket_id; + hashtable_updater.get_pointer()->clear(); + } + return eResult::success; + }); + + return response; +} + +eResult module::neighbor_flush() +{ + generation_hashtable.switch_generation_with_update([this]() { + dataplane->switch_worker_base(); + }); + return eResult::success; +} + +eResult module::neighbor_update_interfaces(const common::idp::neighbor_update_interfaces::request& request) +{ + generation_interface.next_lock(); + + auto& generation = generation_interface.next(); + for (const auto& [interface_id, + route_name, + interface_name] : request) + { + generation.interface_name_to_id[interface_name] = interface_id; + generation.interface_id_to_name[interface_id] = {route_name, interface_name}; + } + + generation_interface.switch_generation(); + generation_interface.next_unlock(); + return eResult::success; +} + +common::idp::neighbor_stats::response module::neighbor_stats() const +{ + return stats; +} + +void module::report(nlohmann::json& json) +{ + json["neighbor"]["hashtable_insert_success"] = stats.hashtable_insert_success; + json["neighbor"]["hashtable_insert_error"] = stats.hashtable_insert_error; + json["neighbor"]["hashtable_remove_success"] = stats.hashtable_remove_success; + json["neighbor"]["hashtable_remove_error"] = stats.hashtable_remove_error; + json["neighbor"]["netlink_neighbor_update"] = stats.netlink_neighbor_update; + json["neighbor"]["resolve"] = stats.resolve; +} + +void module::main_thread() +{ + std::vector keys; + + for (;;) + { + keys.clear(); + + for (auto* worker : dataplane->get_workers()) + { + dataplane->run_on_worker_gc(worker->socketId, [&]() { + for (auto iter : worker->neighbor_resolve.range()) + { + iter.lock(); + if (!iter.is_valid()) + { + iter.unlock(); + continue; + } + + auto key = *iter.key(); + + iter.unset_valid(); + iter.unlock(); + + keys.emplace_back(key); + } + + return true; + }); + } + + for (const auto& key : keys) + { + resolve(key); + } + + generation_hashtable.switch_generation_with_update([this]() { + dataplane->switch_worker_base(); + }); + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void module::netlink_thread() +{ +#ifdef CONFIG_YADECAP_AUTOTEST + return; +#endif // CONFIG_YADECAP_AUTOTEST + + for (;;) + { + netlink_neighbor_monitor([&](const std::string& interface_name, + const common::ip_address_t& ip_address, + const common::mac_address_t& mac_address) { + tInterfaceId interface_id = 0; + { + auto lock = generation_interface.current_lock_guard(); + + const auto& interface_name_to_id = generation_interface.current().interface_name_to_id; + auto it = interface_name_to_id.find(interface_name); + if (it == interface_name_to_id.end()) + { + return; + } + interface_id = it->second; + } + + YANET_LOG_DEBUG("netlink: %s, %s -> %s\n", + interface_name.data(), + ip_address.toString().data(), + mac_address.toString().data()); + + stats.netlink_neighbor_update++; + + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = interface_id; + key.flags = 0; + + if (ip_address.is_ipv4()) + { + key.address.mapped_ipv4_address = ipv4_address_t::convert(ip_address.get_ipv4()); + } + else + { + key.address = ipv6_address_t::convert(ip_address.get_ipv6()); + key.flags |= flag_is_ipv6; + } + + value value; + memcpy(value.ether_address.addr_bytes, mac_address.data(), 6); + + generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { + for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) + { + (void)socket_id; + if (!hashtable_updater.get_pointer()->insert_or_update(key, value)) + { + stats.hashtable_insert_error++; + } + else + { + stats.hashtable_insert_success++; + } + } + return eResult::success; + }); + }); + + YANET_LOG_WARNING("restart neighbor_monitor\n"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} + +void module::resolve(const dataplane::neighbor::key& key) +{ + stats.resolve++; + + common::ip_address_t ip_address(key.flags & flag_is_ipv6 ? 6 : 4, key.address.bytes); + std::string interface_name; + { + auto lock = generation_interface.current_lock_guard(); + const auto& interface_id_to_name = generation_interface.current().interface_id_to_name; + auto it = interface_id_to_name.find(key.interface_id); + if (it == interface_id_to_name.end()) + { + YANET_LOG_ERROR("unknown interface_id: %u [ipv4_address: %s]\n", + key.interface_id, + ip_address.toString().data()); + return; + } + + const auto& [it_route_name, it_interface_name] = it->second; + (void)it_route_name; + + interface_name = it_interface_name; + } + + YANET_LOG_DEBUG("resolve: %s, %s\n", + interface_name.data(), + ip_address.toString().data()); + +#ifdef CONFIG_YADECAP_AUTOTEST + value value; + value.ether_address.addr_bytes[0] = 44; + value.ether_address.addr_bytes[1] = 44; + if (key.flags & flag_is_ipv6) + { + value.ether_address.addr_bytes[0] = 66; + value.ether_address.addr_bytes[1] = 66; + } + *((uint32_t*)&value.ether_address.addr_bytes[2]) = rte_hash_crc(key.address.bytes, 16, 0); + + generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { + for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) + { + (void)socket_id; + if (!hashtable_updater.get_pointer()->insert_or_update(key, value)) + { + stats.hashtable_insert_error++; + } + else + { + stats.hashtable_insert_success++; + } + } + return eResult::success; + }); +#else // CONFIG_YADECAP_AUTOTEST + + /// @todo: in first, try resolve like 'ip neig show 10.0.0.1 dev eth0' + + int family = AF_INET; + int protocol = IPPROTO_ICMP; + if (key.flags & flag_is_ipv6) + { + family = AF_INET6; + protocol = IPPROTO_ICMPV6; + } + + int icmp_socket = socket(family, SOCK_RAW, protocol); + if (icmp_socket == -1) + { + YANET_LOG_WARNING("neighbor_resolve: socket(): %s\n", + strerror(errno)); + return; + } + + int rc = setsockopt(icmp_socket, + SOL_SOCKET, + SO_BINDTODEVICE, + interface_name.data(), + strlen(interface_name.data()) + 1); + if (rc == -1) + { + YANET_LOG_WARNING("neighbor_resolve: setsockopt(%s): %s\n", + interface_name.data(), + strerror(errno)); + close(icmp_socket); + return; + } + + union + { + sockaddr address; + sockaddr_in address_v4; + sockaddr_in6 address_v6; + }; + + socklen_t address_length = sizeof(address_v4); + + if (key.flags & flag_is_ipv6) + { + address_v6.sin6_family = AF_INET6; + address_v6.sin6_port = 0; + memcpy(address_v6.sin6_addr.__in6_u.__u6_addr8, key.address.bytes, 16); + + address_length = sizeof(address_v6); + } + else + { + address_v4.sin_family = AF_INET; + address_v4.sin_port = 0; + address_v4.sin_addr.s_addr = key.address.mapped_ipv4_address.address; + } + + icmphdr header; + memset(&header, 0, sizeof(header)); + if (sendto(icmp_socket, + &header, + sizeof(header), + 0, + &address, + address_length) == 0) + { + YANET_LOG_WARNING("neighbor_resolve: sendto(): %s\n", + strerror(errno)); + } + + close(icmp_socket); +#endif // CONFIG_YADECAP_AUTOTEST +} diff --git a/dataplane/neighbor.h b/dataplane/neighbor.h new file mode 100644 index 00000000..1c5483cd --- /dev/null +++ b/dataplane/neighbor.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "common/generation.h" +#include "common/idp.h" +#include "common/neighbor.h" + +#include "hashtable.h" +#include "type.h" + +namespace dataplane::neighbor +{ + +constexpr static uint16_t flag_is_ipv6 = 1; + +struct key +{ + tInterfaceId interface_id : 16; + uint16_t flags; + ipv6_address_t address; +}; + +static_assert(CONFIG_YADECAP_INTERFACES_SIZE <= 0xFFFF, "invalid size"); + +struct value +{ + rte_ether_addr ether_address; + uint16_t last_update_timestamp; +}; + +// + +using hashtable = hashtable_mod_dynamic; + +// + +class generation_interface +{ +public: + std::unordered_map interface_name_to_id; + std::unordered_map> ///< interface_name + interface_id_to_name; +}; + +class generation_hashtable +{ +public: + std::map hashtable_updater; +}; + +// + +class module +{ +public: + module(); + +public: + eResult init(cDataPlane* dataplane); + + void update_worker_base(const std::vector>& base_nexts); + + common::idp::neighbor_show::response neighbor_show() const; + eResult neighbor_insert(const common::idp::neighbor_insert::request& request); + eResult neighbor_remove(const common::idp::neighbor_remove::request& request); + eResult neighbor_clear(); + eResult neighbor_flush(); + eResult neighbor_update_interfaces(const common::idp::neighbor_update_interfaces::request& request); + common::idp::neighbor_stats::response neighbor_stats() const; + + void report(nlohmann::json& json); + +protected: + void main_thread(); + void netlink_thread(); + + void resolve(const dataplane::neighbor::key& key); + +protected: + cDataPlane* dataplane; + + std::vector threads; + + generation_manager generation_interface; + generation_manager generation_hashtable; + + common::neighbor::stats stats; +}; + +} diff --git a/dataplane/report.cpp b/dataplane/report.cpp index 026c8d32..21fb5b54 100644 --- a/dataplane/report.cpp +++ b/dataplane/report.cpp @@ -159,6 +159,8 @@ nlohmann::json cReport::getReport() } jsonReport["memory_total"] = memory_total; + dataPlane->neighbor.report(jsonReport); + return jsonReport; } @@ -761,8 +763,6 @@ nlohmann::json cReport::convertGlobalBase(const dataplane::globalBase::generatio nlohmann::json jsonInterface; jsonInterface["interfaceId"] = interfaceId; - jsonInterface["neighbor_ether_address_v4"] = convertEtherAddressToString(interface.neighbor_ether_address_v4); - jsonInterface["neighbor_ether_address_v6"] = convertEtherAddressToString(interface.neighbor_ether_address_v6); jsonInterface["flow"] = convertFlow(interface.flow); json["interfaces"].emplace_back(jsonInterface); diff --git a/dataplane/type.h b/dataplane/type.h index 83346038..b6c21713 100644 --- a/dataplane/type.h +++ b/dataplane/type.h @@ -295,8 +295,6 @@ struct tInterface { /// @todo: uint8_t enabled; - rte_ether_addr neighbor_ether_address_v4; - rte_ether_addr neighbor_ether_address_v6; tAclId aclId; common::globalBase::tFlow flow; }; @@ -384,25 +382,19 @@ struct dregress_t struct nexthop ///< @todo { tInterfaceId interfaceId : 16; + ipv6_address_t neighbor_address; uint32_t labelExpTransport; ///< @todo: rename first uint32_t labelExpService; ///< @todo: rename second }; struct nexthop_tunnel_t { - union - { - struct - { - tInterfaceId interface_id : 8; - tCounterId counter_id : 24; - }; - - uint32_t atomic1; - }; - + tInterfaceId interface_id : 16; + uint16_t flags; + tCounterId counter_id; uint32_t label; ipv6_address_t nexthop_address; + ipv6_address_t neighbor_address; }; static_assert(YANET_CONFIG_COUNTERS_SIZE <= 0xFFFFFF, "invalid YANET_CONFIG_COUNTERS_SIZE"); @@ -427,8 +419,6 @@ struct route_value_t }; }; -static_assert(sizeof(route_value_t) == 192, "invalid size of route_value_t"); - struct route_tunnel_value_t { route_tunnel_value_t() : diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index 0553a9cd..4679b4a6 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -2165,16 +2165,29 @@ inline void cWorker::route_handle4() continue; } - if (targetInterface.neighbor_ether_address_v4.addr_bytes[0] == 1) + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = nexthop.interfaceId; + key.flags = 0; + key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + + dataplane::neighbor::value const* value; + base.neighbor_hashtable->lookup(key, value); + if (value) + { + generic_rte_ether_hdr* ethernet_header = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); + rte_ether_addr_copy(&value->ether_address, ðernet_header->dst_addr); + } + else { stats.interface_neighbor_invalid++; drop(mbuf); + + neighbor_resolve.insert_or_update(key, 0); + continue; } - generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); - rte_ether_addr_copy(&targetInterface.neighbor_ether_address_v4, ðernetHeader->dst_addr); - route_nexthop(mbuf, nexthop); ipv4Header->time_to_live--; @@ -2264,16 +2277,30 @@ inline void cWorker::route_handle6() continue; } - if (targetInterface.neighbor_ether_address_v6.addr_bytes[0] == 1) + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = nexthop.interfaceId; + key.flags = 0; + key.flags |= dataplane::neighbor::flag_is_ipv6; + memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + + dataplane::neighbor::value const* value; + base.neighbor_hashtable->lookup(key, value); + if (value) + { + generic_rte_ether_hdr* ethernet_header = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); + rte_ether_addr_copy(&value->ether_address, ðernet_header->dst_addr); + } + else { stats.interface_neighbor_invalid++; drop(mbuf); + + neighbor_resolve.insert_or_update(key, 0); + continue; } - generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); - rte_ether_addr_copy(&targetInterface.neighbor_ether_address_v6, ðernetHeader->dst_addr); - route_nexthop(mbuf, nexthop); ipv6Header->hop_limits--; @@ -2450,19 +2477,31 @@ inline void cWorker::route_tunnel_handle4() continue; } - if (targetInterface.neighbor_ether_address_v4.addr_bytes[0] == 1) + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = nexthop.interface_id; + key.flags = 0; + key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + + dataplane::neighbor::value const* value; + base.neighbor_hashtable->lookup(key, value); + if (value) + { + generic_rte_ether_hdr* ethernet_header = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); + rte_ether_addr_copy(&value->ether_address, ðernet_header->dst_addr); + } + else { stats.interface_neighbor_invalid++; drop(mbuf); + + neighbor_resolve.insert_or_update(key, 0); + continue; } - /// counters[nexthop.counter_id]++; - counters[nexthop.atomic1 >> 8]++; - counters[(nexthop.atomic1 >> 8) + 1] += mbuf->pkt_len; - - generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); - rte_ether_addr_copy(&targetInterface.neighbor_ether_address_v4, ðernetHeader->dst_addr); + counters[nexthop.counter_id]++; + counters[nexthop.counter_id + 1] += mbuf->pkt_len; route_tunnel_nexthop(mbuf, nexthop); @@ -2556,19 +2595,32 @@ inline void cWorker::route_tunnel_handle6() continue; } - if (targetInterface.neighbor_ether_address_v6.addr_bytes[0] == 1) + dataplane::neighbor::key key; + memset(&key, 0, sizeof(key)); + key.interface_id = nexthop.interface_id; + key.flags = 0; + key.flags |= dataplane::neighbor::flag_is_ipv6; + memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + + dataplane::neighbor::value const* value; + base.neighbor_hashtable->lookup(key, value); + if (value) + { + generic_rte_ether_hdr* ethernet_header = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); + rte_ether_addr_copy(&value->ether_address, ðernet_header->dst_addr); + } + else { stats.interface_neighbor_invalid++; drop(mbuf); + + neighbor_resolve.insert_or_update(key, 0); + continue; } - /// counters[nexthop.counter_id]++; - counters[nexthop.atomic1 >> 8]++; - counters[(nexthop.atomic1 >> 8) + 1] += mbuf->pkt_len; - - generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); - rte_ether_addr_copy(&targetInterface.neighbor_ether_address_v6, ðernetHeader->dst_addr); + counters[nexthop.counter_id]++; + counters[nexthop.counter_id + 1] += mbuf->pkt_len; route_tunnel_nexthop(mbuf, nexthop); diff --git a/dataplane/worker.h b/dataplane/worker.h index 3731f47f..6410262d 100644 --- a/dataplane/worker.h +++ b/dataplane/worker.h @@ -214,7 +214,7 @@ class cWorker YANET_NEVER_INLINE void slowWorkerFlow(rte_mbuf* mbuf, const common::globalBase::tFlow& flow); YANET_NEVER_INLINE void slowWorkerTranslation(rte_mbuf* mbuf, const dataplane::globalBase::tNat64stateless& nat64stateless, const dataplane::globalBase::nat64stateless_translation_t& translation, bool direction); /** true: ingress, false: egress */ -protected: +public: friend class cDataPlane; friend class cReport; friend class cControlPlane; @@ -229,6 +229,7 @@ class cWorker rte_mempool* mempool; +protected: /// variables above are not needed for mainThread() YADECAP_CACHE_ALIGNED(align1); @@ -333,6 +334,15 @@ class cWorker samples::Sampler sampler; +public: + /// use this table for pass resolve neighbor MAC + dataplane::hashtable_mod_spinlock + neighbor_resolve; + +protected: YADECAP_CACHE_ALIGNED(align3); dataplane::base::generation bases[2]; diff --git a/dataplane/worker_gc.h b/dataplane/worker_gc.h index 99e5951a..1a39ec82 100644 --- a/dataplane/worker_gc.h +++ b/dataplane/worker_gc.h @@ -6,6 +6,7 @@ #include "base.h" #include "common.h" +#include "hashtable.h" #include "common/generation.h" #include "common/idp.h" From 701750d1636e8995707c55bd10259588a589d48c Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 11:37:19 +0300 Subject: [PATCH 02/12] add autotest for check resolve MAC via 'neighbor_resolve' --- .../070_neighbor_resolve/001-expect.pcap | Bin 0 -> 24 bytes .../070_neighbor_resolve/001-send.pcap | Bin 0 -> 98 bytes .../070_neighbor_resolve/002-expect.pcap | Bin 0 -> 98 bytes .../070_neighbor_resolve/002-send.pcap | Bin 0 -> 98 bytes .../070_neighbor_resolve/003-expect.pcap | Bin 0 -> 24 bytes .../070_neighbor_resolve/003-send.pcap | Bin 0 -> 118 bytes .../070_neighbor_resolve/004-expect.pcap | Bin 0 -> 118 bytes .../070_neighbor_resolve/004-send.pcap | Bin 0 -> 118 bytes .../070_neighbor_resolve/autotest.yaml | 52 ++++++++++++++++++ .../070_neighbor_resolve/controlplane.conf | 37 +++++++++++++ .../001_one_port/070_neighbor_resolve/gen.py | 51 +++++++++++++++++ 11 files changed, 140 insertions(+) create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/001-expect.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/001-send.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/002-expect.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/002-send.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/003-expect.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/003-send.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/004-expect.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/004-send.pcap create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/autotest.yaml create mode 100644 autotest/units/001_one_port/070_neighbor_resolve/controlplane.conf create mode 100755 autotest/units/001_one_port/070_neighbor_resolve/gen.py diff --git a/autotest/units/001_one_port/070_neighbor_resolve/001-expect.pcap b/autotest/units/001_one_port/070_neighbor_resolve/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/001-send.pcap b/autotest/units/001_one_port/070_neighbor_resolve/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e303bb97232a17a0c9f4921a339e9e22bce3a663 GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmqyz;885r)ZWngGzU`XL$aAjc704a4~%Q(&j V)WiY=@)J1VdIOjg7{a_57yzzU3)TPt literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/002-expect.pcap b/autotest/units/001_one_port/070_neighbor_resolve/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..101a04736e9eb339e2ea33e396d5f82cd16b2377 GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2?5(pFHcqhnj9`4`9$6clV^U`XL$aAjc704cR+%RJ5n V)WiY=@)J1VdIOjg7{a_57y#HO4153p literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/002-send.pcap b/autotest/units/001_one_port/070_neighbor_resolve/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e303bb97232a17a0c9f4921a339e9e22bce3a663 GIT binary patch literal 98 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmqyz;885r)ZWngGzU`XL$aAjc704a4~%Q(&j V)WiY=@)J1VdIOjg7{a_57yzzU3)TPt literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/003-expect.pcap b/autotest/units/001_one_port/070_neighbor_resolve/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a324304509bdd12aef4a69458a409cefefafe614 GIT binary patch literal 24 Ycmca|c+)~A1{MYw`2U}Qff2|708wKE@Bjb+ literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/003-send.pcap b/autotest/units/001_one_port/070_neighbor_resolve/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..8e2558b76fe7f7ad46bd94be8b01d50d61bfb641 GIT binary patch literal 118 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13q?DAD7#QxYWngGzU^vlsHvuTbAj0O5f&^HA kK!IWP*?<2wY&dY>-!d+sVH^zd6F^EqAb?4M;UG{D0FK}px&QzG literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/004-expect.pcap b/autotest/units/001_one_port/070_neighbor_resolve/004-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e98800abb23191033812e03c19c08e6046d9588d GIT binary patch literal 118 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3v-!d+sVH^zd6F^EqAb?4M;UG{D0FK}px&QzG literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/autotest.yaml b/autotest/units/001_one_port/070_neighbor_resolve/autotest.yaml new file mode 100644 index 00000000..7561c73b --- /dev/null +++ b/autotest/units/001_one_port/070_neighbor_resolve/autotest.yaml @@ -0,0 +1,52 @@ +steps: +- ipv4Update: "0.0.0.0/0 -> 200.0.0.1" +- ipv6Update: "::/0 -> fe80::1" +- cli_check: | + YANET_FORMAT_COLUMNS=route_name,interface_name,ip_address,mac_address neighbor show + route_name interface_name ip_address mac_address + ---------- -------------- ---------- ----------- +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sleep: 1 +- 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 +- cli_check: | + YANET_FORMAT_COLUMNS=route_name,interface_name,ip_address,mac_address neighbor show + route_name interface_name ip_address mac_address + ---------- -------------- ---------- ----------------- + route0 kni0.100 200.0.0.1 2C:2C:3D:76:29:FD + route0 kni0.200 fe80::1 42:42:A4:59:BE:A5 + +- cli: neighbor insert route0 kni0.100 200.0.0.2 00:11:22:33:44:55 +- sleep: 1 + +- cli_check: | + YANET_FORMAT_COLUMNS=route_name,interface_name,ip_address,mac_address neighbor show + route_name interface_name ip_address mac_address + ---------- -------------- ---------- ----------------- + route0 kni0.100 200.0.0.2 00:11:22:33:44:55 + route0 kni0.100 200.0.0.1 2C:2C:3D:76:29:FD + route0 kni0.200 fe80::1 42:42:A4:59:BE:A5 + +- cli: neighbor remove route0 kni0.100 200.0.0.2 +- sleep: 1 + +- cli_check: | + YANET_FORMAT_COLUMNS=route_name,interface_name,ip_address,mac_address neighbor show + route_name interface_name ip_address mac_address + ---------- -------------- ---------- ----------------- + route0 kni0.100 200.0.0.1 2C:2C:3D:76:29:FD + route0 kni0.200 fe80::1 42:42:A4:59:BE:A5 diff --git a/autotest/units/001_one_port/070_neighbor_resolve/controlplane.conf b/autotest/units/001_one_port/070_neighbor_resolve/controlplane.conf new file mode 100644 index 00000000..811b6b61 --- /dev/null +++ b/autotest/units/001_one_port/070_neighbor_resolve/controlplane.conf @@ -0,0 +1,37 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:00:00:11:11:11", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:00:00:22:22:22", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "route0" + ] + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "200.0.0.1", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv6Address": "fe80::1", + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/070_neighbor_resolve/gen.py b/autotest/units/001_one_port/070_neighbor_resolve/gen.py new file mode 100755 index 00000000..36f0d4b6 --- /dev/null +++ b/autotest/units/001_one_port/070_neighbor_resolve/gen.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +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) + + +# ipv4 (first packet. resolve mac) +write_pcap("001-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="10.0.0.1", ttl=64)/TCP(dport=2048, sport=8080)) + +write_pcap("001-expect.pcap") + + +# ipv4 +write_pcap("002-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="10.0.0.1", ttl=64)/TCP(dport=2048, sport=8080)) + +write_pcap("002-expect.pcap", + Ether(dst="2C:2C:3D:76:29:FD", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="10.0.0.1", ttl=63)/TCP(dport=2048, sport=8080)) + + +# ipv6 (first packet. resolve mac) +write_pcap("003-send.pcap", + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:10.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=64)/TCP(dport=8080, sport=2048)) + +write_pcap("003-expect.pcap") + + +# ipv6 +write_pcap("004-send.pcap", + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:10.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=64)/TCP(dport=8080, sport=2048)) + +write_pcap("004-expect.pcap", + Ether(dst="42:42:A4:59:BE:A5", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:10.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=63)/TCP(dport=8080, sport=2048)) From 62f07e00299fac4f0adedfb7247fface1d8c1cef Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 18:58:18 +0300 Subject: [PATCH 03/12] remove resolve MAC from controlplane. dregress: always use route module for send probe packet. update dregress autotest. --- .../029_acl_dregress_decap/002-expect.pcap | Bin 660 -> 660 bytes .../029_acl_dregress_decap/003-expect.pcap | Bin 720 -> 720 bytes .../029_acl_dregress_decap/004-expect.pcap | Bin 818 -> 818 bytes .../029_acl_dregress_decap/005-expect.pcap | Bin 130 -> 130 bytes .../029_acl_dregress_decap/006-expect.pcap | Bin 180 -> 172 bytes .../029_acl_dregress_decap/007-expect.pcap | Bin 180 -> 172 bytes .../029_acl_dregress_decap/009-expect.pcap | Bin 462 -> 462 bytes .../029_acl_dregress_decap/010-expect.pcap | Bin 920 -> 920 bytes .../029_acl_dregress_decap/011-expect.pcap | Bin 1058 -> 1058 bytes .../029_acl_dregress_decap/autotest.yaml | 2 +- .../029_acl_dregress_decap/controlplane.conf | 6 +- .../029_acl_dregress_decap/gen.py | 71 ++++++++------- common/idp.h | 2 +- controlplane/controlplane.cpp | 43 --------- controlplane/controlplane.h | 1 - controlplane/dregress.cpp | 86 ------------------ controlplane/dregress.h | 2 - controlplane/module.cpp | 4 - controlplane/module.h | 2 - dataplane/dregress.cpp | 43 +-------- dataplane/dregress.h | 4 - dataplane/globalbase.cpp | 16 +--- dataplane/globalbase.h | 1 - 23 files changed, 45 insertions(+), 238 deletions(-) diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/002-expect.pcap b/autotest/units/001_one_port/029_acl_dregress_decap/002-expect.pcap index 97fe030d2e0a83782fa5fbf0e84d9b607ef5172d..87690da593529691c1644f4f8bdb1dcb865ddd73 100644 GIT binary patch delta 52 mcmbQjI)!zD6SKYG%89P&U}`;>nk>l(p_`%fTPPjQWD5YbBoK4} delta 52 mcmbQjI)!zD6SIThiixi2U}`;>nk>l(p_`%fTPPjQWD5YbFc5SA diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/003-expect.pcap b/autotest/units/001_one_port/029_acl_dregress_decap/003-expect.pcap index 17929979b453e1688b740ffe198205fa7a8b4f1c..e34b596b426b43779b183fd6b1ccd258ce214a9d 100644 GIT binary patch delta 48 qcmcb>dVzI<6SKYG%89P&U}}9oh??xk*axOBF;0i_MJ6{e1pok<3lJj! delta 48 qcmcb>dVzI<6SIThiixi2U}}9oh??xk*axOBF;0i_MJ6{e1pok<6%Zo; diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/004-expect.pcap b/autotest/units/001_one_port/029_acl_dregress_decap/004-expect.pcap index 11d48a33d3127dd7d193abbe3c67decc47bd1ed2..7ba5864da440e75780f9c026b16f099ec9295dd9 100644 GIT binary patch delta 50 hcmdnQwuxB$w0VE|=+5b6K` delta 43 xcmX@de2#g7BcsE_D+&{n3PJQlVFx9p8D$I%LMH3hF*5%9cS`VI!{iFaFaTwd5Y+$x diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/010-expect.pcap b/autotest/units/001_one_port/029_acl_dregress_decap/010-expect.pcap index 9b2d92e382be7d5d8efc8c7d77cd4a0c14238bbe..46523b7bd0e36c4c81e6754b3639a0aa61acdeef 100644 GIT binary patch delta 50 qcmbQiK7)ONBcuJ~K1S7v={Zow&naNW4hVO04$~YkOM9{ja|!^kLJ*k% delta 50 qcmbQiK7)ONBcsFQK1S7v={Zow&naNW4hVO04$~YkOM9{ja|!^k#1NhU diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/011-expect.pcap b/autotest/units/001_one_port/029_acl_dregress_decap/011-expect.pcap index a691fee9e143195b4558e84732bcc407240672c6..3aa2f055e4404fb67219461bedbf589b6986382d 100644 GIT binary patch delta 58 icmZ3)v4~@WBcuJ~K1S8aIZQcF)<32xVAc+tGW`HD?h|zY delta 58 icmZ3)v4~@WBcsFQK1S8aIZQcF)<32xVAc+tGW`HEmJ@pb diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/autotest.yaml b/autotest/units/001_one_port/029_acl_dregress_decap/autotest.yaml index 10c3abc8..049608cd 100644 --- a/autotest/units/001_one_port/029_acl_dregress_decap/autotest.yaml +++ b/autotest/units/001_one_port/029_acl_dregress_decap/autotest.yaml @@ -12,7 +12,7 @@ steps: - ipv6Update: "::/0 -> fe80::1" - ipv6LabelledUpdate: - "cccc::/16 -> caca::123|210" - - "dddd::/16 -> fe80::1|211" + - "dddd::/16 -> cbcb::1|211" - sendPackets: - port: kni0 send: 001-send.pcap diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/controlplane.conf b/autotest/units/001_one_port/029_acl_dregress_decap/controlplane.conf index e4cfc7b6..d23741d7 100644 --- a/autotest/units/001_one_port/029_acl_dregress_decap/controlplane.conf +++ b/autotest/units/001_one_port/029_acl_dregress_decap/controlplane.conf @@ -65,7 +65,11 @@ "neighborMacAddress": "00:00:00:00:00:02", "nextModule": "lp0.200" } - } + }, + "ignore_tables": [ + "ipv4 mpls", + "ipv6 mpls" + ] } } } diff --git a/autotest/units/001_one_port/029_acl_dregress_decap/gen.py b/autotest/units/001_one_port/029_acl_dregress_decap/gen.py index 6c226f19..c0eaa8b6 100755 --- a/autotest/units/001_one_port/029_acl_dregress_decap/gen.py +++ b/autotest/units/001_one_port/029_acl_dregress_decap/gen.py @@ -35,12 +35,12 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="daad::1", fl=0x12345, hlim=64)/IP(dst="6.7.8.0", src="5.5.5.81", ttl=64)/TCP(dport=80, sport=2048)) write_pcap("002-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xbe62 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x682a | 0xc000, chksum=0)/MPLS(label=111, ttl=255)/IP(dst="6.7.8.1", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x6403 | 0xc000, chksum=0)/MPLS(label=112, ttl=255)/IP(dst="6.7.8.2", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xb24b | 0xc000, chksum=0)/MPLS(label=113, ttl=255)/IP(dst="6.7.8.3", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x58d3 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.80", ttl=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x60b6 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.81", ttl=64)/TCP(dport=80, sport=2048)) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xbe62 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x682a | 0xc000, chksum=0)/MPLS(label=111, ttl=255)/IP(dst="6.7.8.1", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x6403 | 0xc000, chksum=0)/MPLS(label=112, ttl=255)/IP(dst="6.7.8.2", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xb24b | 0xc000, chksum=0)/MPLS(label=113, ttl=255)/IP(dst="6.7.8.3", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x58d3 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.80", ttl=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x60b6 | 0xc000, chksum=0)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.81", ttl=64)/TCP(dport=80, sport=2048)) TCP_SYNACK = TCP(sport=8800, dport=555, flags='SA', seq=3535) @@ -57,11 +57,11 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK2_2) write_pcap("003-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK2_1, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=253)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK1_2, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=252)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK2_2) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK2_1, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=253)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK1_2, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x974e | 0xc000, chksum=0)/MPLS(label=114, ttl=252)/IP(dst="6.7.8.6", src="5.5.5.66", ttl=64)/TCP_ACK2_2) write_pcap("004-send.pcap", @@ -73,26 +73,27 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK2_1) write_pcap("004-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK2_1, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK2_1) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK2_1, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=255)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0xaf2b | 0xc000, chksum=0)/MPLS(label=114, ttl=254)/IP(dst="6.7.8.6", src="5.5.5.67", ttl=64)/TCP_ACK2_1) write_pcap("005-send.pcap", Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IP(dst="7.0.0.1", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048)) write_pcap("005-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=64)/UDP(dport=6635, sport=0x0b40 | 0xc000, chksum=0)/MPLS(label=115, ttl=255)/IP(dst="7.0.0.1", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048)) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="200.0.0.1", src="10.50.0.1", ttl=63)/UDP(dport=6635, sport=0x0b40 | 0xc000, chksum=0)/MPLS(label=115, ttl=255)/IP(dst="7.0.0.1", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048)) +# 'local' packet write_pcap("006-send.pcap", Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IP(dst="7.0.0.2/31", src="5.5.5.55", ttl=64)/TCP(dport=80, sport=2048)) write_pcap("006-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=115, ttl=255)/IP(dst="7.0.0.2/31", src="5.5.5.55", ttl=63)/TCP(dport=80, sport=2048)) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="7.0.0.2/31", src="5.5.5.55", ttl=63)/TCP(dport=80, sport=2048)) write_pcap("007-send.pcap", @@ -100,8 +101,8 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="daad::3", fl=0x12345, hlim=64)/IP(dst="6.7.8.0", src="5.5.5.83", ttl=64)/TCP(dport=80, sport=2048)) write_pcap("007-expect.pcap", - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.82", ttl=63)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/MPLS(label=110, ttl=255)/IP(dst="6.7.8.0", src="5.5.5.83", ttl=63)/TCP(dport=80, sport=2048)) + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="6.7.8.0", src="5.5.5.82", ttl=63)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:02", src="00:11:22:33:44:55")/Dot1Q(vlan=200)/IP(dst="6.7.8.0", src="5.5.5.83", ttl=63)/TCP(dport=80, sport=2048)) write_pcap("008-send.pcap", @@ -119,9 +120,9 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="daad::1", fl=0x12345, hlim=64)/IPv6(dst="dddd::200", src="cafe::4", hlim=64)/TCP(dport=80, sport=2048)) write_pcap("009-expect.pcap", - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xa0b8 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::1", src="cafe::2", hlim=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xc6c8 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::100", src="cafe::3", hlim=64)/TCP(dport=80, sport=2048), - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="fe80::1", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x3b9f | 0xc000, chksum=0)/MPLS(label=211, ttl=255)/IPv6(dst="dddd::200", src="cafe::4", hlim=64)/TCP(dport=80, sport=2048)) + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xa0b8 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::1", src="cafe::2", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xc6c8 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::100", src="cafe::3", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="cbcb::1", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x3b9f | 0xc000, chksum=0)/MPLS(label=211, ttl=255)/IPv6(dst="dddd::200", src="cafe::4", hlim=64)/TCP(dport=80, sport=2048)) write_pcap("010-send.pcap", @@ -132,11 +133,11 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK2_2) write_pcap("010-expect.pcap", - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK2_1, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=253)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK1_2, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=252)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK2_2) + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK2_1, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=253)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK1_2, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0xd4e4 | 0xc000, chksum=0)/MPLS(label=210, ttl=252)/IPv6(dst="cccc::6", src="cafe::2", hlim=64)/TCP_ACK2_2) write_pcap("011-send.pcap", @@ -148,11 +149,11 @@ def write_pcap(filename, *packetsList): Ether(dst="00:11:22:33:44:55", src="00:00:00:00:00:02")/Dot1Q(vlan=200)/IPv6(dst="1234::abcd", src="abba::1", fl=0x12345, hlim=64)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK2_1) write_pcap("011-expect.pcap", - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK2_1, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_SYNACK, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK1_1, - Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=64)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK2_1) + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK2_1, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_SYNACK, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=255)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK1_1, + Ether(dst="00:00:00:00:00:01", src="00:11:22:33:44:55")/Dot1Q(vlan=100)/IPv6(dst="caca::123", src="2222:9876:0:1234:aeae:0101:fefe:ca11", hlim=63)/UDP(dport=6635, sport=0x6daa | 0xc000, chksum=0)/MPLS(label=210, ttl=254)/IPv6(dst="cccc::6", src="cafe::4", hlim=64)/TCP_ACK2_1) # @todo: ipv6 ext diff --git a/common/idp.h b/common/idp.h index bdcbb1f7..1382bd5b 100644 --- a/common/idp.h +++ b/common/idp.h @@ -429,7 +429,7 @@ namespace dregress_local_prefix_update using request = std::set; } -namespace dregress_neighbor_update +namespace dregress_neighbor_update ///< @deprecated { using request = std::tuple>, std::set>>; diff --git a/controlplane/controlplane.cpp b/controlplane/controlplane.cpp index 7e127802..b8486b99 100644 --- a/controlplane/controlplane.cpp +++ b/controlplane/controlplane.cpp @@ -193,11 +193,6 @@ void cControlPlane::start() } threads.emplace_back([this] { main_thread(); }); - -#ifdef CONFIG_YADECAP_AUTOTEST -#else // CONFIG_YADECAP_AUTOTEST - threads.emplace_back([this] { mac_address_resolve_thread(); }); -#endif // CONFIG_YADECAP_AUTOTEST } void cControlPlane::stop() @@ -972,44 +967,6 @@ void cControlPlane::main_thread() } } -void cControlPlane::mac_address_resolve_thread() -{ - while (!flagStop) - { - bool mac_addresses_changed = false; - - { - std::unique_lock mac_addresses_lock(mac_addresses_mutex); - - for (auto& [key, mac_address] : this->mac_addresses) - { - const auto& [vrf, interface_name, address] = key; - (void)vrf; - - const auto mac_address_next = system.getMacAddress(interface_name, address); - if (mac_address_next) - { - if ((!mac_address) || - *mac_address != *mac_address_next) - { - mac_address = mac_address_next; - mac_addresses_changed = true; - } - } - } - } - - if (mac_addresses_changed) - { - for (auto* module : modules) - { - module->mac_addresses_changed(); - } - } - - std::this_thread::sleep_for(std::chrono::seconds{8}); - } -} void cControlPlane::register_service(google::protobuf::Service* service) { services[service->GetDescriptor()->name()] = service; diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index e6cf6858..393de929 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -142,7 +142,6 @@ class cControlPlane void addConfig(uint32_t serial, const controlplane::base_t& config); void main_thread(); - void mac_address_resolve_thread(); protected: friend class telegraf_t; diff --git a/controlplane/dregress.cpp b/controlplane/dregress.cpp index 0bdef135..c5a10764 100644 --- a/controlplane/dregress.cpp +++ b/controlplane/dregress.cpp @@ -200,7 +200,6 @@ void dregress_t::prefix_flush() { std::lock_guard guard(mutex); compile(globalbase, generations.current()); - compile_neighbors(globalbase, generations.current()); } dataplane.updateGlobalBase(globalbase); @@ -242,75 +241,6 @@ void dregress_t::compile(common::idp::updateGlobalBase::request& globalbase, } } -void dregress_t::compile_neighbors(common::idp::updateGlobalBase::request& globalbase, - const dregress::generation_t& generation) -{ - if (!update_neighbors) - { - return; - } - - common::idp::updateGlobalBase::dregress_neighbor_update::request dregress_neighbor_update; - auto& [neighbor_v4, neighbor_v6] = dregress_neighbor_update; - - for (const auto& [route_name, route] : generation.routes) - { - (void)route_name; - - for (auto& [interface_name, interface] : route.interfaces) - { - if (interface.neighborIPv4Address) - { - if (exist(defaults_v4, *interface.neighborIPv4Address)) - { - std::optional neighbor_mac_address_v4; - - if (interface.static_neighbor_mac_address_v4) - { - neighbor_mac_address_v4 = *interface.static_neighbor_mac_address_v4; - } - else - { - neighbor_mac_address_v4 = controlPlane->get_mac_address(route.vrf, interface_name, *interface.neighborIPv4Address); - } - - if (neighbor_mac_address_v4) - { - neighbor_v4.emplace(*neighbor_mac_address_v4, interface.flow); - } - } - } - - if (interface.neighborIPv6Address) - { - if (exist(defaults_v6, *interface.neighborIPv6Address)) - { - std::optional neighbor_mac_address_v6; - - if (interface.static_neighbor_mac_address_v6) - { - neighbor_mac_address_v6 = *interface.static_neighbor_mac_address_v6; - } - else - { - neighbor_mac_address_v6 = controlPlane->get_mac_address(route.vrf, interface_name, *interface.neighborIPv6Address); - } - - if (neighbor_mac_address_v6) - { - neighbor_v6.emplace(*neighbor_mac_address_v6, interface.flow); - } - } - } - } - } - - globalbase.emplace_back(common::idp::updateGlobalBase::requestType::dregress_neighbor_update, - dregress_neighbor_update); - - update_neighbors = false; -} - void dregress_t::limit(common::icp::limit_summary::response& limits) const { limit_insert(limits, "dregress.values", values.stats()); @@ -331,7 +261,6 @@ void dregress_t::reload(const controlplane::base_t& base_prev, std::lock_guard guard(mutex); update_neighbors = true; compile(globalbase, generations.next()); - compile_neighbors(globalbase, generations.next()); } } @@ -341,21 +270,6 @@ void dregress_t::reload_after() generations.next_unlock(); } -void dregress_t::mac_addresses_changed() -{ - common::idp::updateGlobalBase::request globalbase; - - auto current_guard = generations.current_lock_guard(); - - { - std::lock_guard guard(mutex); - update_neighbors = true; - compile_neighbors(globalbase, generations.current()); - } - - dataplane.updateGlobalBase(globalbase); -} - std::optional dregress_t::value_insert(const dregress::value_key_t& value_key) { auto value_id = values.update_or_insert(value_key); diff --git a/controlplane/dregress.h b/controlplane/dregress.h index f10e9ee9..3ea8cd41 100644 --- a/controlplane/dregress.h +++ b/controlplane/dregress.h @@ -85,7 +85,6 @@ class dregress_t : public module_t void reload_before() override; void reload(const controlplane::base_t& base_prev, const controlplane::base_t& base_next, common::idp::updateGlobalBase::request& globalbase) override; void reload_after() override; - void mac_addresses_changed() override; void prefix_insert(const std::tuple& vrf_priority, const ip_prefix_t& prefix, const rib::nexthop_map_t& nexthops); void prefix_remove(const std::tuple& vrf_priority, const ip_prefix_t& prefix); @@ -95,7 +94,6 @@ class dregress_t : public module_t common::icp::dregress_config::response dregress_config() const; void compile(common::idp::updateGlobalBase::request& globalbase, const dregress::generation_t& generation); - void compile_neighbors(common::idp::updateGlobalBase::request& globalbase, const dregress::generation_t& generation); protected: std::optional value_insert(const dregress::value_key_t& value_key); diff --git a/controlplane/module.cpp b/controlplane/module.cpp index 0a6e1c2c..6d6c1f71 100644 --- a/controlplane/module.cpp +++ b/controlplane/module.cpp @@ -93,10 +93,6 @@ void cModule::reload_after() { } -void cModule::mac_addresses_changed() -{ -} - eResult cModule::init() { return eResult::success; diff --git a/controlplane/module.h b/controlplane/module.h index e7e3f8ee..fd107bdc 100644 --- a/controlplane/module.h +++ b/controlplane/module.h @@ -8,7 +8,6 @@ #include "common/idp.h" #include "common/result.h" -#include "common.h" #include "type.h" // @@ -33,7 +32,6 @@ class cModule virtual void reload_before(); virtual void reload(const controlplane::base_t& base_prev, const controlplane::base_t& base_next, common::idp::updateGlobalBase::request& globalbase); virtual void reload_after(); - virtual void mac_addresses_changed(); protected: virtual eResult init(); diff --git a/dataplane/dregress.cpp b/dataplane/dregress.cpp index ab93ae49..5cc838b7 100644 --- a/dataplane/dregress.cpp +++ b/dataplane/dregress.cpp @@ -377,48 +377,7 @@ void dregress_t::insert(rte_mbuf* mbuf) /// @todo: opt controlplane->slowWorker->preparePacket(mbuf); - - common::globalBase::tFlow flow = dregress.flow; - { - /// try send to logical port - - common::mac_address_t neighbor; - - { - std::lock_guard guard(neighbor_mutex); - - if (metadata->network_headerType == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) - { - if (neighbor_v4.size()) - { - const auto& [dregress_neighbor, dregress_flow] = *std::next(neighbor_v4.begin(), metadata->hash % neighbor_v4.size()); - - neighbor = dregress_neighbor; - flow = dregress_flow; - } - } - else - { - if (neighbor_v6.size()) - { - const auto& [dregress_neighbor, dregress_flow] = *std::next(neighbor_v6.begin(), metadata->hash % neighbor_v6.size()); - - neighbor = dregress_neighbor; - flow = dregress_flow; - } - } - } - - if (!neighbor.is_default()) - { - generic_rte_ether_hdr* ethernetHeader = rte_pktmbuf_mtod(mbuf, generic_rte_ether_hdr*); - memcpy(ethernetHeader->dst_addr.addr_bytes, - neighbor.data(), - 6); - } - } - - controlplane->sendPacketToSlowWorker(mbuf, flow); + controlplane->sendPacketToSlowWorker(mbuf, dregress.flow); } void dregress_t::handle() diff --git a/dataplane/dregress.h b/dataplane/dregress.h index 3b707b84..bb35ae4a 100644 --- a/dataplane/dregress.h +++ b/dataplane/dregress.h @@ -84,9 +84,5 @@ class dregress_t common::dregress::counters_t counters_v4; common::dregress::counters_t counters_v6; - std::mutex neighbor_mutex; - std::set> neighbor_v4; - std::set> neighbor_v6; - uint32_t gc_step; }; diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index 5cfdfe0e..fdce5332 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -206,7 +206,7 @@ eResult generation::update(const common::idp::updateGlobalBase::request& request } else if (type == common::idp::updateGlobalBase::requestType::dregress_neighbor_update) { - result = dregress_neighbor_update(std::get(data)); + /// @deprecated } else if (type == common::idp::updateGlobalBase::requestType::dregress_value_update) { @@ -2144,20 +2144,6 @@ eResult generation::dregress_local_prefix_update(const common::idp::updateGlobal return result; } -eResult generation::dregress_neighbor_update(const common::idp::updateGlobalBase::dregress_neighbor_update::request& request) -{ - eResult result = eResult::success; - - const auto& [neighbor_v4, neighbor_v6] = request; - - std::lock_guard guard(dataPlane->controlPlane->dregress.neighbor_mutex); - - dataPlane->controlPlane->dregress.neighbor_v4 = neighbor_v4; - dataPlane->controlPlane->dregress.neighbor_v6 = neighbor_v6; - - return result; -} - eResult generation::dregress_value_update(const common::idp::updateGlobalBase::dregress_value_update::request& request) { eResult result = eResult::success; diff --git a/dataplane/globalbase.h b/dataplane/globalbase.h index 689ad198..1a155ab7 100644 --- a/dataplane/globalbase.h +++ b/dataplane/globalbase.h @@ -172,7 +172,6 @@ class generation eResult dregress_prefix_remove(const common::idp::updateGlobalBase::dregress_prefix_remove::request& request); eResult dregress_prefix_clear(); eResult dregress_local_prefix_update(const common::idp::updateGlobalBase::dregress_local_prefix_update::request& request); - eResult dregress_neighbor_update(const common::idp::updateGlobalBase::dregress_neighbor_update::request& request); eResult dregress_value_update(const common::idp::updateGlobalBase::dregress_value_update::request& request); eResult fwstate_synchronization_update(const common::idp::updateGlobalBase::fwstate_synchronization_update::request& request); eResult tun64_update(const common::idp::updateGlobalBase::tun64_update::request& request); From fb423953736345949acee33563b07ae9b944434f Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 20:44:06 +0300 Subject: [PATCH 04/12] dataplane: move currentTime to cDataPlane::get_current_time() --- dataplane/controlplane.cpp | 16 ---------------- dataplane/controlplane.h | 2 -- dataplane/dataplane.cpp | 29 +++++++++++++++++++++++++++++ dataplane/dataplane.h | 9 +++++++++ dataplane/dregress.cpp | 20 ++++++++++++++++---- 5 files changed, 54 insertions(+), 22 deletions(-) diff --git a/dataplane/controlplane.cpp b/dataplane/controlplane.cpp index bc4d4ae2..e669a7ff 100644 --- a/dataplane/controlplane.cpp +++ b/dataplane/controlplane.cpp @@ -1665,12 +1665,8 @@ void cControlPlane::mainThread() { rte_mbuf* mbufs[CONFIG_YADECAP_MBUFS_BURST_SIZE]; - uint32_t prevTime = 0; - for (;;) { - currentTime = time(nullptr); - if (dataPlane->config.SWNormalPriorityRateLimitPerWorker || dataPlane->config.SWICMPOutRateLimit) { SWRateLimiterTimeTracker(); @@ -1678,18 +1674,6 @@ void cControlPlane::mainThread() slowWorker->slowWorkerBeforeHandlePackets(); - if (currentTime != prevTime) - { - for (const auto& iter : dataPlane->globalBaseAtomics) - { - auto* globalBaseAtomic = iter.second; - - globalBaseAtomic->currentTime = currentTime; - } - - prevTime = currentTime; - }; - /// dequeue packets from worker's rings for (unsigned nIter = 0; nIter < YANET_CONFIG_RING_PRIORITY_RATIO; nIter++) { diff --git a/dataplane/controlplane.h b/dataplane/controlplane.h index 9249a2e3..3c5b33b4 100644 --- a/dataplane/controlplane.h +++ b/dataplane/controlplane.h @@ -189,7 +189,5 @@ class cControlPlane ///< @todo: move to cDataPlane std::chrono::high_resolution_clock::time_point prevTimePointForSWRateLimiter; uint32_t icmpOutRemainder; - - uint32_t currentTime; uint32_t gc_step; }; diff --git a/dataplane/dataplane.cpp b/dataplane/dataplane.cpp index 7e26e382..52370c44 100644 --- a/dataplane/dataplane.cpp +++ b/dataplane/dataplane.cpp @@ -102,6 +102,8 @@ eResult cDataPlane::init(const std::string& binaryPath, { eResult result = eResult::success; + current_time = time(nullptr); + result = parseConfig(configFilePath); if (result != eResult::success) { @@ -1213,8 +1215,35 @@ int cDataPlane::lcoreThread(void* args) return 0; } +void cDataPlane::timestamp_thread() +{ + uint32_t prev_time = 0; + + for (;;) + { + current_time = time(nullptr); + + if (current_time != prev_time) + { + for (const auto& [socket_id, globalbase_atomic] : globalBaseAtomics) + { + (void)socket_id; + globalbase_atomic->currentTime = current_time; + } + + prev_time = current_time; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} + void cDataPlane::start() { + threads.emplace_back([this]() { + timestamp_thread(); + }); + report.run(); bus.run(); diff --git a/dataplane/dataplane.h b/dataplane/dataplane.h index 6c3b2912..f206e22a 100644 --- a/dataplane/dataplane.h +++ b/dataplane/dataplane.h @@ -131,6 +131,11 @@ class cDataPlane void switch_worker_base(); + inline uint32_t get_current_time() const + { + return current_time; + } + template type* hugepage_create_static(int socket_id, @@ -290,6 +295,7 @@ class cDataPlane common::idp::get_shm_info::response getShmInfo(); static int lcoreThread(void* args); + void timestamp_thread(); protected: friend class cWorker; @@ -355,4 +361,7 @@ class cDataPlane std::vector workers_vector; std::mutex switch_worker_base_mutex; + uint32_t current_time; + + std::vector threads; }; diff --git a/dataplane/dregress.cpp b/dataplane/dregress.cpp index 5cc838b7..70835f11 100644 --- a/dataplane/dregress.cpp +++ b/dataplane/dregress.cpp @@ -5,6 +5,7 @@ #include "checksum.h" #include "controlplane.h" +#include "dataplane.h" #include "dregress.h" #include "metadata.h" #include "worker.h" @@ -158,7 +159,18 @@ void dregress_t::insert(rte_mbuf* mbuf) flags |= YANET_DREGRESS_FLAG_NH_IS_IPV4; } - connections->insert(key, {loss_count, ack_count, labelled_nexthop, label, community, prefix_address, peer_as, origin_as, (uint16_t)controlplane->currentTime, flags, prefix_mask}); + connections->insert(key, + {loss_count, + ack_count, + labelled_nexthop, + label, + community, + prefix_address, + peer_as, + origin_as, + (uint16_t)dataplane->get_current_time(), + flags, + prefix_mask}); if (tcpHeader->tcp_flags & TCP_FIN_FLAG) { @@ -285,7 +297,7 @@ void dregress_t::insert(rte_mbuf* mbuf) labelled_nexthop = value->nexthop; labelled_label = value->label; - value->timestamp = (uint16_t)controlplane->currentTime; + value->timestamp = (uint16_t)dataplane->get_current_time(); if (tcpHeader->tcp_flags & (TCP_FIN_FLAG | TCP_RST_FLAG)) { @@ -391,7 +403,7 @@ void dregress_t::handle() { if (iter.value()->flags & YANET_DREGRESS_FLAG_FIN) { - if ((uint16_t)(controlplane->currentTime - iter.value()->timestamp) > 8) ///< @todo: tag:DREGRESS_CONFIG + if ((uint16_t)(dataplane->get_current_time() - iter.value()->timestamp) > 8) ///< @todo: tag:DREGRESS_CONFIG { iter.unsetValid(); @@ -400,7 +412,7 @@ void dregress_t::handle() } else { - if ((uint16_t)(controlplane->currentTime - iter.value()->timestamp) > 60) ///< @todo: tag:DREGRESS_CONFIG + if ((uint16_t)(dataplane->get_current_time() - iter.value()->timestamp) > 60) ///< @todo: tag:DREGRESS_CONFIG { iter.unsetValid(); From e25420e2fc52e92afd23bc5e259d4666acef03d7 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 20:45:09 +0300 Subject: [PATCH 05/12] neighbor: fix timestamp; add flag 'static' --- cli/neighbor.h | 3 +-- common/idp.h | 2 +- dataplane/neighbor.cpp | 15 ++++++++++++++- dataplane/neighbor.h | 6 ++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cli/neighbor.h b/cli/neighbor.h index 14f865ad..d343031a 100644 --- a/cli/neighbor.h +++ b/cli/neighbor.h @@ -1,6 +1,5 @@ #pragma once -#include "common/icontrolplane.h" #include "common/idataplane.h" #include "helper.h" @@ -13,7 +12,7 @@ void show() interface::dataPlane dataplane; const auto response = dataplane.neighbor_show(); - table_t table; + table_t table({.optional_null = "static"}); table.insert("route_name", "interface_name", "ip_address", diff --git a/common/idp.h b/common/idp.h index 1382bd5b..5731e797 100644 --- a/common/idp.h +++ b/common/idp.h @@ -927,7 +927,7 @@ using response = std::vector>; ///< last_update_timestamp + std::optional>>; ///< last_update_timestamp } namespace neighbor_insert diff --git a/dataplane/neighbor.cpp b/dataplane/neighbor.cpp index 6c88e690..4c7978c7 100644 --- a/dataplane/neighbor.cpp +++ b/dataplane/neighbor.cpp @@ -208,11 +208,17 @@ common::idp::neighbor_show::response module::neighbor_show() const const auto& [route_name, interface_name] = it->second; + std::optional last_update_timestamp; + if (!(value.flags & flag_is_static)) + { + last_update_timestamp = dataplane->get_current_time() - value.last_update_timestamp; + } + response.emplace_back(route_name, interface_name, common::ip_address_t(key.flags & flag_is_ipv6 ? 6 : 4, key.address.bytes), common::mac_address_t(value.ether_address.addr_bytes), - value.last_update_timestamp); + last_update_timestamp); } } } @@ -256,6 +262,9 @@ eResult module::neighbor_insert(const common::idp::neighbor_insert::request& req dataplane::neighbor::value value; memcpy(value.ether_address.addr_bytes, mac_address.data(), 6); + value.flags = 0; + value.flags |= flag_is_static; + value.last_update_timestamp = dataplane->get_current_time(); auto response = generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { eResult result = eResult::success; @@ -481,6 +490,8 @@ void module::netlink_thread() value value; memcpy(value.ether_address.addr_bytes, mac_address.data(), 6); + value.flags = 0; + value.last_update_timestamp = dataplane->get_current_time(); generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) @@ -542,6 +553,8 @@ void module::resolve(const dataplane::neighbor::key& key) value.ether_address.addr_bytes[1] = 66; } *((uint32_t*)&value.ether_address.addr_bytes[2]) = rte_hash_crc(key.address.bytes, 16, 0); + value.flags = 0; + value.last_update_timestamp = dataplane->get_current_time(); generation_hashtable.update([this, key, value](neighbor::generation_hashtable& hashtable) { for (auto& [socket_id, hashtable_updater] : hashtable.hashtable_updater) diff --git a/dataplane/neighbor.h b/dataplane/neighbor.h index 1c5483cd..e163862b 100644 --- a/dataplane/neighbor.h +++ b/dataplane/neighbor.h @@ -17,7 +17,8 @@ namespace dataplane::neighbor { -constexpr static uint16_t flag_is_ipv6 = 1; +constexpr static uint16_t flag_is_ipv6 = 1 << 0; +constexpr static uint16_t flag_is_static = 1 << 1; struct key { @@ -31,7 +32,8 @@ static_assert(CONFIG_YADECAP_INTERFACES_SIZE <= 0xFFFF, "invalid size"); struct value { rte_ether_addr ether_address; - uint16_t last_update_timestamp; + uint16_t flags; + uint32_t last_update_timestamp; }; // From efb73effbf7e5ae2335956e3a7c3335d93d15ee6 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Tue, 9 Jan 2024 20:45:49 +0300 Subject: [PATCH 06/12] autotest: clear dataplane's states before start autotest --- autotest/autotest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index aa809ded..21d317d6 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -1281,6 +1281,12 @@ void tAutotest::mainThread() fflushSharedMemory(); + /// clear dataplane states + { + dataPlane.balancer_state_clear(); + dataPlane.neighbor_clear(); + } + try { { @@ -1466,12 +1472,6 @@ void tAutotest::mainThread() std::abort(); } - /// clear dataplane states - { - dataPlane.balancer_state_clear(); - dataPlane.neighbor_clear(); - } - YANET_LOG_PRINT(ANSI_COLOR_GREEN "done '%s'\n\n" ANSI_COLOR_RESET, configFilePath.data()); fflush(stdout); fflush(stderr); From e320dd2e73c29d2b838c066200f8b363542e4461 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Thu, 11 Jan 2024 17:39:31 +0300 Subject: [PATCH 07/12] support directly connected routes. move forEachSocket() from cControlPlane to module generation. --- common/controlplaneconfig.h | 6 +- common/define.h | 2 + common/icp.h | 2 +- common/idp.h | 10 +- common/type.h | 12 ++ controlplane/configconverter.cpp | 6 +- controlplane/configparser.cpp | 2 +- controlplane/controlplane.h | 12 -- controlplane/route.cpp | 225 +++++++++++++++++++++---------- controlplane/route.h | 17 ++- dataplane/globalbase.cpp | 6 +- dataplane/type.h | 1 + dataplane/worker.cpp | 40 +++++- 13 files changed, 239 insertions(+), 102 deletions(-) diff --git a/common/controlplaneconfig.h b/common/controlplaneconfig.h index 3e526762..e7b505ad 100644 --- a/common/controlplaneconfig.h +++ b/common/controlplaneconfig.h @@ -102,7 +102,7 @@ class interface_t void pop(common::stream_in_t& stream) { stream.pop(interfaceId); - stream.pop(ipAddresses); + stream.pop(ip_prefixes); stream.pop(neighborIPv4Address); stream.pop(neighborIPv6Address); stream.pop(static_neighbor_mac_address_v4); @@ -116,7 +116,7 @@ class interface_t void push(common::stream_out_t& stream) const { stream.push(interfaceId); - stream.push(ipAddresses); + stream.push(ip_prefixes); stream.push(neighborIPv4Address); stream.push(neighborIPv6Address); stream.push(static_neighbor_mac_address_v4); @@ -130,7 +130,7 @@ class interface_t public: tInterfaceId interfaceId; - std::set ipAddresses; + std::set ip_prefixes; std::optional neighborIPv4Address; std::optional neighborIPv6Address; std::optional static_neighbor_mac_address_v4; ///< @todo: no directly connected (only v4 and v6 neighbor) diff --git a/common/define.h b/common/define.h index 52669396..85807681 100644 --- a/common/define.h +++ b/common/define.h @@ -104,6 +104,8 @@ extern LogPriority logPriority; #define YANET_NETWORK_FLAG_NOT_FIRST_FRAGMENT ((uint8_t)(1u << 1)) #define YANET_NETWORK_FLAG_HAS_EXTENSION ((uint8_t)(1u << 2)) +#define YANET_NEXTHOP_FLAG_DIRECTLY ((uint16_t)(1u << 0)) + /// @todo: move template diff --git a/common/icp.h b/common/icp.h index 5920ef18..a50f6cf8 100644 --- a/common/icp.h +++ b/common/icp.h @@ -395,7 +395,7 @@ namespace route_interface { using response = std::map, ///< interface_name - std::tuple, + std::tuple, std::optional, ///< neighbor std::optional, ///< neighbor std::optional, ///< neighbor_mac_address_v4 diff --git a/common/idp.h b/common/idp.h index 5731e797..e68f8bff 100644 --- a/common/idp.h +++ b/common/idp.h @@ -377,9 +377,10 @@ using request = lpm::request; namespace route_value_update { -using interface = std::vector, - ip_address_t>>; ///< neighbor_address +using interface = std::vector, ///< labels + ip_address_t, ///< neighbor_address + uint16_t>>; ///< nexthop_flags using request = std::tuple>>; ///< neighbor_address + ip_address_t, ///< neighbor_address + uint16_t>>>; ///< nexthop_flags using request = std::tuple(prefix).mask() == 32; + } + else + { + return std::get(prefix).mask() == 128; + } + } + ip_prefix_t get_default() const { if (is_ipv4()) diff --git a/controlplane/configconverter.cpp b/controlplane/configconverter.cpp index 81ccae70..4a129463 100644 --- a/controlplane/configconverter.cpp +++ b/controlplane/configconverter.cpp @@ -874,15 +874,15 @@ void config_converter_t::acl_rules_route_local(controlplane::base::acl_t& acl, { (void)interfaceName; - for (const auto& ipAddress : interface.ipAddresses) + for (const auto& ipAddress : interface.ip_prefixes) { if (ipAddress.is_ipv4()) { - rule_network_ipv4.destinationPrefixes.emplace(ipAddress.get_ipv4()); + rule_network_ipv4.destinationPrefixes.emplace(ipAddress.address()); } else { - rule_network_ipv6.destinationPrefixes.emplace(ipAddress.get_ipv6()); + rule_network_ipv6.destinationPrefixes.emplace(ipAddress.address()); } } } diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index fc73242c..bddf53e4 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -250,7 +250,7 @@ void config_parser_t::loadConfig_route(controlplane::base_t& baseNext, { for (const auto& ipAddressJson : interfaceJson["ipAddresses"]) { - interface.ipAddresses.emplace(ipAddressJson.get()); + interface.ip_prefixes.emplace(ipAddressJson.get()); } } diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index 393de929..06981cbe 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -100,18 +100,6 @@ class cControlPlane } } - void inline forEachSocket(const std::function& interfaces)>& function) const - { - generations.current_lock(); - std::map> socket_interfaces = generations.current().socket_interfaces; - generations.current_unlock(); - - for (const auto& [socket_id, interfaces] : socket_interfaces) - { - function(socket_id, interfaces); - } - } - protected: /** commands */ common::icp::getPhysicalPorts::response getPhysicalPorts() const; common::icp::getLogicalPorts::response getLogicalPorts() const; diff --git a/controlplane/route.cpp b/controlplane/route.cpp index 6fde5558..08849cfc 100644 --- a/controlplane/route.cpp +++ b/controlplane/route.cpp @@ -49,7 +49,7 @@ eResult route_t::init() return eResult::success; } -void route_t::prefix_update(const std::tuple& vrf_priority, const ip_prefix_t& prefix, const std::vector& pptns, const std::variant& value) +void route_t::prefix_update(const std::tuple& vrf_priority, const ip_prefix_t& prefix, const std::vector& pptns, const std::variant& value) { const auto& [vrf, priority] = vrf_priority; @@ -108,6 +108,10 @@ void route_t::prefix_update(const std::tuple& vrf_priorit destination_next = interface_destination_next.begin()->second; } } + else if (const auto directly_connected = std::get_if(&value)) + { + destination_next = *directly_connected; + } else if (const auto virtual_port_id = std::get_if(&value)) { destination_next = *virtual_port_id; @@ -546,9 +550,9 @@ common::icp::route_interface::response route_t::route_interface() const { for (const auto& [interface_name, interface] : route.interfaces) { - auto& [addresses, neighbor_v4, neighbor_v6, neighbor_mac_address_v4, neighbor_mac_address_v6, next_module] = response[{route_name, interface_name}]; + auto& [prefixes, neighbor_v4, neighbor_v6, neighbor_mac_address_v4, neighbor_mac_address_v6, next_module] = response[{route_name, interface_name}]; - addresses = interface.ipAddresses; + prefixes = interface.ip_prefixes; neighbor_v4 = interface.neighborIPv4Address; neighbor_v6 = interface.neighborIPv6Address; @@ -896,6 +900,49 @@ void route_t::reload(const controlplane::base_t& base_prev, std::tuple<>()); } } + + for (const auto& [config_module_name, config_module] : base_prev.routes) + { + (void)config_module_name; + + for (const auto& [interface_name, interface] : config_module.interfaces) + { + (void)interface_name; + + for (const auto& ip_prefix : interface.ip_prefixes) + { + if (!ip_prefix.is_host()) + { + prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + ip_prefix.applyMask(ip_prefix.mask()), + {}, + std::monostate()); + } + } + } + } + + for (const auto& [config_module_name, config_module] : base_next.routes) + { + (void)config_module_name; + + for (const auto& [interface_name, interface] : config_module.interfaces) + { + for (const auto& ip_prefix : interface.ip_prefixes) + { + if (!ip_prefix.is_host()) + { + route::directly_connected_destination_t directly_connected = {interface.interfaceId, + interface_name}; + + prefix_update({"default", YANET_RIB_PRIORITY_ROUTE_REPEAT}, + ip_prefix.applyMask(ip_prefix.mask()), + {}, + directly_connected); + } + } + } + } } #ifdef CONFIG_YADECAP_AUTOTEST @@ -1096,83 +1143,95 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, return; } - - for (const auto& destination_iter : std::get<0>(destination)) ///< interface + else if (const auto directly_connected = std::get_if(&destination)) { - const auto& [nexthop, labels] = destination_iter; + const auto& [interface_id, interface_name] = *directly_connected; - if (nexthop.is_default()) + request_interface.emplace_back(ipv4_address_t(), ///< default + interface_id, + interface_name, + std::vector(), + ipv4_address_t()); ///< default + } + else + { + for (const auto& destination_iter : std::get<0>(destination)) ///< interface { - controlPlane->forEachSocket([this, &value_id, &globalbase](const tSocketId& socket_id) { - globalbase.emplace_back(common::idp::updateGlobalBase::requestType::route_value_update, - common::idp::updateGlobalBase::route_value_update::request(value_id, - socket_id, - common::globalBase::eNexthopType::controlPlane, - {})); + const auto& [nexthop, labels] = destination_iter; - value_lookup[value_id][socket_id].emplace_back(ip_address_t(), - "linux", - std::vector()); - }); + if (nexthop.is_default()) + { + controlPlane->forEachSocket([this, &value_id, &globalbase](const tSocketId& socket_id) { + globalbase.emplace_back(common::idp::updateGlobalBase::requestType::route_value_update, + common::idp::updateGlobalBase::route_value_update::request(value_id, + socket_id, + common::globalBase::eNexthopType::controlPlane, + {})); + + value_lookup[value_id][socket_id].emplace_back(ip_address_t(), + "linux", + std::vector()); + }); - return; - } + return; + } - auto interface = generation.get_interface_by_neighbor(nexthop); - if (interface) - { - const auto& [interface_id, interface_name] = **interface; + auto interface = generation.get_interface_by_neighbor(nexthop); + if (interface) + { + const auto& [interface_id, interface_name] = **interface; - if (labels.size() > 2) + if (labels.size() > 2) + { + YANET_LOG_WARNING("wrong labels count '%lu'\n", + labels.size()); + continue; + } + + request_interface.emplace_back(nexthop, + interface_id, + interface_name, + labels, + nexthop); + + continue; + } + + if (labels.size() > 1) { YANET_LOG_WARNING("wrong labels count '%lu'\n", labels.size()); continue; } - request_interface.emplace_back(nexthop, - interface_id, - interface_name, - labels, - nexthop); - - continue; - } - - if (labels.size() > 1) - { - YANET_LOG_WARNING("wrong labels count '%lu'\n", - labels.size()); - continue; - } - - ip_prefix_t prefix_next; - if (nexthop.is_ipv4()) - { - prefix_next = {nexthop, 32}; - } - else - { - prefix_next = {nexthop, 128}; - } + ip_prefix_t prefix_next; + if (nexthop.is_ipv4()) + { + prefix_next = {nexthop, 32}; + } + else + { + prefix_next = {nexthop, 128}; + } - auto& [priority_current, update] = prefixes[vrf]; - auto& current = priority_current[priority]; - (void)update; + auto& [priority_current, update] = prefixes[vrf]; + auto& current = priority_current[priority]; + (void)update; - const auto value_id_label = current.get(prefix_next); - if (value_id_label) - { - value_compile_label(globalbase, - generation, - *value_id_label, - labels, - request_interface, - nexthop); - } - else - { - /// @todo: stats + const auto value_id_label = current.get(prefix_next); + if (value_id_label) + { + value_compile_label(globalbase, + generation, + *value_id_label, + labels, + request_interface, + nexthop); + } + else + { + /// @todo: stats + } } } @@ -1223,7 +1282,7 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, request_interface.resize(CONFIG_YADECAP_GB_ECMP_SIZE); } - controlPlane->forEachSocket([this, &value_id, &request_interface, &globalbase](const tSocketId& socket_id, const std::set& interfaces) { + generation.for_each_socket([this, &value_id, &request_interface, &globalbase](const tSocketId& socket_id, const std::set& interfaces) { common::idp::updateGlobalBase::route_value_update::interface update_interface; /// same numa @@ -1233,7 +1292,13 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, if (exist(interfaces, egress_interface_id)) { - update_interface.emplace_back(egress_interface_id, labels, neighbor_address); + uint16_t flags = 0; + if (neighbor_address.is_default()) + { + flags |= YANET_NEXTHOP_FLAG_DIRECTLY; + } + + update_interface.emplace_back(egress_interface_id, labels, neighbor_address, flags); value_lookup[value_id][socket_id].emplace_back(nexthop, egress_interface_name, @@ -1248,7 +1313,13 @@ void route_t::value_compile(common::idp::updateGlobalBase::request& globalbase, { const auto& [nexthop, egress_interface_id, egress_interface_name, labels, neighbor_address] = item; - update_interface.emplace_back(egress_interface_id, labels, neighbor_address); + uint16_t flags = 0; + if (neighbor_address.is_default()) + { + flags |= YANET_NEXTHOP_FLAG_DIRECTLY; + } + + update_interface.emplace_back(egress_interface_id, labels, neighbor_address, flags); value_lookup[value_id][socket_id].emplace_back(nexthop, egress_interface_name, @@ -1621,7 +1692,7 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa return; } - controlPlane->forEachSocket([this, &value_id, &request_interface, &fallback = fallback, &globalbase](const tSocketId& socket_id, const std::set& interfaces) { + generation.for_each_socket([this, &value_id, &request_interface, &fallback = fallback, &globalbase](const tSocketId& socket_id, const std::set& interfaces) { common::idp::updateGlobalBase::route_tunnel_value_update::interface update_interface; auto& [update_weight_start, update_weight_size, update_nexthops] = update_interface; @@ -1638,7 +1709,13 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa { const auto counter_ids = tunnel_counter.get_ids({fallback.is_ipv4(), peer_id, nexthop, origin_as}); - update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address); + uint16_t flags = 0; + if (neighbor_address.is_default()) + { + flags |= YANET_NEXTHOP_FLAG_DIRECTLY; + } + + update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address, flags); weights.emplace_back(weight); tunnel_value_lookup[value_id][socket_id].emplace_back(nexthop, @@ -1662,7 +1739,13 @@ void route_t::tunnel_value_compile(common::idp::updateGlobalBase::request& globa const auto counter_ids = tunnel_counter.get_ids({fallback.is_ipv4(), peer_id, nexthop, origin_as}); - update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address); + uint16_t flags = 0; + if (neighbor_address.is_default()) + { + flags |= YANET_NEXTHOP_FLAG_DIRECTLY; + } + + update_nexthops.emplace_back(egress_interface_id, counter_ids[0], label, nexthop, neighbor_address, flags); weights.emplace_back(weight); tunnel_value_lookup[value_id][socket_id].emplace_back(nexthop, diff --git a/controlplane/route.h b/controlplane/route.h index 09f653a3..0213c8b0 100644 --- a/controlplane/route.h +++ b/controlplane/route.h @@ -15,8 +15,12 @@ namespace route { +using directly_connected_destination_t = std::tuple; ///< interface_name + using destination_t = std::variant>>, + directly_connected_destination_t, ///< via interface uint32_t>; ///< virtual_port_id using value_key_t = std::tuple*> get_interface_by_neighbor(const ip_address_t& address) const @@ -143,10 +149,19 @@ class generation_t return &peers; } + void inline for_each_socket(const std::function& interfaces)>& function) const + { + for (const auto& [socket_id, interfaces] : socket_interfaces) + { + function(socket_id, interfaces); + } + } + public: std::map routes; std::map> interface_by_neighbors; std::map peers; ///< @todo: VRF + std::map> socket_interfaces; ///< @todo: per route }; class generation_neighbors_t @@ -182,7 +197,7 @@ class route_t : public module_t void reload(const controlplane::base_t& base_prev, const controlplane::base_t& base_next, common::idp::updateGlobalBase::request& globalbase) override; void reload_after() override; - void prefix_update(const std::tuple& vrf_priority, const ip_prefix_t& prefix, const std::vector& pptns, const std::variant& value); + void prefix_update(const std::tuple& vrf_priority, const ip_prefix_t& prefix, const std::vector& pptns, const std::variant& value); void tunnel_prefix_update(const std::tuple& vrf_priority_orig, const ip_prefix_t& prefix, const std::variant>& value); void prefix_flush(); diff --git a/dataplane/globalbase.cpp b/dataplane/globalbase.cpp index fdce5332..aa557e44 100644 --- a/dataplane/globalbase.cpp +++ b/dataplane/globalbase.cpp @@ -1600,7 +1600,7 @@ eResult generation::route_value_update(const common::idp::updateGlobalBase::rout ecmp_i < request_interface.size(); ecmp_i++) { - const auto& [interface_id, labels, neighbor_address] = request_interface[ecmp_i]; + const auto& [interface_id, labels, neighbor_address, nexthop_flags] = request_interface[ecmp_i]; if (interface_id >= CONFIG_YADECAP_INTERFACES_SIZE) { @@ -1609,6 +1609,7 @@ eResult generation::route_value_update(const common::idp::updateGlobalBase::rout } route_value.interface.nexthops[ecmp_i].interfaceId = interface_id; + route_value.interface.nexthops[ecmp_i].flags = nexthop_flags; route_value.interface.nexthops[ecmp_i].neighbor_address = ipv6_address_t::convert(neighbor_address); if (labels.size() == 0) @@ -1786,7 +1787,7 @@ eResult generation::route_tunnel_value_update(const common::idp::updateGlobalBas ecmp_i < nexthops.size(); ecmp_i++) { - const auto& [interface_id, counter_id, label, nexthop_address, neighbor_address] = nexthops[ecmp_i]; + const auto& [interface_id, counter_id, label, nexthop_address, neighbor_address, nexthop_flags] = nexthops[ecmp_i]; if (interface_id >= CONFIG_YADECAP_INTERFACES_SIZE) { @@ -1795,6 +1796,7 @@ eResult generation::route_tunnel_value_update(const common::idp::updateGlobalBas } route_tunnel_value.interface.nexthops[ecmp_i].interface_id = interface_id; + route_tunnel_value.interface.nexthops[ecmp_i].flags = nexthop_flags; route_tunnel_value.interface.nexthops[ecmp_i].counter_id = counter_id; route_tunnel_value.interface.nexthops[ecmp_i].label = label; route_tunnel_value.interface.nexthops[ecmp_i].nexthop_address = ipv6_address_t::convert(nexthop_address); diff --git a/dataplane/type.h b/dataplane/type.h index b6c21713..eb733efc 100644 --- a/dataplane/type.h +++ b/dataplane/type.h @@ -382,6 +382,7 @@ struct dregress_t struct nexthop ///< @todo { tInterfaceId interfaceId : 16; + uint16_t flags; ipv6_address_t neighbor_address; uint32_t labelExpTransport; ///< @todo: rename first uint32_t labelExpService; ///< @todo: rename second diff --git a/dataplane/worker.cpp b/dataplane/worker.cpp index 4679b4a6..c1d4ea77 100644 --- a/dataplane/worker.cpp +++ b/dataplane/worker.cpp @@ -2169,7 +2169,15 @@ inline void cWorker::route_handle4() memset(&key, 0, sizeof(key)); key.interface_id = nexthop.interfaceId; key.flags = 0; - key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + + if (nexthop.flags & YANET_NEXTHOP_FLAG_DIRECTLY) + { + key.address.mapped_ipv4_address.address = ipv4Header->dst_addr; + } + else + { + key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + } dataplane::neighbor::value const* value; base.neighbor_hashtable->lookup(key, value); @@ -2282,7 +2290,15 @@ inline void cWorker::route_handle6() key.interface_id = nexthop.interfaceId; key.flags = 0; key.flags |= dataplane::neighbor::flag_is_ipv6; - memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + + if (nexthop.flags & YANET_NEXTHOP_FLAG_DIRECTLY) + { + memcpy(key.address.bytes, ipv6Header->dst_addr, 16); + } + else + { + memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + } dataplane::neighbor::value const* value; base.neighbor_hashtable->lookup(key, value); @@ -2481,7 +2497,15 @@ inline void cWorker::route_tunnel_handle4() memset(&key, 0, sizeof(key)); key.interface_id = nexthop.interface_id; key.flags = 0; - key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + + if (nexthop.flags & YANET_NEXTHOP_FLAG_DIRECTLY) + { + key.address.mapped_ipv4_address.address = ipv4Header->dst_addr; + } + else + { + key.address.mapped_ipv4_address.address = nexthop.neighbor_address.mapped_ipv4_address.address; + } dataplane::neighbor::value const* value; base.neighbor_hashtable->lookup(key, value); @@ -2600,7 +2624,15 @@ inline void cWorker::route_tunnel_handle6() key.interface_id = nexthop.interface_id; key.flags = 0; key.flags |= dataplane::neighbor::flag_is_ipv6; - memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + + if (nexthop.flags & YANET_NEXTHOP_FLAG_DIRECTLY) + { + memcpy(key.address.bytes, ipv6Header->dst_addr, 16); + } + else + { + memcpy(key.address.bytes, nexthop.neighbor_address.bytes, 16); + } dataplane::neighbor::value const* value; base.neighbor_hashtable->lookup(key, value); From 0360ce721ffec79aef9ed6afef55d7edd427d89c Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Fri, 12 Jan 2024 11:12:29 +0300 Subject: [PATCH 08/12] cli: add 'neighbor flush' command --- cli/main.cpp | 1 + cli/neighbor.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/cli/main.cpp b/cli/main.cpp index 8d024253..7e41f0a3 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -81,6 +81,7 @@ std::vector Date: Fri, 12 Jan 2024 11:13:12 +0300 Subject: [PATCH 09/12] add autotest for check directly connected routes --- .../001-expect.pcap | Bin 0 -> 272 bytes .../001-send.pcap | Bin 0 -> 396 bytes .../002-expect.pcap | Bin 0 -> 352 bytes .../002-send.pcap | Bin 0 -> 516 bytes .../003-expect.pcap | Bin 0 -> 272 bytes .../003-send.pcap | Bin 0 -> 396 bytes .../004-expect.pcap | Bin 0 -> 352 bytes .../004-send.pcap | Bin 0 -> 516 bytes .../autotest.yaml | 27 ++++++ .../controlplane.conf | 43 +++++++++ .../071_route_directly_connected/gen.py | 86 ++++++++++++++++++ 11 files changed, 156 insertions(+) create mode 100644 autotest/units/001_one_port/071_route_directly_connected/001-expect.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/001-send.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/002-expect.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/002-send.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/003-expect.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/003-send.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/004-expect.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/004-send.pcap create mode 100644 autotest/units/001_one_port/071_route_directly_connected/autotest.yaml create mode 100644 autotest/units/001_one_port/071_route_directly_connected/controlplane.conf create mode 100755 autotest/units/001_one_port/071_route_directly_connected/gen.py diff --git a/autotest/units/001_one_port/071_route_directly_connected/001-expect.pcap b/autotest/units/001_one_port/071_route_directly_connected/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..ba0f9e8d4d3646366e21bd09040f87ce40f335c7 GIT binary patch literal 272 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$L!0=AMg$c+J6clV^U`XL$aAjbS0V%Z?+`@hj m2)MWym>5ifki&d6%m5VKzp(4x%n#N53!>X>GgjSnvKs)b!7V5N literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/001-send.pcap b/autotest/units/001_one_port/071_route_directly_connected/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..f6614385942438de9dd25dee76fe2a55252030e8 GIT binary patch literal 396 zcmca|c+)~A1{MYw`2U}Qff2?5(t1z~qyz;885r)ZWngGzU`XL$aAjbS0V#D5+{}It z2)MWym>5ifki&d6%m89^Z<+Px# literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/002-expect.pcap b/autotest/units/001_one_port/071_route_directly_connected/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..b1918701cff1c0775eb252e7b2e4cb67f0693476 GIT binary patch literal 352 zcmca|c+)~A1{MYw`2U}Qff2?5(oRs!!0=8WjS0vR6clV^U`T1Zn*ii6a0uEfDS;R; nproXLqMw0@!4wENX6eCHpqTgzC`zh{zaS>gG{b7*Aaf%CyqP5C literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/002-send.pcap b/autotest/units/001_one_port/071_route_directly_connected/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..5b47b6247ddf80356a53e7e5ea9b6b404bc327f8 GIT binary patch literal 516 zcmca|c+)~A1{MYw`2U}Qff2?5(oRqeqyz;885r)ZWngGzU`T1Zn*bDI;1G0BQUWnx zKuJjfMLz=*gDDVl%+iCYpxDHGh>0@~Qq9C)P!r9tn5YEuAJo?;sN!q#OvLAF@=S#L F8UPinHK70i literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/003-expect.pcap b/autotest/units/001_one_port/071_route_directly_connected/003-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..aed8593e88f578f3a8a0ee4394decde97b564113 GIT binary patch literal 272 zcmca|c+)~A1{MYw`2U}Qff2?5(t1$L!0=ANg$c+}Qc`MUU^v0S;L5-t15#=)xcTor lAm9>VU}7)@LJsqVFauC@|H7f06{`CeM7P;Wth(uBHvj;>F`57X literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/003-send.pcap b/autotest/units/001_one_port/071_route_directly_connected/003-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..3074e8af564aff62acb9af0b23883abf9bfa651e GIT binary patch literal 396 zcmca|c+)~A1{MYw`2U}Qff2?5(t1z~qyz;885r)ZWngGzU`XL$aAjbS0V#D5-1PSz z5O9ewFfo_{A&2=wm;prTo&eRI57li#l5SS0?q3kyW-GDiR#H-eyZi*nF2}8#7?5ifkYlDEOa#TmUqDe(P5cEhafTUI69<_a0g4MJf&c&j literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/004-send.pcap b/autotest/units/001_one_port/071_route_directly_connected/004-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..615b85dfb9a00112094862cb95a9dfbb25958e0c GIT binary patch literal 516 zcmca|c+)~A1{MYw`2U}Qff2?5(oRqeqyz;885r)ZWngGzU`T1Zn*bDI;1G0BQUWnx zKuJk~feFR|(M$}cK*%vu4<<;liTMx{XB?!OiNByGnqe_f3FJShuTN0L*W{Uq&)4Lc H2=_Gr79=&H literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/071_route_directly_connected/autotest.yaml b/autotest/units/001_one_port/071_route_directly_connected/autotest.yaml new file mode 100644 index 00000000..94de4271 --- /dev/null +++ b/autotest/units/001_one_port/071_route_directly_connected/autotest.yaml @@ -0,0 +1,27 @@ +steps: +- cli: + - neighbor insert route0 kni0.100 10.10.0.2 00:00:ee:10:44:02 + - neighbor insert route0 kni0.100 10.10.0.250 00:00:ee:10:44:fa + - neighbor insert route0 kni0.100 2000:100::2 00:00:ee:10:66:02 + - neighbor insert route0 kni0.100 2000:100::fa 00:00:ee:10:66:fa + - neighbor insert route0 kni0.200 10.20.0.2 00:00:ee:20:44:02 + - neighbor insert route0 kni0.200 10.20.0.250 00:00:ee:20:44:fa + - neighbor insert route0 kni0.200 2000:200::2 00:00:ee:20:66:02 + - neighbor insert route0 kni0.200 2000:200::fa 00:00:ee:20:66:fa + - neighbor flush +- 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 +- sendPackets: + - port: kni0 + send: 004-send.pcap + expect: 004-expect.pcap diff --git a/autotest/units/001_one_port/071_route_directly_connected/controlplane.conf b/autotest/units/001_one_port/071_route_directly_connected/controlplane.conf new file mode 100644 index 00000000..2f8ead3d --- /dev/null +++ b/autotest/units/001_one_port/071_route_directly_connected/controlplane.conf @@ -0,0 +1,43 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:00:00:11:11:11", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:00:00:22:22:22", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "route0" + ] + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "ipAddresses": [ + "10.10.0.1/24", + "2000:100::1/96" + ], + "nextModule": "lp0.100" + }, + "kni0.200": { + "ipAddresses": [ + "10.20.0.1/24", + "2000:200::1/96" + ], + "nextModule": "lp0.200" + } + } + } + } +} diff --git a/autotest/units/001_one_port/071_route_directly_connected/gen.py b/autotest/units/001_one_port/071_route_directly_connected/gen.py new file mode 100755 index 00000000..dad6d661 --- /dev/null +++ b/autotest/units/001_one_port/071_route_directly_connected/gen.py @@ -0,0 +1,86 @@ +#!/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) + + +# 10.10.0.0/24 -> kni0.100 +write_pcap("001-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.10.0.2", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.10.0.111", src="222.222.222.222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.10.0.250", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.10.0.2", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.10.0.111", src="222.222.222.222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.10.0.250", src="222.222.222.222")/UDP()) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:EE:10:44:02", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="10.10.0.2", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:10:44:FA", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="10.10.0.250", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:10:44:02", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="10.10.0.2", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:10:44:FA", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="10.10.0.250", src="222.222.222.222", ttl=63)/UDP()) + + +# 2000:100::/96 -> kni0.100 +write_pcap("002-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:100::2", src="2222::2222")/UDP(), + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:100::6F", src="2222::2222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:100::FA", src="2222::2222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:100::2", src="2222::2222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:100::6F", src="2222::2222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:100::FA", src="2222::2222")/UDP()) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:EE:10:66:02", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2000:100::2", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:10:66:FA", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2000:100::FA", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:10:66:02", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2000:100::2", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:10:66:FA", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IPv6(dst="2000:100::FA", src="2222::2222", hlim=63)/UDP()) + + +# 10.20.0.0/24 -> kni0.200 +write_pcap("003-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.20.0.2", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.20.0.111", src="222.222.222.222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="10.20.0.250", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.20.0.2", src="222.222.222.222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.20.0.111", src="222.222.222.222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IP(dst="10.20.0.250", src="222.222.222.222")/UDP()) + +write_pcap("003-expect.pcap", + Ether(dst="00:00:EE:20:44:02", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IP(dst="10.20.0.2", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:20:44:FA", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IP(dst="10.20.0.250", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:20:44:02", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IP(dst="10.20.0.2", src="222.222.222.222", ttl=63)/UDP(), + Ether(dst="00:00:EE:20:44:FA", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IP(dst="10.20.0.250", src="222.222.222.222", ttl=63)/UDP()) + + +# 2000:200::/96 -> kni0.200 +write_pcap("004-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:200::2", src="2222::2222")/UDP(), + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:200::6F", src="2222::2222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IPv6(dst="2000:200::FA", src="2222::2222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:200::2", src="2222::2222")/UDP(), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:200::6F", src="2222::2222")/UDP(), # neighbor mac invalid + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:200::FA", src="2222::2222")/UDP()) + +write_pcap("004-expect.pcap", + Ether(dst="00:00:EE:20:66:02", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:200::2", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:20:66:FA", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:200::FA", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:20:66:02", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:200::2", src="2222::2222", hlim=63)/UDP(), + Ether(dst="00:00:EE:20:66:FA", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:200::FA", src="2222::2222", hlim=63)/UDP()) From 76baf5a6facb06e8dccf908abb3880825669ea21 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Mon, 15 Jan 2024 10:33:19 +0300 Subject: [PATCH 10/12] add routes from controlplane config section 'rib'. add autotest with config routes. --- autotest/autotest.cpp | 3 +- .../072_rib_config/001-expect.pcap | Bin 0 -> 172 bytes .../001_one_port/072_rib_config/001-send.pcap | Bin 0 -> 172 bytes .../072_rib_config/002-expect.pcap | Bin 0 -> 212 bytes .../001_one_port/072_rib_config/002-send.pcap | Bin 0 -> 212 bytes .../001_one_port/072_rib_config/autotest.yaml | 9 ++++ .../072_rib_config/controlplane.conf | 51 ++++++++++++++++++ .../units/001_one_port/072_rib_config/gen.py | 41 ++++++++++++++ controlplane/base.h | 13 +++++ controlplane/configparser.cpp | 25 +++++++++ controlplane/configparser.h | 1 + controlplane/rib.cpp | 44 +++++++++++++++ controlplane/rib.h | 1 + 13 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 autotest/units/001_one_port/072_rib_config/001-expect.pcap create mode 100644 autotest/units/001_one_port/072_rib_config/001-send.pcap create mode 100644 autotest/units/001_one_port/072_rib_config/002-expect.pcap create mode 100644 autotest/units/001_one_port/072_rib_config/002-send.pcap create mode 100644 autotest/units/001_one_port/072_rib_config/autotest.yaml create mode 100644 autotest/units/001_one_port/072_rib_config/controlplane.conf create mode 100755 autotest/units/001_one_port/072_rib_config/gen.py diff --git a/autotest/autotest.cpp b/autotest/autotest.cpp index 21d317d6..5f0c4b17 100644 --- a/autotest/autotest.cpp +++ b/autotest/autotest.cpp @@ -1295,7 +1295,6 @@ void tAutotest::mainThread() common::icp::loadConfig::request request = prepareLoadConfig(configFilePath, "controlplane.conf"); controlPlane.rib_update({common::icp::rib_update::clear("autotest", std::nullopt)}); - controlPlane.rib_flush(); const auto result = controlPlane.loadConfig(request); if (result != eResult::success) @@ -1304,6 +1303,8 @@ void tAutotest::mainThread() throw ""; } + controlPlane.rib_flush(); + this->request.swap(request); } diff --git a/autotest/units/001_one_port/072_rib_config/001-expect.pcap b/autotest/units/001_one_port/072_rib_config/001-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..1d467429bdf60479366e23d7f61576003fbaf92d GIT binary patch literal 172 zcmca|c+)~A1{MYw`2U}Qff2?5(pFH+!0=AM#RbR_6clV^U`XL$aAjc704cR+%RJ5n p)WiY=3;`T)y#Y)L45eLgE>R|l7K2QRhya-+x(22fWRft@BmfWo6A1tS literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/072_rib_config/001-send.pcap b/autotest/units/001_one_port/072_rib_config/001-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..e6dac848f411eb3ed815a548088263473ef49fae GIT binary patch literal 172 zcmca|c+)~A1{MYw`2U}Qff2?5(pFFmqyz;885r)ZWngGzU`XL$aAjc704a4~%Q(&j p)WiY=3;`T)y#Y)L45eLgE>R|l6oX8Phya-+x(22fWRft@Bme~R6B7Uc literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/072_rib_config/002-expect.pcap b/autotest/units/001_one_port/072_rib_config/002-expect.pcap new file mode 100644 index 0000000000000000000000000000000000000000..a389dba3cbec5d7b1b58f81f212a32905c41c66f GIT binary patch literal 212 zcmca|c+)~A1{MYw`2U}Qff2?5(tc3P!0=8XEe*&~Qc`MUU^vlsHv!0D5Mi@VK>{p5 vpun*D?7x2-HXJzcZy6WRFb)QW0FY7;2w+lRc;E$LgGkCu7r|osHK6GLyJ0UN literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/072_rib_config/002-send.pcap b/autotest/units/001_one_port/072_rib_config/002-send.pcap new file mode 100644 index 0000000000000000000000000000000000000000..210b7c92567d8c1a6bdb8b6259690ebdf096da50 GIT binary patch literal 212 zcmca|c+)~A1{MYw`2U}Qff2?5(tc13q?DAD7#QxYWngGzU^vlsHvuTbAj0O5f&^HA vK!IWP*?<2wY&dY>-!d+sVH^w$0U)Iy5Wu9s@W2bg29cDRE`r7MYe3ThWo0ge literal 0 HcmV?d00001 diff --git a/autotest/units/001_one_port/072_rib_config/autotest.yaml b/autotest/units/001_one_port/072_rib_config/autotest.yaml new file mode 100644 index 00000000..397f75cc --- /dev/null +++ b/autotest/units/001_one_port/072_rib_config/autotest.yaml @@ -0,0 +1,9 @@ +steps: +- sendPackets: + - port: kni0 + send: 001-send.pcap + expect: 001-expect.pcap +- sendPackets: + - port: kni0 + send: 002-send.pcap + expect: 002-expect.pcap diff --git a/autotest/units/001_one_port/072_rib_config/controlplane.conf b/autotest/units/001_one_port/072_rib_config/controlplane.conf new file mode 100644 index 00000000..91667458 --- /dev/null +++ b/autotest/units/001_one_port/072_rib_config/controlplane.conf @@ -0,0 +1,51 @@ +{ + "modules": { + "lp0.100": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "100", + "macAddress": "00:00:00:11:11:11", + "nextModule": "acl0" + }, + "lp0.200": { + "type": "logicalPort", + "physicalPort": "kni0", + "vlanId": "200", + "macAddress": "00:00:00:22:22:22", + "nextModule": "acl0" + }, + "acl0": { + "type": "acl", + "nextModules": [ + "route0" + ] + }, + "route0": { + "type": "route", + "interfaces": { + "kni0.100": { + "neighborIPv4Address": "200.0.0.1", + "neighborMacAddress": "00:00:EE:10:44:44", + "nextModule": "lp0.100" + }, + "kni0.200": { + "neighborIPv6Address": "fe80::1", + "neighborMacAddress": "00:00:EE:20:66:66", + "nextModule": "lp0.200" + } + } + } + }, + "rib": { + "default": [ + { + "prefix": "0.0.0.0/0", + "nexthop": "200.0.0.1" + }, + { + "prefix": "::/0", + "nexthop": "fe80::1" + } + ] + } +} diff --git a/autotest/units/001_one_port/072_rib_config/gen.py b/autotest/units/001_one_port/072_rib_config/gen.py new file mode 100755 index 00000000..cd68e08e --- /dev/null +++ b/autotest/units/001_one_port/072_rib_config/gen.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from scapy.all import * + + +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) + + +# IPv4: -> 200.0.0.1 +write_pcap("001-send.pcap", + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="10.0.0.1", ttl=64)/TCP(dport=2048, sport=80), + Ether(dst="00:00:00:11:11:11", src="00:00:DE:AD:00:00")/Dot1Q(vlan=100)/IP(dst="88.88.4.4", src="10.0.0.1", ttl=64)/TCP(dport=5548, sport=80)) + +write_pcap("001-expect.pcap", + Ether(dst="00:00:EE:10:44:44", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="4.4.4.4", src="10.0.0.1", ttl=63)/TCP(dport=2048, sport=80), + Ether(dst="00:00:EE:10:44:44", src="00:00:00:11:11:11")/Dot1Q(vlan=100)/IP(dst="88.88.4.4", src="10.0.0.1", ttl=63)/TCP(dport=5548, sport=80)) + + +# IPv6: -> fe80::1 +write_pcap("002-send.pcap", + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:10.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=64)/TCP(dport=80, sport=2048), + Ether(dst="00:00:00:22:22:22", src="00:00:DE:AD:00:00")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:20.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=64)/TCP(dport=80, sport=2048)) + +write_pcap("002-expect.pcap", + Ether(dst="00:00:EE:20:66:66", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:10.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=63)/TCP(dport=80, sport=2048), + Ether(dst="00:00:EE:20:66:66", src="00:00:00:22:22:22")/Dot1Q(vlan=200)/IPv6(dst="2000:abcd:fefe:b0b0:c0c0:fea6:20.0.0.1", src="6464:6464:6464:6464:6464:6464:0404:0404", hlim=63)/TCP(dport=80, sport=2048)) diff --git a/controlplane/base.h b/controlplane/base.h index 5cebc58b..5103415c 100644 --- a/controlplane/base.h +++ b/controlplane/base.h @@ -418,6 +418,15 @@ class acl_t // +class base_rib +{ +public: + ip_prefix_t prefix; + ip_address_t nexthop; +}; + +// + class base_t { public: @@ -471,6 +480,10 @@ class base_t vrf_fqdns; uint32_t nat64stateful_pool_size; + + std::map> + rib; }; // diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index bddf53e4..c897aa55 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -125,6 +125,11 @@ controlplane::base_t config_parser_t::loadConfig(const std::string& rootFilePath loadConfig_fqdns(baseNext, path_json, rootFilePath, jsons); } } + + if (exist(rootJson, "rib")) + { + loadConfig_rib(baseNext, rootJson["rib"]); + } } catch (const error_result_t& err) { @@ -1876,3 +1881,23 @@ void config_parser_t::loadConfig_fqdns(controlplane::base_t& baseNext, } } } + +void config_parser_t::loadConfig_rib(controlplane::base_t& baseNext, + const nlohmann::json& json) +{ + for (const auto& json_iter : json.items()) + { + const auto& name = json_iter.key(); + const auto& rib_items = json_iter.value(); + + auto& vrf = baseNext.rib[name]; + for (const auto& json_rib_item : rib_items) + { + controlplane::base_rib base_rib; + base_rib.prefix = json_rib_item["prefix"].get(); + base_rib.nexthop = json_rib_item["nexthop"].get(); + + vrf.emplace_back(std::move(base_rib)); + } + } +} diff --git a/controlplane/configparser.h b/controlplane/configparser.h index df18858b..e041fb10 100644 --- a/controlplane/configparser.h +++ b/controlplane/configparser.h @@ -38,6 +38,7 @@ class config_parser_t void loadConfig_variables(controlplane::base_t& baseNext, const nlohmann::json& json); void loadConfig_fqdns(controlplane::base_t& baseNext, const nlohmann::json& json, const std::string& rootFilePath, const std::map& jsons); + void loadConfig_rib(controlplane::base_t& baseNext, const nlohmann::json& json); private: common::idp::getConfig::response dataPlaneConfig; diff --git a/controlplane/rib.cpp b/controlplane/rib.cpp index 478b0110..90700c53 100644 --- a/controlplane/rib.cpp +++ b/controlplane/rib.cpp @@ -73,6 +73,50 @@ eResult rib_t::init() return eResult::success; } +void rib_t::reload(const controlplane::base_t& base_prev, + const controlplane::base_t& base_next, + common::idp::updateGlobalBase::request& globalbase) +{ + (void)base_prev; + (void)globalbase; + + common::icp::rib_update::request request; + + { + common::icp::rib_update::clear clear{"config", std::nullopt}; + request.emplace_back(std::move(clear)); + } + + for (const auto& [vrf_name, rib_items] : base_next.rib) + { + common::icp::rib_update::insert request_insert = {"config", + vrf_name, + YANET_RIB_PRIORITY_DEFAULT, + {}}; + + for (const auto& rib_item : rib_items) + { + auto& prefixes = std::get<3>(request_insert)[{ip_address_t("::"), "", 0, {}, {}, {}, 0}] + [""] + [rib_item.nexthop]; + prefixes.emplace_back(rib_item.prefix, "", std::vector()); + } + + request.emplace_back(std::move(request_insert)); + } + + { + common::icp::rib_update::eor request_eor = {"config", + "default", + YANET_RIB_PRIORITY_DEFAULT, + ip_address_t("::"), + ""}; + request.emplace_back(std::move(request_eor)); + } + + rib_update(request); +} + void rib_t::rib_update(const common::icp::rib_update::request& request) { std::lock_guard rib_update_guard(rib_update_mutex); diff --git a/controlplane/rib.h b/controlplane/rib.h index a2362f0e..c436dc3b 100644 --- a/controlplane/rib.h +++ b/controlplane/rib.h @@ -42,6 +42,7 @@ class rib_t : public cModule ~rib_t() override; eResult init() override; + void reload(const controlplane::base_t& base_prev, const controlplane::base_t& base_next, common::idp::updateGlobalBase::request& globalbase) override; void rib_update(const common::icp::rib_update::request& request); void rib_flush(bool force_flush = false); From 65da4b0487a41780abe91c766d1146066270b8d3 Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Fri, 29 Dec 2023 13:59:08 +0300 Subject: [PATCH 11/12] fix use "route:local" in acl's nextModules --- controlplane/configconverter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/controlplane/configconverter.cpp b/controlplane/configconverter.cpp index 4a129463..e3a4e974 100644 --- a/controlplane/configconverter.cpp +++ b/controlplane/configconverter.cpp @@ -758,15 +758,15 @@ void config_converter_t::processAcl() { if (entry == "local") { - acl_rules_route_local(acl, nextModule); + acl_rules_route_local(acl, nextModuleName); } else if (entry == "forward") { - acl_rules_route_forward(acl, nextModule); + acl_rules_route_forward(acl, nextModuleName); } else if (entry == "tunnel") { - acl_rules_route_forward(acl, nextModule); + acl_rules_route_forward(acl, nextModuleName); } else { From 090591afee143829ee301b93c037400e7feb88df Mon Sep 17 00:00:00 2001 From: Timur Aitov Date: Mon, 15 Jan 2024 11:15:50 +0300 Subject: [PATCH 12/12] TEST --- .github/workflows/docker-image.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index dac68a54..a2695f81 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -30,6 +30,31 @@ jobs: # todo + build-debian-packet: + needs: build-image-builder + runs-on: ubuntu-latest + container: + image: yanetplatform/builder + steps: + - uses: actions/checkout@v3 + - run: | + meson setup --prefix=/target -Dstrip=true build + meson compile -C build + - run: meson install -C build + - uses: jiro4989/build-deb-action@v3 + with: + package: yanet + package_root: /target + maintainer: taitov + version: 61.0 + arch: amd64 + desc: YANET is an open-source extensible framework for software forwarding traffic based on DPDK + - uses: actions/upload-artifact@v4 + with: + name: build-debian-packet + path: | + ./*.deb + build-unittest: needs: build-image-builder runs-on: ubuntu-latest