From b89113b81bffa7e3fc4fe0d5baab3a6b4aa77d8b Mon Sep 17 00:00:00 2001 From: Pavel Odintsov Date: Sat, 5 Aug 2023 14:06:42 +0100 Subject: [PATCH] Extracted GoBGP client into separate module --- src/CMakeLists.txt | 15 ++- src/actions/gobgp_action.cpp | 8 +- src/gobgp_client/gobgp_client.cpp | 204 ++++++++++++++++++++++++++++++ src/gobgp_client/gobgp_client.hpp | 160 +---------------------- 4 files changed, 225 insertions(+), 162 deletions(-) create mode 100644 src/gobgp_client/gobgp_client.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 64deaee..cfc4be0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -521,6 +521,10 @@ endif() if (ENABLE_GOBGP_SUPPORT) add_definitions(-DENABLE_GOBGP) + + # GoBGP client library + add_library(gobgp_client STATIC gobgp_client/gobgp_client.cpp) + add_library(gobgp_action STATIC actions/gobgp_action.cpp) # We use find_package for Windows as our approach for *nix platforms leads to bunch of linking errors @@ -542,7 +546,9 @@ if (ENABLE_GOBGP_SUPPORT) message(FATAL_ERROR "NOT Found gRPC module") endif() - target_link_libraries(gobgp_action gRPC::grpc gRPC::grpc++) + target_link_libraries(gobgp_client gRPC::grpc gRPC::grpc++) + + target_link_libraries(gobgp_action gRPC::grpc gRPC::grpc++ gobgp_client) else() @@ -556,7 +562,12 @@ if (ENABLE_GOBGP_SUPPORT) target_link_libraries(gobgp_action ${GRPC_LIBRARY_GRPC_PATH}) target_link_libraries(gobgp_action ${GRPC_LIBRARY_GPR_PATH}) target_link_libraries(gobgp_action ${GRPC_LIBRARY_GRPC_CPP_PATH}) - + target_link_libraries(gobgp_action gobgp_client) + + target_link_libraries(gobgp_client ${GRPC_LIBRARY_GRPC_PATH}) + target_link_libraries(gobgp_client ${GRPC_LIBRARY_GPR_PATH}) + target_link_libraries(gobgp_client ${GRPC_LIBRARY_GRPC_CPP_PATH}) + message(STATUS "Found gRPC library: ${GRPC_LIBRARY_GRPC_PATH} ${GRPC_LIBRARY_GPR_PATH} ${GRPC_LIBRARY_GRPC_CPP_PATH}") else() message(FATAL_ERROR "Could not find gRPC library") diff --git a/src/actions/gobgp_action.cpp b/src/actions/gobgp_action.cpp index 76d7226..3b34b12 100644 --- a/src/actions/gobgp_action.cpp +++ b/src/actions/gobgp_action.cpp @@ -1,16 +1,10 @@ #include "gobgp_action.hpp" #include "../fastnetmon_actions.hpp" -#include #include #include -#include -unsigned int gobgp_client_connection_timeout = 5; - -using grpc::Channel; -using grpc::ClientContext; -using grpc::Status; +#include "../bgp_protocol.hpp" #include "../gobgp_client/gobgp_client.hpp" diff --git a/src/gobgp_client/gobgp_client.cpp b/src/gobgp_client/gobgp_client.cpp new file mode 100644 index 0000000..3400eb1 --- /dev/null +++ b/src/gobgp_client/gobgp_client.cpp @@ -0,0 +1,204 @@ +#include "gobgp_client.hpp" + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif // __GNUC__ + + + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; + +// +// MinGW has quite weird definitions which clash with field names in gRPC bindinds +// We need to apply some trickery to avoid complilation errors: +// https://github.com/pavel-odintsov/fastnetmon/issues/977 +// + +#ifdef _WIN32 + +// Save previous values of these defines +#pragma push_macro("interface") +#pragma push_macro("IN") +#pragma push_macro("OUT") + +#undef interface +#undef IN +#undef OUT + +#endif + + +#include "../gobgp_client/attribute.pb.h" + +#ifdef _WIN32 + +// Restore original values of these defines +#pragma pop_macro("interface") +#pragma pop_macro("IN") +#pragma pop_macro("OUT") + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // __GNUC__ + +using apipb::GobgpApi; + +#include "../all_logcpp_libraries.hpp" + +#include "../fast_library.hpp" + +unsigned int gobgp_client_connection_timeout = 5; + +extern log4cpp::Category& logger; + +GrpcClient::GrpcClient(std::shared_ptr channel) : stub_(GobgpApi::NewStub(channel)) { + +} + +bool GrpcClient::AnnounceUnicastPrefixIPv4(std::string announced_address, + std::string announced_prefix_nexthop, + bool is_withdrawal, + unsigned int cidr_mask, + uint32_t community_as_32bit_int) { + grpc::ClientContext context; + + // Set timeout for API + std::chrono::system_clock::time_point deadline = + std::chrono::system_clock::now() + std::chrono::seconds(gobgp_client_connection_timeout); + context.set_deadline(deadline); + + auto gobgp_ipv4_unicast_route_family = new apipb::Family; + gobgp_ipv4_unicast_route_family->set_afi(apipb::Family::AFI_IP); + gobgp_ipv4_unicast_route_family->set_safi(apipb::Family::SAFI_UNICAST); + + apipb::AddPathRequest request; + request.set_table_type(apipb::TableType::GLOBAL); + + apipb::Path* current_path = new apipb::Path; + + current_path->set_allocated_family(gobgp_ipv4_unicast_route_family); + + if (is_withdrawal) { + current_path->set_is_withdraw(true); + } + + // Configure required announce + google::protobuf::Any* current_nlri = new google::protobuf::Any; + apipb::IPAddressPrefix current_ipaddrprefix; + current_ipaddrprefix.set_prefix(announced_address); + current_ipaddrprefix.set_prefix_len(cidr_mask); + + current_nlri->PackFrom(current_ipaddrprefix); + current_path->set_allocated_nlri(current_nlri); + + // Updating OriginAttribute info for current_path + google::protobuf::Any* current_origin = current_path->add_pattrs(); + apipb::OriginAttribute current_origin_t; + current_origin_t.set_origin(0); + current_origin->PackFrom(current_origin_t); + + // Updating NextHopAttribute info for current_path + google::protobuf::Any* current_next_hop = current_path->add_pattrs(); + apipb::NextHopAttribute current_next_hop_t; + current_next_hop_t.set_next_hop(announced_prefix_nexthop); + current_next_hop->PackFrom(current_next_hop_t); + + // Updating CommunitiesAttribute for current_path + google::protobuf::Any* current_communities = current_path->add_pattrs(); + apipb::CommunitiesAttribute current_communities_t; + current_communities_t.add_communities(community_as_32bit_int); + current_communities->PackFrom(current_communities_t); + + request.set_allocated_path(current_path); + + apipb::AddPathResponse response; + + // Don't be confused by name, it also can withdraw announces + auto status = stub_->AddPath(&context, request, &response); + + if (!status.ok()) { + logger << log4cpp::Priority::ERROR << "AddPath request to BGP daemon failed with code: " << status.error_code() + << " message " << status.error_message(); + + return false; + } + + + return true; +} + +bool GrpcClient::AnnounceUnicastPrefixIPv6(const subnet_ipv6_cidr_mask_t& client_ipv6, + const subnet_ipv6_cidr_mask_t& ipv6_next_hop, + bool is_withdrawal, + uint32_t community_as_32bit_int) { + grpc::ClientContext context; + + // Set timeout for API + std::chrono::system_clock::time_point deadline = + std::chrono::system_clock::now() + std::chrono::seconds(gobgp_client_connection_timeout); + context.set_deadline(deadline); + + auto gobgp_ipv6_unicast_route_family = new apipb::Family; + gobgp_ipv6_unicast_route_family->set_afi(apipb::Family::AFI_IP6); + gobgp_ipv6_unicast_route_family->set_safi(apipb::Family::SAFI_UNICAST); + + apipb::AddPathRequest request; + request.set_table_type(apipb::TableType::GLOBAL); + + apipb::Path* current_path = new apipb::Path; + + current_path->set_allocated_family(gobgp_ipv6_unicast_route_family); + + if (is_withdrawal) { + current_path->set_is_withdraw(true); + } + + // Configure required announce + google::protobuf::Any* current_nlri = new google::protobuf::Any; + apipb::IPAddressPrefix current_ipaddrprefix; + current_ipaddrprefix.set_prefix(print_ipv6_address(client_ipv6.subnet_address)); + current_ipaddrprefix.set_prefix_len(client_ipv6.cidr_prefix_length); + + current_nlri->PackFrom(current_ipaddrprefix); + current_path->set_allocated_nlri(current_nlri); + + // Updating OriginAttribute info for current_path + google::protobuf::Any* current_origin = current_path->add_pattrs(); + apipb::OriginAttribute current_origin_t; + current_origin_t.set_origin(0); + current_origin->PackFrom(current_origin_t); + + // Updating NextHopAttribute info for current_path + google::protobuf::Any* current_next_hop = current_path->add_pattrs(); + apipb::NextHopAttribute current_next_hop_t; + current_next_hop_t.set_next_hop(print_ipv6_address(ipv6_next_hop.subnet_address)); + current_next_hop->PackFrom(current_next_hop_t); + + // Updating CommunitiesAttribute for current_path + google::protobuf::Any* current_communities = current_path->add_pattrs(); + apipb::CommunitiesAttribute current_communities_t; + current_communities_t.add_communities(community_as_32bit_int); + current_communities->PackFrom(current_communities_t); + + request.set_allocated_path(current_path); + + apipb::AddPathResponse response; + + // Don't be confused by name, it also can withdraw announces + auto status = stub_->AddPath(&context, request, &response); + + if (!status.ok()) { + logger << log4cpp::Priority::ERROR << "AddPath request to BGP daemon failed with code: " << status.error_code() + << " message " << status.error_message(); + + return false; + } + + + return true; +} diff --git a/src/gobgp_client/gobgp_client.hpp b/src/gobgp_client/gobgp_client.hpp index d246a41..4c5b931 100644 --- a/src/gobgp_client/gobgp_client.hpp +++ b/src/gobgp_client/gobgp_client.hpp @@ -1,15 +1,9 @@ #pragma once -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif // __GNUC__ +#include +#include - - -using grpc::Channel; -using grpc::ClientContext; -using grpc::Status; +#include "../fastnetmon_networks.hpp" // // MinGW has quite weird definitions which clash with field names in gRPC bindinds @@ -31,7 +25,6 @@ using grpc::Status; #endif -#include "../gobgp_client/attribute.pb.h" #include "../gobgp_client/gobgp.grpc.pb.h" #ifdef _WIN32 @@ -43,166 +36,27 @@ using grpc::Status; #endif -#include "../bgp_protocol.hpp" - #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ -using apipb::GobgpApi; - class GrpcClient { public: - GrpcClient(std::shared_ptr channel) : stub_(GobgpApi::NewStub(channel)) { - } + GrpcClient(std::shared_ptr channel); bool AnnounceUnicastPrefixIPv4(std::string announced_address, std::string announced_prefix_nexthop, bool is_withdrawal, unsigned int cidr_mask, - uint32_t community_as_32bit_int) { - grpc::ClientContext context; - - // Set timeout for API - std::chrono::system_clock::time_point deadline = - std::chrono::system_clock::now() + std::chrono::seconds(gobgp_client_connection_timeout); - context.set_deadline(deadline); - - auto gobgp_ipv4_unicast_route_family = new apipb::Family; - gobgp_ipv4_unicast_route_family->set_afi(apipb::Family::AFI_IP); - gobgp_ipv4_unicast_route_family->set_safi(apipb::Family::SAFI_UNICAST); - - apipb::AddPathRequest request; - request.set_table_type(apipb::TableType::GLOBAL); - - apipb::Path* current_path = new apipb::Path; - - current_path->set_allocated_family(gobgp_ipv4_unicast_route_family); - - if (is_withdrawal) { - current_path->set_is_withdraw(true); - } - - // Configure required announce - google::protobuf::Any* current_nlri = new google::protobuf::Any; - apipb::IPAddressPrefix current_ipaddrprefix; - current_ipaddrprefix.set_prefix(announced_address); - current_ipaddrprefix.set_prefix_len(cidr_mask); - - current_nlri->PackFrom(current_ipaddrprefix); - current_path->set_allocated_nlri(current_nlri); - - // Updating OriginAttribute info for current_path - google::protobuf::Any* current_origin = current_path->add_pattrs(); - apipb::OriginAttribute current_origin_t; - current_origin_t.set_origin(0); - current_origin->PackFrom(current_origin_t); - - // Updating NextHopAttribute info for current_path - google::protobuf::Any* current_next_hop = current_path->add_pattrs(); - apipb::NextHopAttribute current_next_hop_t; - current_next_hop_t.set_next_hop(announced_prefix_nexthop); - current_next_hop->PackFrom(current_next_hop_t); - - // Updating CommunitiesAttribute for current_path - google::protobuf::Any* current_communities = current_path->add_pattrs(); - apipb::CommunitiesAttribute current_communities_t; - current_communities_t.add_communities(community_as_32bit_int); - current_communities->PackFrom(current_communities_t); - - request.set_allocated_path(current_path); - - apipb::AddPathResponse response; - - // Don't be confused by name, it also can withdraw announces - auto status = stub_->AddPath(&context, request, &response); - - if (!status.ok()) { - logger << log4cpp::Priority::ERROR << "AddPath request to BGP daemon failed with code: " << status.error_code() - << " message " << status.error_message(); - - return false; - } - - - return true; - } + uint32_t community_as_32bit_int); bool AnnounceUnicastPrefixIPv6(const subnet_ipv6_cidr_mask_t& client_ipv6, const subnet_ipv6_cidr_mask_t& ipv6_next_hop, bool is_withdrawal, - uint32_t community_as_32bit_int) { - grpc::ClientContext context; - - // Set timeout for API - std::chrono::system_clock::time_point deadline = - std::chrono::system_clock::now() + std::chrono::seconds(gobgp_client_connection_timeout); - context.set_deadline(deadline); - - auto gobgp_ipv6_unicast_route_family = new apipb::Family; - gobgp_ipv6_unicast_route_family->set_afi(apipb::Family::AFI_IP6); - gobgp_ipv6_unicast_route_family->set_safi(apipb::Family::SAFI_UNICAST); - - apipb::AddPathRequest request; - request.set_table_type(apipb::TableType::GLOBAL); - - apipb::Path* current_path = new apipb::Path; - - current_path->set_allocated_family(gobgp_ipv6_unicast_route_family); - - if (is_withdrawal) { - current_path->set_is_withdraw(true); - } - - // Configure required announce - google::protobuf::Any* current_nlri = new google::protobuf::Any; - apipb::IPAddressPrefix current_ipaddrprefix; - current_ipaddrprefix.set_prefix(print_ipv6_address(client_ipv6.subnet_address)); - current_ipaddrprefix.set_prefix_len(client_ipv6.cidr_prefix_length); - - current_nlri->PackFrom(current_ipaddrprefix); - current_path->set_allocated_nlri(current_nlri); - - // Updating OriginAttribute info for current_path - google::protobuf::Any* current_origin = current_path->add_pattrs(); - apipb::OriginAttribute current_origin_t; - current_origin_t.set_origin(0); - current_origin->PackFrom(current_origin_t); - - // Updating NextHopAttribute info for current_path - google::protobuf::Any* current_next_hop = current_path->add_pattrs(); - apipb::NextHopAttribute current_next_hop_t; - current_next_hop_t.set_next_hop(print_ipv6_address(ipv6_next_hop.subnet_address)); - current_next_hop->PackFrom(current_next_hop_t); - - // Updating CommunitiesAttribute for current_path - google::protobuf::Any* current_communities = current_path->add_pattrs(); - apipb::CommunitiesAttribute current_communities_t; - current_communities_t.add_communities(community_as_32bit_int); - current_communities->PackFrom(current_communities_t); - - request.set_allocated_path(current_path); - - apipb::AddPathResponse response; - - // Don't be confused by name, it also can withdraw announces - auto status = stub_->AddPath(&context, request, &response); - - if (!status.ok()) { - logger << log4cpp::Priority::ERROR << "AddPath request to BGP daemon failed with code: " << status.error_code() - << " message " << status.error_message(); - - return false; - } - - - return true; - } - - + uint32_t community_as_32bit_int); private: - std::unique_ptr stub_; + std::unique_ptr stub_; };