diff --git a/common/controlplaneconfig.h b/common/controlplaneconfig.h index da9a6d4d..6458619f 100644 --- a/common/controlplaneconfig.h +++ b/common/controlplaneconfig.h @@ -3,6 +3,7 @@ #include #include "balancer.h" +#include "define.h" #include "scheduler.h" #include "type.h" @@ -104,6 +105,19 @@ class interface_t common::globalBase::tFlow flow; }; +class bird_import_t +{ +public: + SERIALIZABLE(socket, vrf); + +public: + inline static const std::string socketStr = "socket"; + inline static const std::string vrfStr = "vrf"; + + std::string socket; + std::string vrf; +}; + class config_t { public: @@ -114,7 +128,7 @@ class config_t nlohmann::json save() const; */ - SERIALIZABLE(routeId, to_kernel_prefixes, vrf, tunnel_enabled, ignore_tables, ipv4_source_address, ipv6_source_address, udp_destination_port, local_prefixes, peers, interfaces); + SERIALIZABLE(routeId, to_kernel_prefixes, vrf, tunnel_enabled, ignore_tables, ipv4_source_address, ipv6_source_address, udp_destination_port, local_prefixes, peers, interfaces, bird_imports); public: tRouteId routeId; @@ -128,6 +142,7 @@ class config_t std::set local_prefixes; ///< for fallback to default std::map peers; std::map interfaces; + std::vector bird_imports; }; } diff --git a/common/icp.h b/common/icp.h index d5103a29..b8b6f2ea 100644 --- a/common/icp.h +++ b/common/icp.h @@ -671,7 +671,9 @@ using eor = std::tuple; ///< table_name -using request = std::vector>; +using action = std::variant; + +using request = std::vector; } namespace rib_summary diff --git a/controlplane/configparser.cpp b/controlplane/configparser.cpp index 92054e4c..76839015 100644 --- a/controlplane/configparser.cpp +++ b/controlplane/configparser.cpp @@ -197,6 +197,32 @@ controlplane::base_t config_parser_t::loadConfig(const std::string& rootFilePath return baseNext; } +void config_parser_t::loadConfig_route_bird([[maybe_unused]]controlplane::base_t& baseNext, + std::vector& birdsImport, + const nlohmann::json& birdJson) +{ + using BirdImport = controlplane::route::bird_import_t; + for (const auto& elemJson : birdJson) + { + BirdImport import; + + if (exist(elemJson, BirdImport::socketStr)) + { + import.socket = elemJson[BirdImport::socketStr]; + } + + if (exist(elemJson, BirdImport::vrfStr)) + { + import.vrf = elemJson[BirdImport::vrfStr]; + } + + YANET_LOG_INFO("loadConfig_route_bird: socket(%s), vrf(%s)\n", + import.socket.data(), + import.vrf.data()); + birdsImport.push_back(std::move(import)); + } +} + void config_parser_t::loadConfig_logicalPort(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson) @@ -367,6 +393,13 @@ void config_parser_t::loadConfig_route(controlplane::base_t& baseNext, route.tunnel_enabled = false; } + if (exist(moduleJson, "birdImport")) + { + loadConfig_route_bird(baseNext, + route.bird_imports, + moduleJson["birdImport"]); + } + // route.routeId = routeId; diff --git a/controlplane/configparser.h b/controlplane/configparser.h index 2b86dad8..df6ee28e 100644 --- a/controlplane/configparser.h +++ b/controlplane/configparser.h @@ -21,6 +21,7 @@ class config_parser_t void loadConfig_logicalPort(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson); void loadConfig_route(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson, const std::string& rootFilePath, const std::map& jsons); void loadConfig_route_peers(controlplane::base_t& baseNext, controlplane::route::config_t& route, const nlohmann::json& json, const std::string& rootFilePath, const std::map& jsons); + void loadConfig_route_bird(controlplane::base_t& baseNext, std::vector& birdsImport, const nlohmann::json& birdJson); void loadConfig_decap(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson); void loadConfig_nat64stateful(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson, const std::string& rootFilePath, const std::map& jsons); void loadConfig_nat64stateless(controlplane::base_t& baseNext, const std::string& moduleId, const nlohmann::json& moduleJson, const std::string& rootFilePath, const std::map& jsons); diff --git a/controlplane/controlplane.cpp b/controlplane/controlplane.cpp index ae31b56d..16ff417f 100644 --- a/controlplane/controlplane.cpp +++ b/controlplane/controlplane.cpp @@ -538,6 +538,18 @@ common::icp::controlplane_values::response cControlPlane::controlplane_values() return response; } +common::icp::route_config::response cControlPlane::getRoute() const +{ + common::icp::route_config::response response; + + { + auto current_guard = generations.current_lock_guard(); + response = generations.current().routes; + } + + return response; +} + common::icp::getDecapPrefixes::response cControlPlane::command_getDecapPrefixes() { common::icp::getDecapPrefixes::response response; @@ -941,6 +953,14 @@ eResult cControlPlane::loadConfig(const std::string& rootFilePath, } YANET_LOG_INFO("dataplane has been updated (stage 7)\n"); + for (auto& module : modules) + { + if (rib_t* rib = dynamic_cast(module)) + { + rib->bird_import_get(); + rib->moduleStart(); + } + } } catch (const error_result_t& error) { diff --git a/controlplane/controlplane.h b/controlplane/controlplane.h index 7f98d1a6..7e807a05 100644 --- a/controlplane/controlplane.h +++ b/controlplane/controlplane.h @@ -106,6 +106,7 @@ class cControlPlane common::icp::acl_unwind::response acl_unwind(const common::icp::acl_unwind::request& request) const; common::icp::acl_lookup::response acl_lookup(const common::icp::acl_lookup::request& request) const; common::icp::controlplane_values::response controlplane_values() const; + common::icp::route_config::response getRoute() const; common::icp::getDecapPrefixes::response command_getDecapPrefixes(); common::icp::getNat64statelessTranslations::response command_getNat64statelessTranslations(); diff --git a/controlplane/libbird.cpp b/controlplane/libbird.cpp new file mode 100644 index 00000000..3cd478b4 --- /dev/null +++ b/controlplane/libbird.cpp @@ -0,0 +1,612 @@ +#include "libbird.h" + +#include +#include +#include +#include +#include "common/type.h" +#include "common/icp.h" +#include "controlplane/rib.h" + +static inline bool +decode_u8(uintptr_t *ppos, uintptr_t end, uint8_t *pvalue) +{ + if (*ppos + sizeof(uint8_t) > end) + return false; + *pvalue = *(uint8_t *)*ppos; + *ppos += sizeof(uint8_t); + return true; +} + +static inline bool +decode_u16(uintptr_t *ppos, uintptr_t end, uint16_t *pvalue) +{ + if (*ppos + sizeof(uint16_t) > end) + return false; + *pvalue = *(uint16_t *)*ppos; + *ppos += sizeof(uint16_t); + return true; +} + +static inline bool +decode_u32(uintptr_t *ppos, uintptr_t end, uint32_t *pvalue) +{ + if (*ppos + sizeof(uint32_t) > end) + return false; + *pvalue = *(uint32_t *)*ppos; + *ppos += sizeof(uint32_t); + return true; +} + +static inline bool +decode_chunk(uintptr_t *ppos, uintptr_t end, uintptr_t *pchunk_end) +{ + uint32_t chunk_size; + if (!decode_u32(ppos, end, &chunk_size)) + return false; + *pchunk_end = *ppos + chunk_size; + return *pchunk_end <= end; +} + +static inline bool +decode_u32_array(uintptr_t *ppos, uintptr_t end, uintptr_t *parray_end) +{ + uint32_t array_count; + if (!decode_u32(ppos, end, &array_count)) + return false; + *parray_end = *ppos + sizeof(uint32_t) * array_count; + return (*parray_end <= end); +} + +static inline bool +decode_ip_addr(uintptr_t *ppos, uintptr_t end, ip_addr *paddr) +{ + if (*ppos + sizeof(ip_addr) > end) + return false; + *paddr = *(ip_addr *)*ppos; + *ppos += sizeof(ip_addr); + return true; +} + +static inline bool +decode_net_addr(uintptr_t *ppos, uintptr_t end, net_addr_union *paddr) +{ + if (*ppos + sizeof(net_addr_union) > end) + return false; + *paddr = *(net_addr_union *)*ppos; + // Some members of net_addr_union are variable length structures so + // check the length attribute. + if (*ppos + paddr->n.length > end) + return false; + if (paddr->n.length <= sizeof(net_addr_union)) { + *ppos += sizeof(net_addr_union); + return true; + } + return false; + /* + * FIXME: this is not supported yet + memcpy( + paddr + 1, (void *)(*ppos + sizeof(net_addr_union)), + paddr->n.length - sizeof(net_addr_union) + ); + *ppos += paddr->n.length; + return true; + */ +} + +static inline bool +decode_u16_array(uintptr_t *ppos, uintptr_t end, std::vector *values) +{ + size_t attr_end; + if (!decode_chunk(ppos, end, &attr_end)) { + return false; + } + + while (*ppos < attr_end) { + uint16_t value; + if (!decode_u16(ppos, attr_end, &value)) { + return false; + } + + values->emplace_back(value); + } + + return true; +} + +static inline bool +decode_u32_array(uintptr_t *ppos, uintptr_t end, std::vector *values) +{ + size_t attr_end; + if (!decode_chunk(ppos, end, &attr_end)) { + return false; + } + + while (*ppos < attr_end) { + uint32_t value; + if (!decode_u32(ppos, attr_end, &value)) { + return false; + } + + values->emplace_back(value); + } + + return true; +} + +static inline bool +decode_as_path(uintptr_t *ppos, uintptr_t end, std::vector *as_path) +{ + size_t attr_end; + if (!decode_chunk(ppos, end, &attr_end)) { + return false; + } + + while (*ppos < attr_end) { + uint8_t segment_type; + if (!decode_u8(ppos, attr_end, &segment_type)) { + return false; + } + + if (segment_type != 2 && segment_type != 3) { + return false; + } + + uint8_t segment_len; + if (!decode_u8(ppos, attr_end, &segment_len)) { + return false; + } + + for (uint16_t idx = 0; idx < segment_len; ++idx) { + uint32_t as; + if (!decode_u32(ppos, attr_end, &as)) { + return false; + } + as = ntohl(as); + as_path->emplace_back(as); + } + } + + return true; +} + +static inline bool +ipa_is_ip4(ip_addr addr) +{ + return addr.addr[0] == 0 && addr.addr[1] == 0 && addr.addr[2] == 0xffff; +} + +static inline common::ipv4_address_t +ipa_to_address_4(ip_addr addr) +{ + return common::ipv4_address_t(addr.addr[3]); +} + +static inline common::ipv6_address_t +ipa_to_address_6(ip_addr addr) +{ + addr.addr[0] = ntohl(addr.addr[0]); + addr.addr[1] = ntohl(addr.addr[1]); + addr.addr[2] = ntohl(addr.addr[2]); + addr.addr[3] = ntohl(addr.addr[3]); + return common::ipv6_address_t((uint8_t *)&addr); +} + +static inline common::ip_address_t +ipa_to_address(ip_addr addr) +{ + if (ipa_is_ip4(addr)) + return common::ip_address_t(ipa_to_address_4(addr)); + return common::ip_address_t(ipa_to_address_6(addr)); +} + +static inline bool +recover_prefix_info(net_addr_union *paddr, common::ip_prefix_t *prefix, + common::ip_address_t *vpnDST, uint32_t *vpnRD) +{ + + switch (paddr->n.type) { + case NET_IP4: { + *prefix = common::ip_prefix_t(common::ipv4_address_t(paddr->ip4.prefix), paddr->ip4.pxlen); + break; + } + + case NET_IP6: { + *prefix = common::ip_prefix_t(ipa_to_address_6(paddr->ip6.prefix), paddr->ip6.pxlen); + break; + } + + case NET_VPN4: { + if ((paddr->vpn4.rd >> 48) != 1) { + return false; + } + + *prefix = common::ip_prefix_t(common::ipv4_address_t(paddr->vpn4.prefix), paddr->vpn4.pxlen); + *vpnDST = common::ip_address_t(common::ipv4_address_t(paddr->vpn4.rd >> 16)); + *vpnRD = paddr->vpn4.rd & 0xffff; + break; + } + + case NET_VPN6: { + if ((paddr->vpn6.rd >> 48) != 1) { + return false; + } + + *prefix = common::ip_prefix_t(ipa_to_address_6(paddr->vpn6.prefix), paddr->vpn6.pxlen); + *vpnDST = common::ip_address_t(common::ipv4_address_t(paddr->vpn4.rd >> 16)); + *vpnRD = paddr->vpn6.rd & 0xffff; + + break; + } + + default: + return false; + } + + return true; +} + +static inline bool +recover_next_hop(uintptr_t *ppos, uintptr_t end, common::ip_address_t *next_hop) +{ + if (end - *ppos != sizeof(ip_addr) && + end - *ppos != 2 * sizeof(ip_addr)) { + return false; + } + + if (end - *ppos == sizeof(ip_addr)) { + ip_addr nh_addr; + if (!decode_ip_addr(ppos, end, &nh_addr)) { + return false; + } + *next_hop = ipa_to_address(nh_addr); + return true; + } + + ip_addr nh_addr1; + ip_addr nh_addr2; + if (!decode_ip_addr(ppos, end, &nh_addr1) || + !decode_ip_addr(ppos, end, &nh_addr2)) { + return false; + } + + if (nh_addr2.addr[0] == 0 && nh_addr2.addr[1] == 0 && + nh_addr2.addr[2] == 0 && nh_addr2.addr[3] == 0) { + *next_hop = ipa_to_address(nh_addr1); + } else { + *next_hop = ipa_to_address(nh_addr2); + } + + return true; +} + +static bool +parse_route_update(uintptr_t *ppos, uintptr_t end, const char *vrf, + common::icp::rib_update::action *paction) +{ + common::ip_address_t peer_address; + std::string attribute_origin; + std::string path_information; + std::vector attribute_aspath; + std::set attribute_communities; + std::set attribute_large_communities; + std::vector labels; + + uint32_t attribute_local_preference = 0; + uint32_t attribute_med = 0; + + common::ip_address_t next_hop; + common::ip_prefix_t prefix; + common::ip_address_t vpnDST; + uint32_t vpnRD = 0; + + /* Decode route prefix. */ + net_addr_union addr; + if (!decode_net_addr(ppos, end, &addr)) + return false; + + if (!recover_prefix_info(&addr, &prefix, &vpnDST, &vpnRD)) + return false; + + uint32_t type; + if (!decode_u32(ppos, end, &type)) + return false; + + ip_addr remote_addr; + if (!decode_ip_addr(ppos, end, &remote_addr)) + return false; + peer_address = ipa_to_address(remote_addr); + + size_t attrs_end; + if (!decode_chunk(ppos, end, &attrs_end)) + return false; + + if (attrs_end != end) + return false; + + /* Now decode all attributes one by one. */ + while (*ppos < attrs_end) { + uint32_t attr_id; + if (!decode_u32(ppos, attrs_end, &attr_id)) + return false; + + + switch (EA_ID(attr_id)) { + case BA_ORIGIN: { + uint32_t origin; + if (!decode_u32(ppos, attrs_end, &origin)) { + return false; + } + switch (origin) { + case 0: attribute_origin = "IGP"; break; + case 1: attribute_origin = "EGP"; break; + case 2: attribute_origin = "Incomplete"; break; + default: attribute_origin = "?"; + } + + break; + } + + case BA_MULTI_EXIT_DISC: { + uint32_t med; + if (!decode_u32(ppos, attrs_end, &med)) { + return false; + } + + attribute_med = med; + + break; + } + + case BA_LOCAL_PREF: { + uint32_t pref; + if (!decode_u32(ppos, attrs_end, &pref)) { + return false; + } + + attribute_local_preference = pref; + + break; + } + + case BA_ORIGINATOR_ID: { + uint32_t originator; + if (!decode_u32(ppos, attrs_end, &originator)) { + return false; + } + + break; + } + + case BA_AS_PATH: { + if (!decode_as_path(ppos, attrs_end, &attribute_aspath)) { + return false; + } + + break; + } + + case BA_NEXT_HOP: { + size_t attr_end; + if (!decode_chunk(ppos, attrs_end, &attr_end)) { + return false; + } + + if (!recover_next_hop(ppos, attr_end, &next_hop)) { + return false; + } + + break; + } + + case BA_COMMUNITY: { + std::vector communities; + if (!decode_u16_array(ppos, attrs_end, &communities)) { + return false; + } + + if (communities.size() % 2 != 0) { + return false; + } + + for (size_t idx = 0; idx < communities.size() / 2; ++idx) { + attribute_communities.emplace( + communities[idx * 2 + 0], + communities[idx * 2 + 1] + ); + } + + break; + } + + case BA_CLUSTER_LIST: { + std::vector clusters; + if (!decode_u32_array(ppos, attrs_end, &clusters)) { + return false; + } + + break; + } + + case BA_EXT_COMMUNITY: { + std::vector ext_communities; + if (!decode_u32_array(ppos, attrs_end, &ext_communities)) { + return false; + } + + break; + } + + case BA_LARGE_COMMUNITY: { + std::vector large_communities; + if (!decode_u32_array(ppos, attrs_end, &large_communities)) { + return false; + } + + if (large_communities.size() % 3 != 0) { + return false; + } + + for (size_t idx = 0; idx < large_communities.size() / 3; + ++idx) { + + attribute_large_communities.emplace( + large_communities[idx * 3 + 0], + large_communities[idx * 3 + 1], + large_communities[idx * 3 + 2] + ); + } + + break; + } + + case BA_MPLS_LABEL_STACK: { + if (!decode_u32_array(ppos, attrs_end, &labels)) { + return false; + } + + break; + } + + default: + return false; + + } + } + + std::string afi; + std::string safi; + + //FIXME: table name + if (prefix.is_ipv4()) { + afi = "ipv4"; + } else { + afi = "ipv6"; + } + + if (vpnRD == 0) { + safi = "unicast"; + } else { + safi = "mpls-vpn"; + } + + if (type == 1) { + common::icp::rib_update::insert insert = {"bgp", + std::string(vrf), + YANET_RIB_PRIORITY_DEFAULT, + {}}; + + auto& announce = std::get<3>(insert)[{peer_address, + attribute_origin, + attribute_med, + attribute_aspath, + attribute_communities, + attribute_large_communities, + attribute_local_preference}]; + + auto& announce_table = announce[afi + " " + safi]; + announce_table[next_hop].emplace_back(prefix, std::to_string(vpnRD), labels); + + *paction = insert; + } else { + common::icp::rib_update::remove remove = {"bgp", + std::string(vrf), + YANET_RIB_PRIORITY_DEFAULT, + {}}; + + auto& announce = std::get<3>(remove)[peer_address]; + + //FIXME: table name + auto& announce_table = announce[afi + " " + safi]; + announce_table.emplace_back(prefix, std::to_string(vpnRD), labels); + + *paction = remove; + } + + return true; +} + +void +read_bird_feed(const char *sock_name, const char *vrf, class rib_t *rib) +{ + /* Connect to bird export socket. */ + int bird_sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un server_addr; + server_addr.sun_family = AF_UNIX; + strncpy(server_addr.sun_path, sock_name, sizeof(server_addr.sun_path) - 1); + if (connect(bird_sock, + (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) { + return; + } + + /* + * Read buffer is used to accumulate multuple route updates and + * flush then at once. 1Mib looks good as the buffur size. + */ + const size_t buf_size = 1 << 20; + void *read_buf = malloc(buf_size); + if (read_buf == NULL) { + close(bird_sock); + return; + } + /* + * The variable is the offset to read data to and denotes the first + * byte which could nit be parsed yet. + */ + size_t read_pos = 0; + /* + * Parse position is the position of the next one route update to + * process. + */ + size_t parse_pos = 0; + + common::icp::rib_update::request requests; + + for (;;) + { + /* Read as mush as possible data */ + ssize_t readen = read(bird_sock, + (void *)((uintptr_t)read_buf + read_pos), + buf_size - read_pos); + if (readen <= 0) { + break; + } + + /* Adust read postion and try to recover next route update. */ + read_pos += readen; + while (parse_pos < read_pos) { + /* pos and end denote addresses of a memory chunk to parse. */ + uintptr_t pos = (uintptr_t)read_buf + parse_pos; + uintptr_t end = (uintptr_t)read_buf + read_pos; + + /* Determine boundaries of the next route update. */ + uintptr_t route_end; + if (!decode_chunk(&pos, end, &route_end)) + break; + + common::icp::rib_update::action action; + if (!parse_route_update(&pos, route_end, vrf, &action)) + break; + + requests.emplace_back(action); + + parse_pos = pos - (uintptr_t)read_buf; + } + + rib->rib_update(requests); + rib->rib_flush(); + + if (buf_size - read_pos < buf_size / 2) { + memmove(read_buf, + (void *)((uintptr_t)read_buf + parse_pos), + read_pos - parse_pos); + read_pos = read_pos - parse_pos; + parse_pos = 0; + } + } + + free(read_buf); + close(bird_sock); + + return; +} diff --git a/controlplane/libbird.h b/controlplane/libbird.h new file mode 100644 index 00000000..92646132 --- /dev/null +++ b/controlplane/libbird.h @@ -0,0 +1,175 @@ +#ifndef LIBBIRD_H +#define LIBBIRD_H + +#include + +#define NET_IP4 1 +#define NET_IP6 2 +#define NET_VPN4 3 +#define NET_VPN6 4 +#define NET_ROA4 5 +#define NET_ROA6 6 +#define NET_FLOW4 7 +#define NET_FLOW6 8 +#define NET_IP6_SADR 9 +#define NET_MPLS 10 +#define NET_MAX 11 + +#define NB_IP4 (1 << NET_IP4) +#define NB_IP6 (1 << NET_IP6) +#define NB_VPN4 (1 << NET_VPN4) +#define NB_VPN6 (1 << NET_VPN6) +#define NB_ROA4 (1 << NET_ROA4) +#define NB_ROA6 (1 << NET_ROA6) +#define NB_FLOW4 (1 << NET_FLOW4) +#define NB_FLOW6 (1 << NET_FLOW6) +#define NB_IP6_SADR (1 << NET_IP6_SADR) +#define NB_MPLS (1 << NET_MPLS) + +#define NB_IP (NB_IP4 | NB_IP6) +#define NB_VPN (NB_VPN4 | NB_VPN6) +#define NB_ROA (NB_ROA4 | NB_ROA6) +#define NB_FLOW (NB_FLOW4 | NB_FLOW6) +#define NB_DEST (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS) +#define NB_ANY 0xffffffff + +#define BA_ORIGIN 0x01 /* RFC 4271 */ /* WM */ +#define BA_AS_PATH 0x02 /* WM */ +#define BA_NEXT_HOP 0x03 /* WM */ +#define BA_MULTI_EXIT_DISC 0x04 /* ON */ +#define BA_LOCAL_PREF 0x05 /* WD */ +#define BA_ATOMIC_AGGR 0x06 /* WD */ +#define BA_AGGREGATOR 0x07 /* OT */ +#define BA_COMMUNITY 0x08 /* RFC 1997 */ /* OT */ +#define BA_ORIGINATOR_ID 0x09 /* RFC 4456 */ /* ON */ +#define BA_CLUSTER_LIST 0x0a /* RFC 4456 */ /* ON */ +#define BA_MP_REACH_NLRI 0x0e /* RFC 4760 */ +#define BA_MP_UNREACH_NLRI 0x0f /* RFC 4760 */ +#define BA_EXT_COMMUNITY 0x10 /* RFC 4360 */ +#define BA_AS4_PATH 0x11 /* RFC 6793 */ +#define BA_AS4_AGGREGATOR 0x12 /* RFC 6793 */ +#define BA_AIGP 0x1a /* RFC 7311 */ +#define BA_LARGE_COMMUNITY 0x20 /* RFC 8092 */ +#define BA_ONLY_TO_CUSTOMER 0x23 /* RFC 9234 */ + +/* Bird's private internal BGP attributes */ +#define BA_MPLS_LABEL_STACK 0xfe /* MPLS label stack transfer attribute */ + +#define EA_ID(ea) ((ea) & 0xff) +#define EA_PROTO(ea) ((ea) >> 8) + +typedef uint32_t ip4_addr; + +typedef struct ip6_addr { + uint32_t addr[4]; +} ip6_addr; + +typedef ip6_addr ip_addr; + +typedef struct net_addr { + uint8_t type; + uint8_t pxlen; + uint16_t length; + uint8_t data[20]; + uint64_t align[0]; +} net_addr; + +typedef struct net_addr_ip4 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip4_addr prefix; +} net_addr_ip4; + +typedef struct net_addr_ip6 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip6_addr prefix; +} net_addr_ip6; + +typedef struct net_addr_vpn4 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip4_addr prefix; + uint64_t rd; +} net_addr_vpn4; + +typedef struct net_addr_vpn6 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip6_addr prefix; + uint32_t padding; + uint64_t rd; +} net_addr_vpn6; + +typedef struct net_addr_roa4 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip4_addr prefix; + uint32_t max_pxlen; + uint32_t asn; +} net_addr_roa4; + +typedef struct net_addr_roa6 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip6_addr prefix; + uint32_t max_pxlen; + uint32_t asn; +} net_addr_roa6; + +typedef struct net_addr_flow4 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip4_addr prefix; + uint8_t data[0]; +} net_addr_flow4; + +typedef struct net_addr_flow6 { + uint8_t type; + uint8_t pxlen; + uint16_t length; + ip6_addr prefix; + uint8_t data[0]; +} net_addr_flow6; + +typedef struct net_addr_mpls { + uint8_t type; + uint8_t pxlen; + uint16_t length; + uint32_t label; +} net_addr_mpls; + +typedef struct net_addr_ip6_sadr { + uint8_t type; + uint8_t dst_pxlen; + uint16_t length; + ip6_addr dst_prefix; + int32_t src_pxlen; /* s32 to avoid padding */ + ip6_addr src_prefix; +} net_addr_ip6_sadr; + +typedef union net_addr_union { + net_addr n; + net_addr_ip4 ip4; + net_addr_ip6 ip6; + net_addr_vpn4 vpn4; + net_addr_vpn6 vpn6; + net_addr_roa4 roa4; + net_addr_roa6 roa6; + net_addr_flow4 flow4; + net_addr_flow6 flow6; + net_addr_ip6_sadr ip6_sadr; + net_addr_mpls mpls; +} net_addr_union; + +void +read_bird_feed(const char *sock_name, const char *vrf, class rib_t *rib); + +#endif diff --git a/controlplane/main.cpp b/controlplane/main.cpp index 7abb8577..bb2a45c2 100644 --- a/controlplane/main.cpp +++ b/controlplane/main.cpp @@ -56,7 +56,7 @@ int main(int argc, return 3; } - sd_notify(0, "READY=1"); +// sd_notify(0, "READY=1"); application.start(); application.join(); diff --git a/controlplane/meson.build b/controlplane/meson.build index f888b09c..6fe171fa 100644 --- a/controlplane/meson.build +++ b/controlplane/meson.build @@ -1,6 +1,6 @@ dependencies = [] dependencies += libjson.get_variable('nlohmann_json_dep') -dependencies += dependency('libsystemd') +#dependencies += dependency('libsystemd') dependencies += dependency('threads') dependencies += libyanet_fwparser_dep dependencies += libyanet_protobuf_dep @@ -31,7 +31,8 @@ sources = files('acl_compiler.cpp', 'rib.cpp', 'route.cpp', 'telegraf.cpp', - 'tun64.cpp') + 'tun64.cpp', + 'libbird.cpp') foreach arch : archs bin = 'yanet-controlplane' diff --git a/controlplane/rib.cpp b/controlplane/rib.cpp index 2576a699..16d0f0cf 100644 --- a/controlplane/rib.cpp +++ b/controlplane/rib.cpp @@ -1,5 +1,8 @@ #include "rib.h" #include "controlplane.h" +#include "libbird.h" + +#include using namespace controlplane::module; @@ -863,3 +866,40 @@ void rib_t::rib_thread() std::this_thread::sleep_for(std::chrono::milliseconds{200}); } } + +void rib_t::bird_import_get() +{ + auto route = controlPlane->getRoute(); + for (auto& [vrf, response] : route) + { + YANET_GCC_BUG_UNUSED(vrf); + auto imports = response.bird_imports; + + for (auto& import : imports) + { + funcThreads.emplace_back([this, import]() { + bird_thread(import.socket, import.vrf); + }); + } + } +} + +void rib_t::bird_thread(const std::string& socket, const std::string& vrf) +{ + YANET_LOG_DEBUG("Run bird thread: socket(%s), vrf(%s)\n", + socket.data(), + vrf.data()); + while (!flagStop) + { + read_bird_feed(socket.c_str(), vrf.c_str(), this); + + common::icp::rib_update::clear request = {"bgp", std::nullopt}; + /* std::get<1>(request) = {peer_address, + {"default", ///< @todo: vrf + YANET_RIB_PRIORITY_DEFAULT}}; + */ + rib_clear(request); + + std::this_thread::sleep_for(std::chrono::milliseconds{200}); + } +} diff --git a/controlplane/rib.h b/controlplane/rib.h index 5013421e..b16bd576 100644 --- a/controlplane/rib.h +++ b/controlplane/rib.h @@ -34,6 +34,8 @@ class rib_t : public cModule common::icp::rib_summary::response rib_summary(); common::icp::rib_prefixes::response rib_prefixes(); + void bird_import_get(); + common::icp::rib_lookup::response rib_lookup(const common::icp::rib_lookup::request& request); common::icp::rib_get::response rib_get(const common::icp::rib_get::request& request); common::icp::rib_save::response rib_save(); @@ -46,6 +48,7 @@ class rib_t : public cModule void rib_eor(const common::icp::rib_update::eor& request); void rib_thread(); + void bird_thread(const std::string& socket, const std::string& vrf); protected: mutable std::mutex rib_update_mutex; diff --git a/dataplane/main.cpp b/dataplane/main.cpp index ec0bba7f..4bb0e26f 100644 --- a/dataplane/main.cpp +++ b/dataplane/main.cpp @@ -67,7 +67,7 @@ int main(int argc, return 3; } - sd_notify(0, "READY=1"); +// sd_notify(0, "READY=1"); dataPlane.start(); dataPlane.join(); diff --git a/dataplane/meson.build b/dataplane/meson.build index 73962ecd..43a2fa2f 100644 --- a/dataplane/meson.build +++ b/dataplane/meson.build @@ -1,7 +1,7 @@ dependencies = [] dependencies += libdpdk.get_variable('dpdk_dep') dependencies += libjson.get_variable('nlohmann_json_dep') -dependencies += dependency('libsystemd') +#dependencies += dependency('libsystemd') dependencies += dependency('threads') sources = files('bus.cpp', diff --git a/logger/main.cpp b/logger/main.cpp index aef83344..dbacd0db 100644 --- a/logger/main.cpp +++ b/logger/main.cpp @@ -320,7 +320,7 @@ int main(int argc, char** argv) return ret; } - sd_notify(0, "READY=1"); + //sd_notify(0, "READY=1"); return runLogger(); } diff --git a/logger/meson.build b/logger/meson.build index c07d93eb..8ba9e5e4 100644 --- a/logger/meson.build +++ b/logger/meson.build @@ -1,7 +1,7 @@ dependencies = [] dependencies += libdpdk.get_variable('dpdk_dep') dependencies += libjson.get_variable('nlohmann_json_dep') -dependencies += dependency('libsystemd') +#dependencies += dependency('libsystemd') dependencies += dependency('threads') sources = files('main.cpp') diff --git a/meson.build b/meson.build index 08c20a68..25d116b3 100644 --- a/meson.build +++ b/meson.build @@ -2,9 +2,7 @@ project('yanet', 'cpp', meson_version: '>= 0.61', default_options: ['cpp_std=c++17', 'buildtype=release', - 'warning_level=2', - 'werror=true', - 'b_lto=true']) + 'warning_level=2']) yanet_rootdir = include_directories('.')