mirror of
https://github.com/pavel-odintsov/fastnetmon.git
synced 2024-09-21 02:17:16 +00:00
Migrated IPv6 announces to use our logic to craft BGP IPv6 Unicast announces
This commit is contained in:
parent
742cbcae50
commit
af49358307
@ -124,4 +124,202 @@ bool GrpcClient::AnnounceUnicastPrefixIPv4(std::string announced_address,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Announce unicast or flow spec
|
||||
bool GrpcClient::AnnounceCommonPrefix(dynamic_binary_buffer_t binary_nlri,
|
||||
std::vector<dynamic_binary_buffer_t> bgp_attributes,
|
||||
bool is_withdrawal,
|
||||
unsigned int afi,
|
||||
unsigned int safi) {
|
||||
// We're not going to free this memory and we delegate it to gRPC
|
||||
// but we need to tell about it to PVS
|
||||
//+V773:SUPPRESS, class:Path, namespace:apipb
|
||||
apipb::Path* current_path = new apipb::Path;
|
||||
|
||||
if (is_withdrawal) {
|
||||
current_path->set_is_withdraw(true);
|
||||
}
|
||||
|
||||
// We're not going to free this memory and we delegate it to gRPC
|
||||
// but we need to tell about it to PVS
|
||||
//+V773:SUPPRESS, class:Family, namespace:apipb
|
||||
auto route_family = new apipb::Family;
|
||||
|
||||
if (afi == AFI_IP) {
|
||||
route_family->set_afi(apipb::Family::AFI_IP);
|
||||
} else if (afi == AFI_IP6) {
|
||||
route_family->set_afi(apipb::Family::AFI_IP6);
|
||||
} else {
|
||||
logger << log4cpp::Priority::ERROR << "Unknown AFI";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (safi == SAFI_UNICAST) {
|
||||
route_family->set_safi(apipb::Family::SAFI_UNICAST);
|
||||
} else if (safi == SAFI_FLOW_SPEC_UNICAST) {
|
||||
route_family->set_safi(apipb::Family::SAFI_FLOW_SPEC_UNICAST);
|
||||
} else {
|
||||
logger << log4cpp::Priority::ERROR << "Unknown SAFI";
|
||||
return false;
|
||||
}
|
||||
|
||||
current_path->set_allocated_family(route_family);
|
||||
current_path->set_nlri_binary(binary_nlri.get_pointer(), binary_nlri.get_used_size());
|
||||
|
||||
for (auto bgp_attribute : bgp_attributes) {
|
||||
current_path->add_pattrs_binary(bgp_attribute.get_pointer(), bgp_attribute.get_used_size());
|
||||
}
|
||||
|
||||
apipb::AddPathRequest request;
|
||||
request.set_table_type(apipb::TableType::GLOBAL);
|
||||
request.set_allocated_path(current_path);
|
||||
|
||||
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);
|
||||
|
||||
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::AnnounceUnicastPrefixLowLevelIPv6(const IPv6UnicastAnnounce& unicast_ipv6_announce, bool is_withdrawal) {
|
||||
logger << log4cpp::Priority::INFO << "Send IPv6 " << (is_withdrawal ? "withdrawal " : "")
|
||||
<< "unicast announce to BGP daemon: " << unicast_ipv6_announce.print();
|
||||
|
||||
// We need to prepare very fancy NLRI first: https://github.com/osrg/gobgp/issues/2673
|
||||
// To be more specific:
|
||||
// https://github.com/fujita/gobgp/blob/7e4d9a0e89b1fc5e4fc9865b7b6431a00dcb60e2/pkg/server/grpc_server_test.go#L48
|
||||
// And implementation details:
|
||||
// https://github.com/osrg/gobgp/blob/master/pkg/packet/bgp/bgp.go#L1501
|
||||
// https://github.com/osrg/gobgp/blob/master/pkg/packet/bgp/bgp.go#L1440
|
||||
|
||||
dynamic_binary_buffer_t ipv6_nlri{};
|
||||
ipv6_nlri.set_maximum_buffer_size_in_bytes(256);
|
||||
|
||||
if (!encode_ipv6_prefix(unicast_ipv6_announce.get_prefix(), ipv6_nlri)) {
|
||||
logger << log4cpp::Priority::ERROR << "Cannot encode prefix for IPv6 NLRI";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normally, vector should be ordered in ascending order of attribute types
|
||||
// with the only exception for bgp_mp_reach_ipv6_attribute
|
||||
std::vector<dynamic_binary_buffer_t> bgp_attributes;
|
||||
|
||||
dynamic_binary_buffer_t bgp_mp_reach_ipv6_attribute;
|
||||
bool craft_ipv6_mpreach_nlri_result =
|
||||
encode_ipv6_announces_into_bgp_mp_reach_attribute(unicast_ipv6_announce, bgp_mp_reach_ipv6_attribute);
|
||||
|
||||
if (!craft_ipv6_mpreach_nlri_result) {
|
||||
logger << log4cpp::Priority::ERROR << "Can't encode MP reach NLRI for IPv6 announce";
|
||||
return false;
|
||||
}
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "IPv6 MP reach NLRI attribute size is: " << bgp_mp_reach_ipv6_attribute.get_used_size();
|
||||
|
||||
bgp_attributes.push_back(bgp_mp_reach_ipv6_attribute);
|
||||
|
||||
bgp_attribute_origin origin_attr;
|
||||
|
||||
dynamic_binary_buffer_t origin_as_binary_array;
|
||||
origin_as_binary_array.set_maximum_buffer_size_in_bytes(sizeof(origin_attr));
|
||||
origin_as_binary_array.append_data_as_object_ptr(&origin_attr);
|
||||
|
||||
// It has attribute #1 and will be first in all the cases
|
||||
bgp_attributes.push_back(origin_as_binary_array);
|
||||
|
||||
// TODO: this logic is copied as is from get_attributes() of IPv4 announces
|
||||
// We need to try ways to unify logic to craft such announces
|
||||
// AS Path should be here and it's #2
|
||||
if (unicast_ipv6_announce.as_path_asns.size() > 0) {
|
||||
// We have ASNs for AS_PATH attribute
|
||||
bgp_attribute_as_path_t bgp_attribute_as_path;
|
||||
|
||||
// Populate attribute length
|
||||
bgp_attribute_as_path.attribute_length =
|
||||
sizeof(bgp_as_path_segment_element_t) + unicast_ipv6_announce.as_path_asns.size() * sizeof(uint32_t);
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "AS_PATH attribute length: " << uint32_t(bgp_attribute_as_path.attribute_length);
|
||||
|
||||
uint32_t as_path_attribute_full_length = sizeof(bgp_attribute_as_path_t) + bgp_attribute_as_path.attribute_length;
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "AS_PATH attribute full length: " << as_path_attribute_full_length;
|
||||
|
||||
dynamic_binary_buffer_t as_path_as_binary_array;
|
||||
as_path_as_binary_array.set_maximum_buffer_size_in_bytes(as_path_attribute_full_length);
|
||||
|
||||
// Append attribute header
|
||||
as_path_as_binary_array.append_data_as_object_ptr(&bgp_attribute_as_path);
|
||||
|
||||
bgp_as_path_segment_element_t bgp_as_path_segment_element;
|
||||
|
||||
// Numbers of ASNs in list
|
||||
bgp_as_path_segment_element.path_segment_length = unicast_ipv6_announce.as_path_asns.size();
|
||||
|
||||
logger << log4cpp::Priority::DEBUG
|
||||
<< "AS_PATH segments number: " << uint32_t(bgp_as_path_segment_element.path_segment_length);
|
||||
|
||||
// Append segment header
|
||||
as_path_as_binary_array.append_data_as_object_ptr(&bgp_as_path_segment_element);
|
||||
|
||||
logger << log4cpp::Priority::DEBUG << "AS_PATH ASN numner: " << unicast_ipv6_announce.as_path_asns.size();
|
||||
|
||||
for (auto asn : unicast_ipv6_announce.as_path_asns) {
|
||||
// Append all ASNs in big endian encoding
|
||||
uint32_t asn_big_endian = fast_hton(asn);
|
||||
|
||||
as_path_as_binary_array.append_data_as_object_ptr(&asn_big_endian);
|
||||
}
|
||||
|
||||
if (as_path_as_binary_array.is_failed()) {
|
||||
logger << log4cpp::Priority::ERROR << "Issue with storing AS_PATH";
|
||||
}
|
||||
|
||||
bgp_attributes.push_back(as_path_as_binary_array);
|
||||
}
|
||||
|
||||
auto community_list = unicast_ipv6_announce.get_communities();
|
||||
|
||||
if (!community_list.empty()) {
|
||||
// TODO: I copied this code from bgp_protocol.cpp from get_attributes() function. I think we can unify it
|
||||
|
||||
// We have communities
|
||||
bgp_attribute_community_t bgp_attribute_community;
|
||||
|
||||
// Each record has this of 4 bytes
|
||||
bgp_attribute_community.attribute_length = community_list.size() * sizeof(bgp_community_attribute_element_t);
|
||||
uint32_t community_attribute_full_length = sizeof(bgp_attribute_community_t) + bgp_attribute_community.attribute_length;
|
||||
|
||||
dynamic_binary_buffer_t communities_list_as_binary_array;
|
||||
communities_list_as_binary_array.set_maximum_buffer_size_in_bytes(community_attribute_full_length);
|
||||
|
||||
communities_list_as_binary_array.append_data_as_object_ptr(&bgp_attribute_community);
|
||||
|
||||
for (auto bgp_community_element : community_list) {
|
||||
// Encode they in network byte order
|
||||
bgp_community_element.host_byte_order_to_network_byte_order();
|
||||
|
||||
communities_list_as_binary_array.append_data_as_object_ptr(&bgp_community_element);
|
||||
}
|
||||
|
||||
// Community is attribute #8
|
||||
bgp_attributes.push_back(communities_list_as_binary_array);
|
||||
}
|
||||
|
||||
// Normally NLRI is empty for IPv6 announces but GoBGP uses pretty unusual approach to encode it described on top of this function
|
||||
return AnnounceCommonPrefix(ipv6_nlri, bgp_attributes, is_withdrawal, AFI_IP6, SAFI_UNICAST);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc++/channel.h>
|
||||
|
||||
#include "../bgp_protocol.hpp"
|
||||
|
||||
#include "../fastnetmon_networks.hpp"
|
||||
|
||||
//
|
||||
@ -45,11 +47,18 @@ class GrpcClient {
|
||||
public:
|
||||
GrpcClient(std::shared_ptr<grpc::Channel> channel);
|
||||
|
||||
// Announce unicast or flow spec
|
||||
bool AnnounceCommonPrefix(dynamic_binary_buffer_t binary_nlri,
|
||||
std::vector<dynamic_binary_buffer_t> bgp_attributes,
|
||||
bool is_withdrawal,
|
||||
unsigned int afi,
|
||||
unsigned int safi);
|
||||
bool AnnounceUnicastPrefixIPv4(std::string announced_address,
|
||||
std::string announced_prefix_nexthop,
|
||||
bool is_withdrawal,
|
||||
unsigned int cidr_mask,
|
||||
uint32_t community_as_32bit_int);
|
||||
bool AnnounceUnicastPrefixLowLevelIPv6(const IPv6UnicastAnnounce& unicast_ipv6_announce, bool is_withdrawal);
|
||||
|
||||
private:
|
||||
std::unique_ptr<apipb::GobgpApi::Stub> stub_;
|
||||
|
Loading…
Reference in New Issue
Block a user