From 1a525e7bb6b9f95a0075ae818bc63226ac219e67 Mon Sep 17 00:00:00 2001 From: Georgy Kirichenko Date: Thu, 6 Jun 2024 22:56:00 +0300 Subject: [PATCH] WIP: bird import proto --- controlplane/acl/bitset.h | 1 + controlplane/configconverter.h | 3 - controlplane/libbird.h | 174 +++++++++++ controlplane/main.cpp | 4 +- controlplane/meson.build | 2 +- controlplane/rib.cpp | 520 ++++++++++++++++++++++++++++++++- dataplane/main.cpp | 4 +- dataplane/meson.build | 2 +- librib/libbird.h | 174 +++++++++++ librib/libyabird.cpp | 414 +++++++++++++++++++++++++- logger/main.cpp | 4 +- logger/meson.build | 2 +- meson.build | 9 +- 13 files changed, 1290 insertions(+), 23 deletions(-) create mode 100644 controlplane/libbird.h create mode 100644 librib/libbird.h diff --git a/controlplane/acl/bitset.h b/controlplane/acl/bitset.h index 0b6ff6c9..a0311c5b 100644 --- a/controlplane/acl/bitset.h +++ b/controlplane/acl/bitset.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include diff --git a/controlplane/configconverter.h b/controlplane/configconverter.h index 12c2da88..56806994 100644 --- a/controlplane/configconverter.h +++ b/controlplane/configconverter.h @@ -8,7 +8,6 @@ class config_converter_t config_converter_t(cControlPlane* controlplane, const controlplane::base_t& baseNext, const common::idp::limits::response& limits) : - controlplane(controlplane), baseNext(baseNext), limits(limits) { @@ -64,8 +63,6 @@ class config_converter_t void acl_rules_balancer_icmp_forward(controlplane::base::acl_t& acl, const std::string& nextModule) const; private: - cControlPlane* controlplane; - controlplane::base_t baseNext; common::idp::updateGlobalBase::request globalbase; common::idp::limits::response limits; diff --git a/controlplane/libbird.h b/controlplane/libbird.h new file mode 100644 index 00000000..38122a2c --- /dev/null +++ b/controlplane/libbird.h @@ -0,0 +1,174 @@ +#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; + + + +#endif diff --git a/controlplane/main.cpp b/controlplane/main.cpp index d5288f79..2fb6debf 100644 --- a/controlplane/main.cpp +++ b/controlplane/main.cpp @@ -1,5 +1,5 @@ #include -#include +//#include #include @@ -58,7 +58,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..e2db9b5c 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 diff --git a/controlplane/rib.cpp b/controlplane/rib.cpp index c66e21ed..9f90cb2c 100644 --- a/controlplane/rib.cpp +++ b/controlplane/rib.cpp @@ -1,6 +1,9 @@ #include "rib.h" +#include "libbird.h" #include "controlplane.h" +#include + using namespace controlplane::module; rib_t::rib_t() @@ -862,15 +865,522 @@ void rib_t::rib_load(const common::icp::rib_load::request& request) } } +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 +ipa_is_ip4(ip_addr addr) +{ + return addr.addr[0] == 0 && addr.addr[1] == 0 && addr.addr[2] == 0xffff; +} + +static inline common::ip_address_t +ipa_to_address(ip_addr addr) +{ + if (ipa_is_ip4(addr)) + return common::ip_address_t(4, (uint8_t *)&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::ip_address_t(6, (uint8_t *)&addr); +} + + void rib_t::rib_thread() { - while (!flagStop) +/* + int bird_sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un server_addr; + server_addr.sun_family = AF_UNIX; + strcpy(server_addr.sun_path, "/tmp/export.sock"); + if (connect(bird_sock, + (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) { + // FIXME + } +*/ + int bird_sock = open("/bird.dump", O_RDONLY); + + size_t buf_size = 1 << 20; + void *read_buf = malloc(buf_size); + if (read_buf == NULL) { + // FIXME + } + size_t read_pos = 0; + size_t parse_pos = 0; + + for (;;) { - if (need_flushing) - { - rib_flush(); + ssize_t readen = read(bird_sock, (void *)((uintptr_t)read_buf + read_pos), buf_size - read_pos); + if (readen < 0) { + // FIXME + break; } + if (readen == 0) { + break; + } + if (readen > 0) { + read_pos += readen; + while (parse_pos < read_pos) { + uintptr_t pos = (uintptr_t)read_buf + parse_pos; + uintptr_t end = (uintptr_t)read_buf + read_pos; + + uintptr_t route_end; + if (!decode_chunk(&pos, end, &route_end)) + break; + + 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; + + net_addr_union addr; + if (!decode_net_addr(&pos, route_end, &addr)) + break; - std::this_thread::sleep_for(std::chrono::milliseconds{200}); + switch (addr.n.type) { + case NET_IP4: { + + break; + } + + case NET_IP6: { + + break; + } + + case NET_VPN4: { + prefix = common::ip_prefix_t(common::ipv4_address_t(ntohl(addr.vpn4.prefix)), addr.vpn4.pxlen); + if ((addr.vpn4.rd >> 48) == 1) { + vpnDST = common::ip_address_t(common::ipv4_address_t(ntohl(addr.vpn4.rd >> 16))); +// vpnDST = ip_address_t(ipv4_address_t(ntohl((uint32_t)(addr.vpn4.rd >> 16))); + vpnRD = addr.vpn4.rd & 0xffff; + } else { + //FIXME: chaos corruption, exterminate! + return; + } + break; + } + + case NET_VPN6: { + prefix = common::ip_prefix_t(common::ipv6_address_t((uint8_t *)addr.vpn6.prefix.addr), addr.vpn6.pxlen); + if ((addr.vpn6.rd >> 48) == 1) { +// vpnDST = ip_address_t(ipv4_address_t(ntohl((uint32_t)(addr.vpn6.rd >> 16))); + vpnRD = addr.vpn6.rd & 0xffff; + } else { + //FIXME: chaos corruption, exterminate! + return; + } + break; + } + default: + //FIXME chaos corruption, exterminate! + return; + } + + uint32_t type; + if (!decode_u32(&pos, route_end, &type)) + break; + + ip_addr remote_addr; + if (!decode_ip_addr(&pos, route_end, &remote_addr)) + break; + peer_address = ipa_to_address(remote_addr); + fprintf(stderr, "PEER %s\n", peer_address.toString().c_str()); + + size_t attrs_end; + if (!decode_chunk(&pos, route_end, &attrs_end)) + break; + + if (attrs_end != route_end) + break; + + while (pos < attrs_end) { + uint32_t attr_id; + if (!decode_u32(&pos, attrs_end, &attr_id)) + break; + +fprintf(stderr, "PTH %u %lu\n", attr_id, attrs_end - pos); + + switch (EA_ID(attr_id)) { + + case BA_ORIGIN: { + uint32_t origin; + if (!decode_u32(&pos, attrs_end, &origin)) { + return; + //FIXME + } + 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_AS_PATH: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint8_t segment_type; + if (!decode_u8(&pos, attr_end, &segment_type)) { + return; + //FIXME: corrupted stream + } + + if (segment_type != 2 && segment_type != 3) { + return; + //FIXME: unsupported segment type + } + uint8_t segment_len; + if (!decode_u8(&pos, attr_end, &segment_len)) { + return; + //FIXME: corrupted stream + } + + for (uint8_t idx = 0; idx < segment_len; ++idx) { + uint32_t as; + if (!decode_u32(&pos, attr_end, &as)) { + return; + //FIXME: corrupted stream + } + as = ntohl(as); + attribute_aspath.emplace_back(as); + } + } + + break; + } + + case BA_NEXT_HOP: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + if (attr_end - pos != sizeof(ip_addr) && attr_end - pos != 2 * sizeof(ip_addr)) { + return; + //FIXME: corrupted stream + } + if (attr_end - pos == sizeof(ip_addr)) { + ip_addr nh_addr; + if (!decode_ip_addr(&pos, attr_end, &nh_addr)) { + return; + //FIXME: corrupted stream + } + next_hop = ipa_to_address(nh_addr); + + } else { + ip_addr nh_addr1; + ip_addr nh_addr2; + if (!decode_ip_addr(&pos, attr_end, &nh_addr1) || + !decode_ip_addr(&pos, attr_end, &nh_addr2)) { + return; + //FIXME: corrupted stream + } + + 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); + } + } + fprintf(stderr, "NEXTH %s\n", next_hop.toString().c_str()); + + break; + } + + case BA_MULTI_EXIT_DISC: { + uint32_t med; + if (!decode_u32(&pos, attrs_end, &med)) { + return; + //FIXME: corrupted stream + } + + attribute_med = med; + + break; + } + + case BA_LOCAL_PREF: { + uint32_t pref; + if (!decode_u32(&pos, attrs_end, &pref)) { + return; + //FIXME: corrupted stream + } + + attribute_local_preference = pref; + + break; + } + + case BA_COMMUNITY: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint16_t first; + uint16_t second; + if (!decode_u16(&pos, attr_end, &first) || + !decode_u16(&pos, attr_end, &second)) { + return; + //FIXME: corrupted stream + } + + attribute_communities.emplace(first, second); + } + + + break; + } + + case BA_ORIGINATOR_ID: { + uint32_t originator; + if (!decode_u32(&pos, attrs_end, &originator)) { + return; + //FIXME: corrupted stream + } + + break; + } + + case BA_CLUSTER_LIST: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t cluster; + if (!decode_u32(&pos, attr_end, &cluster)) { + //FIXME: corrupted stream + return; + } + } + + break; + } + + case BA_EXT_COMMUNITY: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t community; + if (!decode_u32(&pos, attr_end, &community)) { + //FIXME: corrupted stream + return; + } + } + + break; + + } + + case BA_LARGE_COMMUNITY: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + return; + } + + while (pos < attr_end) { + uint32_t first; + uint32_t second; + uint32_t third; + if (!decode_u32(&pos, attr_end, &first) || + !decode_u32(&pos, attr_end, &second) || + !decode_u32(&pos, attr_end, &third)) { + //FIXME: corrupted stream + return; + } + + attribute_large_communities.emplace(first, second, third); + } + + break; + } + + + case BA_MPLS_LABEL_STACK: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + return; + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t label; + if (!decode_u32(&pos, attr_end, &label)) { + //FIXME: corrupted stream + return; + } + + labels.emplace_back(label); + } + + + break; + } + + default: + // chaos corruption, exterminate! + return; + + } + } + + parse_pos = pos; + + if (type == 1) { + common::icp::rib_update::insert request = {"bgp", + "default", ///< @todo: vrf + YANET_RIB_PRIORITY_DEFAULT, + {}}; + + auto& announce = std::get<3>(request)[{peer_address, + attribute_origin, + attribute_med, + attribute_aspath, + attribute_communities, + attribute_large_communities, + attribute_local_preference}]; + + //FIXME: table name + auto& announce_table = announce["afi safi"]; + announce_table[next_hop].emplace_back(prefix, std::to_string(vpnRD), labels); + rib_insert(request); + + } else { + + } + + } + + if (buf_size - read_pos < 1 << 12) { + memmove(read_buf, (void *)((uintptr_t)read_buf + parse_pos), read_pos - parse_pos); + read_pos = read_pos - parse_pos; + parse_pos = 0; + } + } + + rib_flush(); } + + + } diff --git a/dataplane/main.cpp b/dataplane/main.cpp index e88d5ab3..aeec9503 100644 --- a/dataplane/main.cpp +++ b/dataplane/main.cpp @@ -1,5 +1,5 @@ #include -#include +//#include #include @@ -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 f3599582..af1ba5d0 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/librib/libbird.h b/librib/libbird.h new file mode 100644 index 00000000..38122a2c --- /dev/null +++ b/librib/libbird.h @@ -0,0 +1,174 @@ +#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; + + + +#endif diff --git a/librib/libyabird.cpp b/librib/libyabird.cpp index abc464f0..609b3799 100644 --- a/librib/libyabird.cpp +++ b/librib/libyabird.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -12,6 +13,8 @@ #include "libyabird.h" +#include "libbird.h" + #define YANET_LOG_PATH "/var/log/yanet-bird.log" common::log::LogPriority common::log::logPriority = common::log::TLOG_DEBUG; @@ -351,12 +354,419 @@ void libyabird_t::flush() controlPlane.rib_update(rib_request); } +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 false; +} + +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 false; +} + +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 +ipa_is_ip4(ip_addr addr) +{ + return addr.addr[0] == 0 && addr.addr[1] == 0 && addr.addr[2] == 0xffff; +} + +static inline common::ip_address_t +ipa_to_address(ip_addr addr) +{ + if (ipa_is_ip4(addr)) + return common::ip_address_t(4, (uint8_t *)&addr); + return common::ip_address_t(6, (uint8_t *)&addr); +} + void libyabird_t::worker_proc() { + int bird_sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un server_addr; + server_addr.sun_family = AF_UNIX; + strcpy(server_addr.sun_path, "/tmp/export.sock"); + if (connect(bird_sock, + (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) { + // FIXME + } + + size_t buf_size = 1 << 20; + void *read_buf = malloc(buf_size); + if (read_buf == NULL) { + // FIXME + } + size_t read_pos = 0; + size_t parse_pos = 0; + + const common::icp::rib_update::request requests; + for (;;) { - flush(); - std::this_thread::sleep_for(std::chrono::milliseconds{100}); + ssize_t readen = read(bird_sock, (void *)((uintptr_t)read_buf + read_pos), buf_size - read_pos); + if (readen < 0) { + // FIXME + break; + } + if (readen == 0) { + break; + } + if (readen > 0) { + read_pos += readen; + while (parse_pos < read_pos) { + uintptr_t pos = (uintptr_t)read_buf + parse_pos; + uintptr_t end = (uintptr_t)read_buf + read_pos; + + uintptr_t route_end; + if (!decode_chunk(&pos, end, &route_end)) + break; + + 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; + + net_addr_union addr; + if (!decode_net_addr(&pos, end, &addr)) + break; + + uint32_t type; + if (!decode_u32(&pos, route_end, &type)) + break; + + ip_addr remote_addr; + if (!decode_ip_addr(&pos, end, &remote_addr)) + break; + peer_address = ipa_to_address(remote_addr); + + size_t attrs_end; + if (!decode_chunk(&pos, route_end, &attrs_end)) + break; + + if (attrs_end != route_end) + break; + + while (pos < attrs_end) { + uint32_t attr_id; + if (!decode_u32(&pos, attrs_end, &attr_id)) + break; + + switch (attr_id) { + + case BA_ORIGIN: { + uint32_t origin; + if (!decode_u32(&pos, attrs_end, &origin)) { + //FIXME + } + 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_AS_PATH: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t segment_type; + if (!decode_u32(&pos, attr_end, &segment_type)) { + //FIXME: corrupted stream + } + + if (segment_type != 2 && segment_type != 3) { + //FIXME: unsupported segment type + } + + uintptr_t segment_end; + if (!decode_u32_array(&pos, attr_end, &segment_end)) { + //FIXME: corrupted stream + } + + while (pos < segment_end) { + uint32_t as; + if (!decode_u32(&pos, segment_end, &as)) { + //FIXME: corrupted stream + } + attribute_aspath.emplace_back(as); + } + } + + break; + } + + case BA_NEXT_HOP: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + if (attr_end - pos != sizeof(ip_addr) && attr_end - pos != 2 * sizeof(ip_addr)) { + //FIXME: corrupted stream + } + if (attr_end - pos == sizeof(ip_addr)) { + ip_addr addr; + if (!decode_ip_addr(&pos, attr_end, &addr)) { + //FIXME: corrupted stream + } + + } else { + ip_addr addr1; + ip_addr addr2; + if (!decode_ip_addr(&pos, attr_end, &addr1) || + !decode_ip_addr(&pos, attr_end, &addr2)) { + //FIXME: corrupted stream + } + + if (addr2.addr[0] == 0 && addr2.addr[1] == 0 && + addr2.addr[2] == 0 && addr2.addr[3] == 0) { + next_hop = ipa_to_address(addr1); + } else { + next_hop = ipa_to_address(addr2); + } + } + + break; + } + + case BA_MULTI_EXIT_DISC: { + uint32_t med; + if (!decode_u32(&pos, attrs_end, &med)) { + //FIXME: corrupted stream + } + + attribute_med = med; + + break; + } + + case BA_LOCAL_PREF: { + uint32_t pref; + if (!decode_u32(&pos, attrs_end, &pref)) { + //FIXME: corrupted stream + } + + attribute_local_preference = pref; + + break; + } + + case BA_COMMUNITY: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint16_t first; + uint16_t second; + if (!decode_u16(&pos, attr_end, &first) || + !decode_u16(&pos, attr_end, &second)) { + //FIXME: corrupted stream + } + + attribute_communities.emplace(first, second); + } + + + break; + } + + case BA_ORIGINATOR_ID: { + uint32_t originator; + if (!decode_u32(&pos, attrs_end, &originator)) { + //FIXME: corrupted stream + } + + break; + } + + case BA_CLUSTER_LIST: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t cluster; + if (!decode_u32(&pos, attr_end, &cluster)) { + //FIXME: corrupted stream + } + } + + break; + } + + case BA_LARGE_COMMUNITY: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t first; + uint32_t second; + uint32_t third; + if (!decode_u32(&pos, attr_end, &first) || + !decode_u32(&pos, attr_end, &second) || + !decode_u32(&pos, attr_end, &third)) { + //FIXME: corrupted stream + } + + attribute_large_communities.emplace(first, second, third); + } + + break; + } + + + case BA_MPLS_LABEL_STACK: { + size_t attr_end; + if (!decode_chunk(&pos, attrs_end, &attr_end)) { + //FIXME: corrupted stream + } + + while (pos < attr_end) { + uint32_t label; + if (!decode_u32(&pos, attr_end, &label)) { + //FIXME: corrupted stream + } + + labels.emplace_back(label); + } + + + break; + } + + } + } + + parse_pos = pos; + + if (type == 1) { + common::icp::rib_update::insert request = {"bgp", + "default", ///< @todo: vrf + YANET_RIB_PRIORITY_DEFAULT, + {}}; + + auto& announce = std::get<3>(request)[{peer_address, + attribute_origin, + attribute_med, + attribute_aspath, + attribute_communities, + attribute_large_communities, + attribute_local_preference}]; + + //FIXME: table name + auto& announce_table = announce["afi safi"]; + announce_table[next_hop].emplace_back(prefix, std::to_string(addr.vpn4.rd), labels); + + } else { + + } + + } + + if (buf_size - read_pos < 1 << 12) { + memmove(read_buf, (void *)((uintptr_t)read_buf + parse_pos), read_pos - parse_pos); + read_pos = read_pos - parse_pos; + parse_pos = 0; + } + flush(); + } + + if (requests.size() > 0) { + +//FIXME + } + +// flush(); +// std::this_thread::sleep_for(std::chrono::milliseconds{100}); } } diff --git a/logger/main.cpp b/logger/main.cpp index 1492ee98..051468c1 100644 --- a/logger/main.cpp +++ b/logger/main.cpp @@ -90,7 +90,7 @@ int runLogger() interface::controlPlane controlplane; - uint32_t size = 1024; + const uint32_t size = 1024; samples::sample_t* samples[size]; std::map configs; @@ -318,7 +318,7 @@ int main(int argc, 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 1e603e71..6f9244da 100644 --- a/meson.build +++ b/meson.build @@ -3,15 +3,15 @@ project('yanet', 'cpp', default_options: ['cpp_std=c++17', 'buildtype=release', 'warning_level=2', - 'werror=true', - 'b_lto=true']) + 'werror=true']) yanet_rootdir = include_directories('.') if get_option('buildtype').contains('release') - add_global_arguments('-Ofast', language: 'cpp') + add_global_arguments('-O0', language: 'cpp') endif +add_global_arguments('-g', language: 'cpp') add_global_arguments('-DYANET_VERSION_MAJOR=' + get_option('version_major').to_string(), language: 'cpp') add_global_arguments('-DYANET_VERSION_MINOR=' + get_option('version_minor').to_string(), language: 'cpp') @@ -28,7 +28,8 @@ libdpdk = subproject('dpdk', default_options: [ 'cpu_instruction_set=corei7', 'disable_apps=dumpcap,graph,pdump,proc-info,test-acl,test-bbdev,test-cmdline,test-compress-perf,test-crypto-perf,test-dma-perf,test-eventdev,test-fib,test-flow-perf,test-gpudev,test-mldev,test-pipeline,test-pmd,test-regex,test-sad,test-security-perf', 'disable_libs=bitratestats,cfgfile,flow_classify,gpudev,gro,gso,kni,jobstats,latencystats,metrics,node,pdump,pipeline,port,power,table,vhost', - 'enable_driver_sdk=true', 'disable_drivers=net/mlx4', + 'enable_drivers=bus/pci,bus/auxiliary,net/virtio,common/iavf,net/ice,net/ring', + 'enable_driver_sdk=true', 'disable_drivers=net/mlx4,net/ena', 'default_library=static', 'tests=false' ] ) libjson = subproject('json')