From bfbf0c345b75a145dc8fba47d8b353901796edab Mon Sep 17 00:00:00 2001 From: Istvan Ruzman Date: Wed, 30 Nov 2022 10:29:26 +0100 Subject: [PATCH 01/27] fix: build error with dpdk due to redefines bngblaster used the same defines as some dpdk headers. This caused a redifine warning, which got promoted to an error (cause of the -Werror flag). Solution: change the defines to have a BBL_ prefix --- code/bngblaster/src/bbl_protocols.c | 6 +++--- code/bngblaster/src/bbl_protocols.h | 6 +++--- code/bngblaster/src/io/io_packet_mmap.c | 2 +- code/bngblaster/src/io/io_thread.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/bngblaster/src/bbl_protocols.c b/code/bngblaster/src/bbl_protocols.c index e56369d6..2fff7787 100644 --- a/code/bngblaster/src/bbl_protocols.c +++ b/code/bngblaster/src/bbl_protocols.c @@ -3932,7 +3932,7 @@ decode_ethernet(uint8_t *buf, uint16_t len, } eth->vlan_outer_priority = *buf >> 5; eth->vlan_outer = be16toh(*(uint16_t*)buf); - eth->vlan_outer &= ETH_VLAN_ID_MAX; + eth->vlan_outer &= BBL_ETH_VLAN_ID_MAX; BUMP_BUFFER(buf, len, sizeof(uint16_t)); eth->type = *(uint16_t*)buf; @@ -3943,7 +3943,7 @@ decode_ethernet(uint8_t *buf, uint16_t len, } eth->vlan_inner_priority = *buf >> 5; eth->vlan_inner = be16toh(*(uint16_t*)buf); - eth->vlan_inner &= ETH_VLAN_ID_MAX; + eth->vlan_inner &= BBL_ETH_VLAN_ID_MAX; BUMP_BUFFER(buf, len, sizeof(uint16_t)); eth->type = *(uint16_t*)buf; BUMP_BUFFER(buf, len, sizeof(uint16_t)); @@ -3952,7 +3952,7 @@ decode_ethernet(uint8_t *buf, uint16_t len, return DECODE_ERROR; } eth->vlan_three = be16toh(*(uint16_t*)buf); - eth->vlan_three &= ETH_VLAN_ID_MAX; + eth->vlan_three &= BBL_ETH_VLAN_ID_MAX; BUMP_BUFFER(buf, len, sizeof(uint16_t)); eth->type = *(uint16_t*)buf; BUMP_BUFFER(buf, len, sizeof(uint16_t)); diff --git a/code/bngblaster/src/bbl_protocols.h b/code/bngblaster/src/bbl_protocols.h index 0aaff8b2..12ec7058 100644 --- a/code/bngblaster/src/bbl_protocols.h +++ b/code/bngblaster/src/bbl_protocols.h @@ -87,8 +87,8 @@ #define NB_ETH_TYPE_MPLS 0x8847 #endif -#define ETH_VLAN_ID_MAX 4095 -#define ETH_VLAN_PBIT_MAX 7 +#define BBL_ETH_VLAN_ID_MAX 4095 +#define BBL_ETH_VLAN_PBIT_MAX 7 #define ETH_IEEE_802_3_MAX_LEN 1500 @@ -953,4 +953,4 @@ protocol_error_t encode_ethernet(uint8_t *buf, uint16_t *len, bbl_ethernet_header_s *eth); -#endif \ No newline at end of file +#endif diff --git a/code/bngblaster/src/io/io_packet_mmap.c b/code/bngblaster/src/io/io_packet_mmap.c index dcc53946..587f38d5 100644 --- a/code/bngblaster/src/io/io_packet_mmap.c +++ b/code/bngblaster/src/io/io_packet_mmap.c @@ -72,7 +72,7 @@ io_packet_mmap_rx_job(timer_s *timer) io->stats.bytes += io->buf_len; decode_result = decode_ethernet(io->buf, io->buf_len, g_ctx->sp, SCRATCHPAD_LEN, ð); if(decode_result == PROTOCOL_SUCCESS) { - vlan = tphdr->tp_vlan_tci & ETH_VLAN_ID_MAX; + vlan = tphdr->tp_vlan_tci & BBL_ETH_VLAN_ID_MAX; if(vlan && eth->vlan_outer != vlan) { /* The outer VLAN is stripped from header */ eth->vlan_inner = eth->vlan_outer; diff --git a/code/bngblaster/src/io/io_thread.c b/code/bngblaster/src/io/io_thread.c index 423e9d5e..fcc8426e 100644 --- a/code/bngblaster/src/io/io_thread.c +++ b/code/bngblaster/src/io/io_thread.c @@ -66,7 +66,7 @@ io_thread_rx_handler(io_thread_s *thread, io_handle_s *io) /** Process */ decode_result = decode_ethernet(io->buf, io->buf_len, thread->sp, SCRATCHPAD_LEN, ð); if(decode_result == PROTOCOL_SUCCESS) { - vlan = io->vlan_tci & ETH_VLAN_ID_MAX; + vlan = io->vlan_tci & BBL_ETH_VLAN_ID_MAX; if(eth->vlan_outer != vlan) { /* The outer VLAN is stripped from header */ eth->vlan_inner = eth->vlan_outer; @@ -114,7 +114,7 @@ io_thread_main_rx_job(timer_s *timer) while((slot = bbl_txq_read_slot(thread->txq))) { decode_result = decode_ethernet(slot->packet, slot->packet_len, g_ctx->sp, SCRATCHPAD_LEN, ð); if(decode_result == PROTOCOL_SUCCESS) { - vlan = slot->vlan_tci & ETH_VLAN_ID_MAX; + vlan = slot->vlan_tci & BBL_ETH_VLAN_ID_MAX; if(vlan && eth->vlan_outer != vlan) { /* Restore outer VLAN */ eth->vlan_inner = eth->vlan_outer; @@ -337,4 +337,4 @@ io_thread_stop_all() pthread_join(thread->thread, NULL); thread = thread->next; } -} \ No newline at end of file +} From 89a8ef44a0b885377aa50b903a5506be0b1c4448 Mon Sep 17 00:00:00 2001 From: Istvan Ruzman Date: Tue, 29 Nov 2022 11:43:08 +0100 Subject: [PATCH 02/27] Improve IPv6 Gateway resolution The previous implementation just checked wether the Neighbor Advertisment is from the gateway. This does not work in all cases. To correctly resolve the the IPv6 Gateway this implementation checks received Advertisments if they include the expected Gateway and uses the MAC Address from the Link-Layer Destination Option (if included). --- code/bngblaster/src/bbl_network.c | 23 ++++++++++++++++------- code/bngblaster/src/bbl_protocols.c | 27 ++++++++++++++++++++++++++- code/bngblaster/src/bbl_protocols.h | 2 ++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/code/bngblaster/src/bbl_network.c b/code/bngblaster/src/bbl_network.c index 4becdbd8..3d23e93c 100644 --- a/code/bngblaster/src/bbl_network.c +++ b/code/bngblaster/src/bbl_network.c @@ -7,6 +7,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include "bbl.h" +#include "bbl_protocols.h" #include "bbl_session.h" #include "bbl_stream.h" @@ -309,6 +310,7 @@ bbl_network_rx_arp(bbl_network_interface_s *interface, bbl_ethernet_header_s *et static void bbl_network_rx_icmpv6(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth) { + uint8_t *gw_mac; bbl_ipv6_s *ipv6; bbl_icmpv6_s *icmpv6; bbl_secondary_ip6_s *secondary_ip6; @@ -316,13 +318,20 @@ bbl_network_rx_icmpv6(bbl_network_interface_s *interface, ipv6 = (bbl_ipv6_s*)eth->next; icmpv6 = (bbl_icmpv6_s*)ipv6->next; - if(memcmp(ipv6->src, interface->gateway6, IPV6_ADDR_LEN) == 0) { - interface->icmpv6_nd_resolved = true; - if(*(uint32_t*)interface->gateway_mac == 0) { - memcpy(interface->gateway_mac, eth->src, ETH_ADDR_LEN); + + if(icmpv6->type == IPV6_ICMPV6_NEIGHBOR_ADVERTISEMENT) { + if(memcmp(icmpv6->prefix.address, interface->gateway6, IPV6_ADDR_LEN) == 0) { + interface->icmpv6_nd_resolved = true; + if(*(uint32_t*)interface->gateway_mac == 0) { + if(icmpv6->dst_mac == NULL) { + gw_mac = eth->src; + } else { + gw_mac = icmpv6->dst_mac; + } + memcpy(interface->gateway_mac, gw_mac, ETH_ADDR_LEN); + } } - } - if(icmpv6->type == IPV6_ICMPV6_NEIGHBOR_SOLICITATION) { + } else if(icmpv6->type == IPV6_ICMPV6_NEIGHBOR_SOLICITATION) { if(memcmp(icmpv6->prefix.address, interface->ip6.address, IPV6_ADDR_LEN) == 0) { bbl_network_icmpv6_na(interface, eth, ipv6, icmpv6); } else if(memcmp(icmpv6->prefix.address, interface->ip6_ll, IPV6_ADDR_LEN) == 0) { @@ -487,4 +496,4 @@ bbl_network_ctrl_interfaces(int fd, uint32_t session_id __attribute__((unused)), json_decref(interfaces); } return result; -} \ No newline at end of file +} diff --git a/code/bngblaster/src/bbl_protocols.c b/code/bngblaster/src/bbl_protocols.c index 2fff7787..a2375401 100644 --- a/code/bngblaster/src/bbl_protocols.c +++ b/code/bngblaster/src/bbl_protocols.c @@ -2175,7 +2175,7 @@ decode_icmpv6(uint8_t *buf, uint16_t len, BUMP_BUFFER(buf, len, sizeof(uint8_t)); /* hop limit */ icmpv6->flags = *buf; BUMP_BUFFER(buf, len, 11); - while(len > 2) { + while(len >= 8) { option = *buf; BUMP_BUFFER(buf, len, sizeof(uint8_t)); option_len = *buf; @@ -2202,12 +2202,37 @@ decode_icmpv6(uint8_t *buf, uint16_t len, } break; case IPV6_ICMPV6_NEIGHBOR_SOLICITATION: + if(len < 20) { + return DECODE_ERROR; + } + BUMP_BUFFER(buf, len, sizeof(uint32_t)); /* flags / reserved */ + memcpy(&icmpv6->prefix.address, buf, IPV6_ADDR_LEN); + break; case IPV6_ICMPV6_NEIGHBOR_ADVERTISEMENT: if(len < 20) { return DECODE_ERROR; } BUMP_BUFFER(buf, len, sizeof(uint32_t)); /* flags / reserved */ memcpy(&icmpv6->prefix.address, buf, IPV6_ADDR_LEN); + BUMP_BUFFER(buf, len, IPV6_ADDR_LEN); + while(len >= 8) { + option = *buf; + BUMP_BUFFER(buf, len, sizeof(uint8_t)); + option_len = (*buf) * 8; + BUMP_BUFFER(buf, len, sizeof(uint8_t)); + if(option_len < 2 || len < option_len - 2) { + return DECODE_ERROR; + } + if(option == ICMPV6_OPTION_DEST_LINK_LAYER) { + if(option_len != 8) { + // Maleformed ICMPv6 packet + return DECODE_ERROR; + } + icmpv6->dst_mac = buf; + break; + } + BUMP_BUFFER(buf, len, option_len-2); + } break; default: break; diff --git a/code/bngblaster/src/bbl_protocols.h b/code/bngblaster/src/bbl_protocols.h index 12ec7058..af4fcb40 100644 --- a/code/bngblaster/src/bbl_protocols.h +++ b/code/bngblaster/src/bbl_protocols.h @@ -212,6 +212,7 @@ #define ICMPV6_FLAGS_MANAGED 0x80 #define ICMPV6_FLAGS_OTHER_CONFIG 0x40 +#define ICMPV6_OPTION_DEST_LINK_LAYER 2 #define ICMPV6_OPTION_PREFIX 3 #define ICMPV6_OPTION_DNS 25 @@ -799,6 +800,7 @@ typedef struct bbl_icmpv6_ { uint16_t data_len; ipv6addr_t *dns1; ipv6addr_t *dns2; + uint8_t *dst_mac; } bbl_icmpv6_s; typedef struct bbl_dhcpv6_ { From 6f5979ee2ed02c643d3661961c5e23aef0c64656 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 1 Dec 2022 20:44:07 +0000 Subject: [PATCH 03/27] LDP initial structure --- code/bngblaster/CMakeLists.txt | 2 +- code/bngblaster/src/bbl.c | 17 +- code/bngblaster/src/bbl.h | 2 + code/bngblaster/src/bbl_config.c | 122 +++++++++++-- code/bngblaster/src/bbl_config.h | 2 + code/bngblaster/src/bbl_ctx.h | 4 + code/bngblaster/src/bbl_def.h | 1 + code/bngblaster/src/bbl_network.c | 56 ++++-- code/bngblaster/src/bbl_network.h | 5 + code/bngblaster/src/bbl_protocols.c | 202 ++++++++++++++++++++-- code/bngblaster/src/bbl_protocols.h | 13 +- code/bngblaster/src/bbl_tx.c | 3 + code/bngblaster/src/bgp/bgp_ctrl.c | 4 +- code/bngblaster/src/bgp/bgp_def.h | 6 +- code/bngblaster/src/bgp/bgp_message.c | 2 +- code/bngblaster/src/bgp/bgp_receive.c | 14 +- code/bngblaster/src/bgp/bgp_session.c | 8 +- code/bngblaster/src/isis/isis.c | 6 +- code/bngblaster/src/isis/isis_adjacency.c | 2 +- code/bngblaster/src/isis/isis_csnp.c | 3 +- code/bngblaster/src/isis/isis_ctrl.c | 4 +- code/bngblaster/src/isis/isis_def.h | 12 +- code/bngblaster/src/isis/isis_lsp.c | 1 + code/bngblaster/src/isis/isis_p2p_hello.c | 23 +-- code/bngblaster/src/isis/isis_psnp.c | 3 +- code/bngblaster/src/isis/isis_utils.c | 2 +- code/bngblaster/src/isis/isis_utils.h | 2 +- code/bngblaster/src/ldp/ldp.c | 63 +++++++ code/bngblaster/src/ldp/ldp.h | 24 +++ code/bngblaster/src/ldp/ldp_def.h | 201 +++++++++++++++++++++ code/bngblaster/src/ldp/ldp_hello.c | 106 ++++++++++++ code/bngblaster/src/ldp/ldp_hello.h | 26 +++ code/bngblaster/src/ldp/ldp_interface.c | 49 ++++++ code/bngblaster/src/ldp/ldp_interface.h | 17 ++ code/bngblaster/src/ldp/ldp_pdu.c | 9 + code/bngblaster/src/ldp/ldp_pdu.h | 12 ++ code/bngblaster/src/ldp/ldp_receive.c | 176 +++++++++++++++++++ code/common/src/logging.h | 1 + docsrc/sources/configuration/bgp.rst | 4 +- docsrc/sources/configuration/isis.rst | 4 +- docsrc/sources/configuration/ldp.rst | 33 ++++ docsrc/sources/quickstart.rst | 6 +- docsrc/sources/routing/index.rst | 3 +- docsrc/sources/routing/ldp.rst | 62 +++++++ 44 files changed, 1219 insertions(+), 98 deletions(-) create mode 100644 code/bngblaster/src/ldp/ldp.c create mode 100644 code/bngblaster/src/ldp/ldp.h create mode 100644 code/bngblaster/src/ldp/ldp_def.h create mode 100644 code/bngblaster/src/ldp/ldp_hello.c create mode 100644 code/bngblaster/src/ldp/ldp_hello.h create mode 100644 code/bngblaster/src/ldp/ldp_interface.c create mode 100644 code/bngblaster/src/ldp/ldp_interface.h create mode 100644 code/bngblaster/src/ldp/ldp_pdu.c create mode 100644 code/bngblaster/src/ldp/ldp_pdu.h create mode 100644 code/bngblaster/src/ldp/ldp_receive.c create mode 100644 docsrc/sources/configuration/ldp.rst create mode 100644 docsrc/sources/routing/ldp.rst diff --git a/code/bngblaster/CMakeLists.txt b/code/bngblaster/CMakeLists.txt index c4834c34..c8ecab55 100644 --- a/code/bngblaster/CMakeLists.txt +++ b/code/bngblaster/CMakeLists.txt @@ -1,4 +1,4 @@ -FILE(GLOB BBL_SOURCES src/*.c src/io/*.c src/isis/*.c src/bgp/*.c) +FILE(GLOB BBL_SOURCES src/*.c src/io/*.c src/isis/*.c src/ldp/*.c src/bgp/*.c) list(SORT BBL_SOURCES) # Deterministic randomness for symbol name creation diff --git a/code/bngblaster/src/bbl.c b/code/bngblaster/src/bbl.c index c5bd3870..bd0ecc78 100644 --- a/code/bngblaster/src/bbl.c +++ b/code/bngblaster/src/bbl.c @@ -23,16 +23,15 @@ bbl_ctx_s *g_ctx = NULL; /* Global Variables */ -bool g_interactive = false; /* interactive mode using ncurses */ - -uint8_t g_log_buf_cur = 0; -char *g_log_buf = NULL; - +bool g_interactive = false; /* interactive mode using ncurses */ bool g_init_phase = true; bool g_traffic = true; bool g_banner = true; bool g_monkey = true; +uint8_t g_log_buf_cur = 0; +char *g_log_buf = NULL; + extern char *g_log_file; volatile bool g_teardown = false; volatile bool g_teardown_request = false; @@ -152,6 +151,7 @@ struct keyval_ log_names[] = { { L2TP, "l2tp" }, { DHCP, "dhcp" }, { ISIS, "isis" }, + { LDP, "ldp" }, { BGP, "bgp" }, { TCP, "tcp" }, { LAG, "lag" }, @@ -293,6 +293,7 @@ bbl_ctrl_job(timer_s *timer) } /* Teardown routing protocols. */ isis_teardown(); + ldp_teardown(); bgp_teardown(); g_teardown_request = false; } else { @@ -549,6 +550,12 @@ main(int argc, char *argv[]) goto CLEANUP; } + /* Init LDP instances. */ + if(!ldp_init()) { + fprintf(stderr, "Error: Failed to init LDP\n"); + goto CLEANUP; + } + /* Init interfaces. */ if(!bbl_interface_init()) { fprintf(stderr, "Error: Failed to init interfaces\n"); diff --git a/code/bngblaster/src/bbl.h b/code/bngblaster/src/bbl.h index 082b7160..4d32822a 100644 --- a/code/bngblaster/src/bbl.h +++ b/code/bngblaster/src/bbl.h @@ -27,6 +27,7 @@ #include "io/io_def.h" #include "bgp/bgp_def.h" #include "isis/isis_def.h" +#include "ldp/ldp_def.h" #include "bbl_ctrl.h" #include "bbl_stats.h" @@ -49,6 +50,7 @@ #include "io/io.h" #include "bgp/bgp.h" #include "isis/isis.h" +#include "ldp/ldp.h" extern bbl_ctx_s *g_ctx; extern WINDOW *log_win; diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index 86775843..f2bb2aba 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -635,6 +635,13 @@ json_parse_network_interface(json_t *network_interface, bbl_network_config_s *ne network_config->isis_l2_metric = 10; } } + + /* LDP interface configuration */ + value = json_object_get(network_interface, "ldp-instance-id"); + if(json_is_number(value)) { + network_config->ldp_instance_id = json_number_value(value); + } + return true; } @@ -1068,11 +1075,11 @@ json_parse_bgp_config(json_t *bgp, bgp_config_s *bgp_config) bgp_config->peer_as = bgp_config->local_as; } - value = json_object_get(bgp, "holdtime"); + value = json_object_get(bgp, "hold-time"); if(value) { - bgp_config->holdtime = json_number_value(value); + bgp_config->hold_time = json_number_value(value); } else { - bgp_config->holdtime = BGP_DEFAULT_HOLDTIME; + bgp_config->hold_time = BGP_DEFAULT_HOLD_TIME; } bgp_config->id = htobe32(0x01020304); @@ -1191,11 +1198,11 @@ json_parse_isis_config(json_t *isis, isis_config_s *isis_config) isis_config->hello_padding = json_boolean_value(value); } - value = json_object_get(isis, "holding-time"); + value = json_object_get(isis, "hold-time"); if(json_is_number(value)) { - isis_config->holding_time = json_number_value(value); + isis_config->hold_time = json_number_value(value); } else { - isis_config->holding_time = ISIS_DEFAULT_HOLDING_TIME; + isis_config->hold_time = ISIS_DEFAULT_HOLD_TIME; } value = json_object_get(isis, "lsp-lifetime"); @@ -1358,6 +1365,72 @@ json_parse_isis_config(json_t *isis, isis_config_s *isis_config) return true; } +static bool +json_parse_ldp_config(json_t *ldp, ldp_config_s *ldp_config) +{ + json_t *value = NULL; + const char *s = NULL; + + value = json_object_get(ldp, "instance-id"); + if(value) { + ldp_config->id = json_number_value(value); + } else { + fprintf(stderr, "JSON config error: Missing value for ldp->instance-id\n"); + return false; + } + + value = json_object_get(ldp, "overload"); + if(json_is_boolean(value)) { + ldp_config->overload = json_boolean_value(value); + } + + value = json_object_get(ldp, "hello-interval"); + if(json_is_number(value)) { + ldp_config->hello_interval = json_number_value(value); + } else { + ldp_config->hello_interval = LDP_DEFAULT_HELLO_INTERVAL; + } + + value = json_object_get(ldp, "hold-time"); + if(json_is_number(value)) { + ldp_config->hold_time = json_number_value(value); + } else { + ldp_config->hold_time = LDP_DEFAULT_HOLD_TIME; + } + + value = json_object_get(ldp, "teardown-time"); + if(json_is_number(value)) { + ldp_config->teardown_time = json_number_value(value); + } else { + ldp_config->teardown_time = LDP_DEFAULT_TEARDOWN_TIME; + } + + if(json_unpack(ldp, "{s:s}", "hostname", &s) == 0) { + ldp_config->hostname = strdup(s); + } else { + ldp_config->hostname = g_default_hostname; + } + + if(json_unpack(ldp, "{s:s}", "lsr-id", &s) == 0) { + ldp_config->lsr_id_str = strdup(s); + } else { + ldp_config->lsr_id_str = g_default_router_id; + } + if(!inet_pton(AF_INET, ldp_config->lsr_id_str, &ldp_config->lsr_id)) { + fprintf(stderr, "JSON config error: Invalid value for ldp->lsr-id\n"); + return false; + } + if(json_unpack(ldp, "{s:s}", "ipv4-transport-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ldp_config->ipv4_transport_address)) { + fprintf(stderr, "JSON config error: Invalid value for ldp->ipv4-transport-address\n"); + return false; + } + } else { + ldp_config->ipv4_transport_address = ldp_config->lsr_id; + } + return true; +} + static bool json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config) { @@ -1642,6 +1715,7 @@ json_parse_config(json_t *root) bgp_config_s *bgp_config = NULL; isis_config_s *isis_config = NULL; + ldp_config_s *ldp_config = NULL; if(json_typeof(root) != JSON_OBJECT) { fprintf(stderr, "JSON config error: Configuration root element must object\n"); @@ -2167,7 +2241,7 @@ json_parse_config(json_t *root) /* BGP Configuration */ sub = json_object_get(root, "bgp"); if(json_is_array(sub)) { - /* Config is provided as array (multiple bgp sessions) */ + /* Config is provided as array (multiple BGP sessions) */ size = json_array_size(sub); for(i = 0; i < size; i++) { if(!bgp_config) { @@ -2182,7 +2256,7 @@ json_parse_config(json_t *root) } } } else if(json_is_object(sub)) { - /* Config is provided as object (single bgp session) */ + /* Config is provided as object (single BGP session) */ bgp_config = calloc(1, sizeof(bgp_config_s)); if(!g_ctx->config.bgp_config) { g_ctx->config.bgp_config = bgp_config; @@ -2209,7 +2283,7 @@ json_parse_config(json_t *root) /* IS-IS Configuration */ sub = json_object_get(root, "isis"); if(json_is_array(sub)) { - /* Config is provided as array (multiple isis instances) */ + /* Config is provided as array (multiple IS-IS instances) */ size = json_array_size(sub); for(i = 0; i < size; i++) { if(!isis_config) { @@ -2224,7 +2298,7 @@ json_parse_config(json_t *root) } } } else if(json_is_object(sub)) { - /* Config is provided as object (single isis instance) */ + /* Config is provided as object (single IS-IS instance) */ isis_config = calloc(1, sizeof(isis_config_s)); if(!g_ctx->config.isis_config) { g_ctx->config.isis_config = isis_config; @@ -2234,6 +2308,34 @@ json_parse_config(json_t *root) } } + /* LDP Configuration */ + sub = json_object_get(root, "ldp"); + if(json_is_array(sub)) { + /* Config is provided as array (multiple LDP instances) */ + size = json_array_size(sub); + for(i = 0; i < size; i++) { + if(!ldp_config) { + g_ctx->config.ldp_config = calloc(1, sizeof(ldp_config_s)); + ldp_config = g_ctx->config.ldp_config; + } else { + ldp_config->next = calloc(1, sizeof(ldp_config_s)); + ldp_config = ldp_config->next; + } + if(!json_parse_ldp_config(json_array_get(sub, i), ldp_config)) { + return false; + } + } + } else if(json_is_object(sub)) { + /* Config is provided as object (single LDP instance) */ + ldp_config = calloc(1, sizeof(ldp_config_s)); + if(!g_ctx->config.ldp_config) { + g_ctx->config.ldp_config = ldp_config; + } + if(!json_parse_ldp_config(sub, ldp_config)) { + return false; + } + } + /* Interface Configuration */ section = json_object_get(root, "interfaces"); if(json_is_object(section)) { diff --git a/code/bngblaster/src/bbl_config.h b/code/bngblaster/src/bbl_config.h index 1e1d1f09..b54e88e0 100644 --- a/code/bngblaster/src/bbl_config.h +++ b/code/bngblaster/src/bbl_config.h @@ -106,6 +106,8 @@ typedef struct bbl_network_config_ uint32_t isis_l1_metric; uint32_t isis_l2_metric; + uint16_t ldp_instance_id; + void *next; /* pointer to next network config element */ bbl_network_interface_s *network_interface; } bbl_network_config_s; diff --git a/code/bngblaster/src/bbl_ctx.h b/code/bngblaster/src/bbl_ctx.h index 0facf2e5..414e1c9e 100644 --- a/code/bngblaster/src/bbl_ctx.h +++ b/code/bngblaster/src/bbl_ctx.h @@ -95,6 +95,7 @@ typedef struct bbl_ctx_ bgp_session_s *bgp_sessions; bgp_raw_update_s *bgp_raw_updates; isis_instance_s *isis_instances; + ldp_instance_s *ldp_instances; /* Scratchpad memory */ uint8_t *sp; @@ -191,6 +192,9 @@ typedef struct bbl_ctx_ /* ISIS Instances */ isis_config_s *isis_config; + /* LDP Instances */ + ldp_config_s *ldp_config; + /* Global Session Settings */ uint32_t sessions; uint32_t sessions_max_outstanding; diff --git a/code/bngblaster/src/bbl_def.h b/code/bngblaster/src/bbl_def.h index e86f129d..0a4aa792 100644 --- a/code/bngblaster/src/bbl_def.h +++ b/code/bngblaster/src/bbl_def.h @@ -90,6 +90,7 @@ #define BBL_IF_SEND_ARP_REQUEST 0x00000001 #define BBL_IF_SEND_ICMPV6_NS 0x00000002 #define BBL_IF_SEND_ISIS_P2P_HELLO 0x00000004 +#define BBL_IF_SEND_LDP_HELLO 0x00000008 #define DUID_LEN 10 diff --git a/code/bngblaster/src/bbl_network.c b/code/bngblaster/src/bbl_network.c index 3d23e93c..c2737ce1 100644 --- a/code/bngblaster/src/bbl_network.c +++ b/code/bngblaster/src/bbl_network.c @@ -42,7 +42,8 @@ bbl_network_interfaces_add() bbl_network_interface_s *network_interface; bbl_interface_s *interface; isis_instance_s *isis; - bool isis_result; + ldp_instance_s *ldp; + bool result; char ifname[SUB_STR_LEN]; @@ -142,12 +143,12 @@ bbl_network_interfaces_add() /* Init routing protocols */ if(network_config->isis_instance_id) { - isis_result = false; + result = false; isis = g_ctx->isis_instances; - while (isis) { + while(isis) { if(isis->config->id == network_config->isis_instance_id) { - isis_result = isis_adjacency_init(network_interface, network_config, isis); - if(!isis_result) { + result = isis_adjacency_init(network_interface, network_config, isis); + if(!result) { LOG(ERROR, "Failed to enable IS-IS for network interface %s (adjacency init failed)\n", ifname); return false; } @@ -155,11 +156,30 @@ bbl_network_interfaces_add() } isis = isis->next; } - if(!isis_result) { + if(!result) { LOG(ERROR, "Failed to enable IS-IS for network interface %s (instance not found)\n", ifname); return false; } } + if(network_config->ldp_instance_id) { + result = false; + ldp = g_ctx->ldp_instances; + while(ldp) { + if(ldp->config->id == network_config->ldp_instance_id) { + result = ldp_interface_init(network_interface, network_config, ldp); + if(!result) { + LOG(ERROR, "Failed to enable LDP for network interface %s (adjacency init failed)\n", ifname); + return false; + } + break; + } + ldp = ldp->next; + } + if(!result) { + LOG(ERROR, "Failed to enable LDP for network interface %s (instance not found)\n", ifname); + return false; + } + } /* TX list init */ CIRCLEQ_INIT(&network_interface->l2tp_tx_qhead); @@ -386,25 +406,39 @@ bbl_network_rx_handler(bbl_network_interface_s *interface, bbl_network_rx_arp(interface, eth); return; case ETH_TYPE_IPV4: - if(memcmp(interface->mac, eth->dst, ETH_ADDR_LEN) != 0) { - /* Drop wrong MAC */ - return; - } ipv4 = (bbl_ipv4_s*)eth->next; if(ipv4->protocol == PROTOCOL_IPV4_UDP) { udp = (bbl_udp_s*)ipv4->next; + /* LDP hello is send to all routers multicast address and therefore + * processed before check on local MAC address. */ + if(udp->protocol == UDP_PROTOCOL_LDP) { + ldp_hello_rx(interface, eth, ipv4, (bbl_ldp_hello_s*)udp->next); + return; + } + if(memcmp(interface->mac, eth->dst, ETH_ADDR_LEN) != 0) { + /* Drop wrong MAC */ + return; + } if(udp->protocol == UDP_PROTOCOL_QMX_LI) { bbl_qmx_li_handler_rx(interface, eth, (bbl_qmx_li_s*)udp->next); return; } else if(udp->protocol == UDP_PROTOCOL_L2TP) { bbl_l2tp_handler_rx(interface, eth, (bbl_l2tp_s*)udp->next); return; - } + } } else if(ipv4->protocol == PROTOCOL_IPV4_ICMP) { + if(memcmp(interface->mac, eth->dst, ETH_ADDR_LEN) != 0) { + /* Drop wrong MAC */ + return; + } interface->stats.icmp_rx++; bbl_network_rx_icmp(interface, eth, ipv4); return; } else if(ipv4->protocol == PROTOCOL_IPV4_TCP) { + if(memcmp(interface->mac, eth->dst, ETH_ADDR_LEN) != 0) { + /* Drop wrong MAC */ + return; + } interface->stats.tcp_rx++; bbl_tcp_ipv4_rx(interface, eth, ipv4); return; diff --git a/code/bngblaster/src/bbl_network.h b/code/bngblaster/src/bbl_network.h index 3b69503c..422ccb97 100644 --- a/code/bngblaster/src/bbl_network.h +++ b/code/bngblaster/src/bbl_network.h @@ -56,6 +56,7 @@ typedef struct bbl_network_interface_ isis_adjacency_p2p_s *isis_adjacency_p2p; isis_adjacency_s *isis_adjacency[ISIS_LEVELS]; + ldp_adjacency_s *ldp_adjacency; struct { uint64_t packets_tx; @@ -108,6 +109,10 @@ typedef struct bbl_network_interface_ uint32_t isis_tx; uint32_t isis_rx_error; + uint32_t ldp_udp_rx; + uint32_t ldp_udp_tx; + uint32_t ldp_udp_rx_error; + /* Rate Stats */ bbl_rate_s rate_packets_tx; diff --git a/code/bngblaster/src/bbl_protocols.c b/code/bngblaster/src/bbl_protocols.c index a2375401..c9f4ec50 100644 --- a/code/bngblaster/src/bbl_protocols.c +++ b/code/bngblaster/src/bbl_protocols.c @@ -10,6 +10,7 @@ #include "bbl_protocols.h" #include "bbl_access_line.h" #include "isis/isis_def.h" +#include "ldp/ldp_def.h" static protocol_error_t decode_l2tp(uint8_t *buf, uint16_t len, uint8_t *sp, uint16_t sp_len, bbl_ethernet_header_s *eth, bbl_l2tp_s **_l2tp); static protocol_error_t encode_l2tp(uint8_t *buf, uint16_t *len, bbl_l2tp_s *l2tp); @@ -551,6 +552,55 @@ encode_dhcp(uint8_t *buf, uint16_t *len, return PROTOCOL_SUCCESS; } +/* + * encode_ldp_hello + */ +static protocol_error_t +encode_ldp_hello(uint8_t *buf, uint16_t *len, bbl_ldp_hello_s *ldp) +{ + /* PDU version and length */ + *(uint16_t*)buf = htobe16(1); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(30); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + + /* LDP identifier (LSR ID + label space) */ + *(uint32_t*)buf = htobe32(ldp->lsr_id); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + *(uint16_t*)buf = htobe16(ldp->label_space_id); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + + /* LDP message type and length */ + *(uint16_t*)buf = htobe16(LDP_MESSAGE_TYPE_HELLO); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(20); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + + /* LDP message ID */ + *(uint32_t*)buf = htobe32(ldp->msg_id); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + + /* Common hello parameters TLV */ + *(uint16_t*)buf = htobe16(LDP_TLV_TYPE_COMMON_HELLO_PARAMETERS); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(4); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(ldp->hold_time); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = 0; + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + + /* IPv4 transport address TLV */ + *(uint16_t*)buf = htobe16(LDP_TLV_TYPE_IPV4_TRANSPORT_ADDRESS); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint16_t*)buf = htobe16(4); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); + *(uint32_t*)buf = htobe32(ldp->ipv4_transport_address); + BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); + + return PROTOCOL_SUCCESS; +} + /* * encode_bbl */ @@ -628,6 +678,9 @@ encode_udp(uint8_t *buf, uint16_t *len, case UDP_PROTOCOL_DHCP: result = encode_dhcp(buf, len, (bbl_dhcp_s*)udp->next); break; + case UDP_PROTOCOL_LDP: + result = encode_ldp_hello(buf, len, (bbl_ldp_hello_s*)udp->next); + break; default: result = PROTOCOL_SUCCESS; break; @@ -2746,6 +2799,106 @@ decode_qmx_li(uint8_t *buf, uint16_t len, return decode_ethernet(buf, len, sp, sp_len, (bbl_ethernet_header_s**)&qmx_li->next); } +/* + * decode_ldp_hello + */ +static protocol_error_t +decode_ldp_hello(uint8_t *buf, uint16_t len, + uint8_t *sp, uint16_t sp_len, + bbl_ldp_hello_s **_ldp) +{ + bbl_ldp_hello_s *ldp; + + uint16_t pdu_version; + uint16_t pdu_len; + uint16_t msg_type; + uint16_t msg_len; + uint16_t tlv_type; + uint16_t tlv_len; + + if(len < 10 || sp_len < sizeof(bbl_ldp_hello_s)) { + return DECODE_ERROR; + } + + /* Init LDP structure */ + ldp = (bbl_ldp_hello_s*)sp; BUMP_BUFFER(sp, sp_len, sizeof(bbl_ldp_hello_s)); + memset(ldp, 0x0, sizeof(bbl_ldp_hello_s)); + + /* PDU version and length */ + pdu_version = be16toh(*(uint16_t*)buf) & 0x7FFF; + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + pdu_len = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + + if(pdu_version != 1) { + return UNKNOWN_PROTOCOL; + } + + /* The PDU length is defined as two octet integer specifying + * the total length of the PDU in octets, excluding the version + * and PDU length fields. */ + if(pdu_len > len) { + return UNKNOWN_PROTOCOL; + } + len = pdu_len; + + /* LDP identifier (LSR ID + label space) */ + ldp->lsr_id = be32toh(*(uint32_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + ldp->label_space_id = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + + /* LDP message type and length */ + if(len < 4) { + return DECODE_ERROR; + } + msg_type = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + msg_len = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + + if(msg_len > len || msg_len < 4 || + msg_type != LDP_MESSAGE_TYPE_HELLO) { + return DECODE_ERROR; + } + len = msg_len; + + /* LDP message ID */ + ldp->msg_id = be32toh(*(uint32_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint32_t)); + + /* LDP TLV's */ + while(len >= LDP_TLV_LEN_MIN) { + tlv_type = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + tlv_len = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + if(tlv_len > len) { + return DECODE_ERROR; + } + switch(tlv_type) { + case LDP_TLV_TYPE_COMMON_HELLO_PARAMETERS: + if(tlv_len != 4) { + return DECODE_ERROR; + } + ldp->hold_time = be16toh(*(uint16_t*)buf); + break; + case LDP_TLV_TYPE_IPV4_TRANSPORT_ADDRESS: + if(tlv_len != 4) { + return DECODE_ERROR; + } + ldp->ipv4_transport_address = be32toh(*(uint16_t*)buf); + break; + default: + break; + } + BUMP_BUFFER(buf, len, tlv_len); + } + + *_ldp = ldp; + return PROTOCOL_SUCCESS; +} + /* * decode_udp */ @@ -2755,7 +2908,7 @@ decode_udp(uint8_t *buf, uint16_t len, bbl_ethernet_header_s *eth, bbl_udp_s **_udp) { - protocol_error_t ret_val = PROTOCOL_SUCCESS; + protocol_error_t ret_val = UNKNOWN_PROTOCOL; bbl_udp_s *udp; @@ -2791,8 +2944,10 @@ decode_udp(uint8_t *buf, uint16_t len, eth->bbl = udp->next; break; case L2TP_UDP_PORT: - udp->protocol = UDP_PROTOCOL_L2TP; - ret_val = decode_l2tp(buf, len, sp, sp_len, eth, (bbl_l2tp_s**)&udp->next); + if(udp->src == L2TP_UDP_PORT) { + udp->protocol = UDP_PROTOCOL_L2TP; + ret_val = decode_l2tp(buf, len, sp, sp_len, eth, (bbl_l2tp_s**)&udp->next); + } break; case DHCP_UDP_CLIENT: case DHCP_UDP_SERVER: @@ -2803,23 +2958,34 @@ decode_udp(uint8_t *buf, uint16_t len, udp->protocol = UDP_PROTOCOL_QMX_LI; ret_val = decode_qmx_li(buf, len, sp, sp_len, (bbl_qmx_li_s**)&udp->next); break; - default: - if(udp->src == QMX_LI_UDP_PORT) { - udp->protocol = UDP_PROTOCOL_QMX_LI; - ret_val = decode_qmx_li(buf, len, sp, sp_len, (bbl_qmx_li_s**)&udp->next); - } else { - /* Try if payload could be decoded as BBL! - * This fails fast if the 64 bit magic number - * is not found on the expected position. */ - if(decode_bbl(buf, len, sp, sp_len, (bbl_bbl_s**)&udp->next) == PROTOCOL_SUCCESS) { - udp->protocol = UDP_PROTOCOL_BBL; - eth->bbl = udp->next; - } else { - udp->protocol = 0; - udp->next = NULL; - } + case LDP_PORT: + if(udp->src == LDP_PORT) { + udp->protocol = UDP_PROTOCOL_LDP; + ret_val = decode_ldp_hello(buf, len, sp, sp_len, (bbl_ldp_hello_s**)&udp->next); } break; + default: + break; + } + + if(ret_val == UNKNOWN_PROTOCOL) { + if(udp->src == QMX_LI_UDP_PORT) { + udp->protocol = UDP_PROTOCOL_QMX_LI; + ret_val = decode_qmx_li(buf, len, sp, sp_len, (bbl_qmx_li_s**)&udp->next); + } else { + /* Try if payload could be decoded as BBL! + * This fails fast if the 64 bit magic number + * is not found on the expected position. */ + ret_val = decode_bbl(buf, len, sp, sp_len, (bbl_bbl_s**)&udp->next); + if(ret_val == PROTOCOL_SUCCESS) { + udp->protocol = UDP_PROTOCOL_BBL; + eth->bbl = udp->next; + } else { + ret_val = PROTOCOL_SUCCESS; + udp->protocol = 0; + udp->next = NULL; + } + } } *_udp = udp; diff --git a/code/bngblaster/src/bbl_protocols.h b/code/bngblaster/src/bbl_protocols.h index af4fcb40..86a50283 100644 --- a/code/bngblaster/src/bbl_protocols.h +++ b/code/bngblaster/src/bbl_protocols.h @@ -202,6 +202,7 @@ #define UDP_PROTOCOL_L2TP 3 #define UDP_PROTOCOL_QMX_LI 4 #define UDP_PROTOCOL_DHCP 5 +#define UDP_PROTOCOL_LDP 6 #define IPV6_NEXT_HEADER_TCP 6 #define IPV6_NEXT_HEADER_UDP 17 @@ -285,6 +286,8 @@ static const ipv6addr_t ipv6_solicited_node_multicast = {0xFF, 0x02, 0x00, 0x00, /* MAC Addresses */ static const uint8_t broadcast_mac[ETH_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const uint8_t slow_mac[ETH_ADDR_LEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02}; +static const uint8_t all_hosts_mac[ETH_ADDR_LEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01}; +static const uint8_t all_routers_mac[ETH_ADDR_LEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x02}; typedef enum protocol_error_ { PROTOCOL_SUCCESS = 0, @@ -530,12 +533,20 @@ typedef struct bbl_mpls_ { /* * ISIS PDU */ -typedef struct bbl_isis_s { +typedef struct bbl_isis_ { uint8_t type; uint8_t *pdu; uint16_t pdu_len; } bbl_isis_s; +typedef struct bbl_ldp_hello_ { + uint32_t lsr_id; + uint16_t label_space_id; + uint32_t msg_id; + uint32_t ipv4_transport_address; + uint16_t hold_time; +} bbl_ldp_hello_s; + typedef struct bbl_bbl_ { uint16_t padding; uint8_t type; diff --git a/code/bngblaster/src/bbl_tx.c b/code/bngblaster/src/bbl_tx.c index b8e0bcf0..016d8cd2 100644 --- a/code/bngblaster/src/bbl_tx.c +++ b/code/bngblaster/src/bbl_tx.c @@ -1421,6 +1421,9 @@ bbl_tx_encode_network_packet(bbl_network_interface_s *interface, uint8_t *buf, u } else if(interface->send_requests & BBL_IF_SEND_ISIS_P2P_HELLO) { interface->send_requests &= ~BBL_IF_SEND_ISIS_P2P_HELLO; result = isis_p2p_hello_encode(interface, buf, len, ð); + } else if(interface->send_requests & BBL_IF_SEND_LDP_HELLO) { + interface->send_requests &= ~BBL_IF_SEND_LDP_HELLO; + result = ldp_hello_encode(interface, buf, len, ð); } else { interface->send_requests = 0; } diff --git a/code/bngblaster/src/bgp/bgp_ctrl.c b/code/bngblaster/src/bgp/bgp_ctrl.c index 98d304e1..30a2c722 100644 --- a/code/bngblaster/src/bgp/bgp_ctrl.c +++ b/code/bngblaster/src/bgp/bgp_ctrl.c @@ -60,11 +60,11 @@ bgp_ctrl_session_json(bgp_session_s *session) "local-address", format_ipv4_address(&session->ipv4_local_address), "local-id", format_ipv4_address(&session->config->id), "local-as", session->config->local_as, - "local-holdtime", session->config->holdtime, + "local-hold-time", session->config->hold_time, "peer-address", format_ipv4_address(&session->ipv4_peer_address), "peer-id", format_ipv4_address(&session->peer.id), "peer-as", session->peer.as, - "peer-holdtime", session->peer.holdtime, + "peer-hold-time", session->peer.hold_time, "state", bgp_session_state_string(session->state), "raw-update-state", raw_update_state(session), "raw-update-file", raw_update_file, diff --git a/code/bngblaster/src/bgp/bgp_def.h b/code/bngblaster/src/bgp/bgp_def.h index 7ea4418f..ad4bfdf2 100644 --- a/code/bngblaster/src/bgp/bgp_def.h +++ b/code/bngblaster/src/bgp/bgp_def.h @@ -16,7 +16,7 @@ #define BGP_MAX_MESSAGE_SIZE 4096U #define BGP_BUF_SIZE 256*1024 #define BGP_DEFAULT_AS 65000 -#define BGP_DEFAULT_HOLDTIME 90 +#define BGP_DEFAULT_HOLD_TIME 90 #define BGP_DEFAULT_TEARDOWN_TIME 5 #define BGP_MSG_OPEN 1 @@ -58,7 +58,7 @@ typedef struct bgp_config_ { uint32_t id; uint32_t local_as; uint32_t peer_as; - uint16_t holdtime; + uint16_t hold_time; uint16_t teardown_time; bool reconnect; @@ -101,7 +101,7 @@ typedef struct bgp_session_ { struct { uint32_t as; uint32_t id; - uint16_t holdtime; + uint16_t hold_time; } peer; struct { diff --git a/code/bngblaster/src/bgp/bgp_message.c b/code/bngblaster/src/bgp/bgp_message.c index f9e7e620..4904f197 100644 --- a/code/bngblaster/src/bgp/bgp_message.c +++ b/code/bngblaster/src/bgp/bgp_message.c @@ -69,7 +69,7 @@ bgp_push_open_message(bgp_session_s *session) } else { push_be_uint(buffer, 2, session->config->local_as); } - push_be_uint(buffer, 2, session->config->holdtime); /* holdtime */ + push_be_uint(buffer, 2, session->config->hold_time); /* hold-time */ push_data(buffer, (uint8_t*)&session->config->id, 4); /* BGP ID */ /* Optional parameters */ diff --git a/code/bngblaster/src/bgp/bgp_receive.c b/code/bngblaster/src/bgp/bgp_receive.c index dd1d9187..5441d1ba 100644 --- a/code/bngblaster/src/bgp/bgp_receive.c +++ b/code/bngblaster/src/bgp/bgp_receive.c @@ -92,14 +92,14 @@ bgp_open(bgp_session_s *session, uint8_t *start, uint16_t length) return; } session->peer.as = read_be_uint(start+20, 2); - session->peer.holdtime = read_be_uint(start+22, 2); + session->peer.hold_time = read_be_uint(start+22, 2); session->peer.id = read_be_uint(start+24, 4); - LOG(BGP, "BGP (%s %s - %s) open message received with peer AS: %u, holdtime: %us\n", + LOG(BGP, "BGP (%s %s - %s) open message received with peer AS: %u, hold-time: %us\n", session->interface->name, format_ipv4_address(&session->ipv4_local_address), format_ipv4_address(&session->ipv4_peer_address), - session->peer.as, session->peer.holdtime); + session->peer.as, session->peer.hold_time); bgp_session_state_change(session, BGP_OPENCONFIRM); return; @@ -185,7 +185,7 @@ bgp_rebase_read_buffer(bgp_session_s *session) } static void -bpg_read(bgp_session_s *session) +bgp_read(bgp_session_s *session) { uint32_t size; uint16_t length; @@ -223,7 +223,7 @@ bpg_read(bgp_session_s *session) format_ipv4_address(&session->ipv4_peer_address), keyval_get_key(bgp_msg_names, type)); - switch (type) { + switch(type) { case BGP_MSG_OPEN: bgp_open(session, start, length); break; @@ -244,7 +244,7 @@ bpg_read(bgp_session_s *session) } /* Reset hold timer */ - bgp_restart_hold_timer(session, session->config->holdtime); + bgp_restart_hold_timer(session, session->config->hold_time); /* Progress pointer to next BGP message */ buffer->start_idx += length; @@ -274,6 +274,6 @@ bgp_receive_cb(void *arg, uint8_t *buf, uint16_t len) memcpy(buffer->data+buffer->idx, buf, len); buffer->idx+=len; } else { - bpg_read(session); + bgp_read(session); } } \ No newline at end of file diff --git a/code/bngblaster/src/bgp/bgp_session.c b/code/bngblaster/src/bgp/bgp_session.c index a203357f..f8702bae 100644 --- a/code/bngblaster/src/bgp/bgp_session.c +++ b/code/bngblaster/src/bgp/bgp_session.c @@ -176,10 +176,10 @@ bgp_session_state_established(bgp_session_s *session) clock_gettime(CLOCK_MONOTONIC, &session->established_timestamp); /* Start BGP keepalive */ - if(session->peer.holdtime < session->config->holdtime) { - keepalive_interval = session->peer.holdtime/2U; + if(session->peer.hold_time < session->config->hold_time) { + keepalive_interval = session->peer.hold_time/2U; } else { - keepalive_interval = session->config->holdtime/2U; + keepalive_interval = session->config->hold_time/2U; } if(!keepalive_interval) { keepalive_interval = 1; @@ -320,7 +320,7 @@ bgp_session_connect(bgp_session_s *session, time_t delay) session->peer.as = 0; session->peer.id = 0; - session->peer.holdtime = 0; + session->peer.hold_time = 0; session->stats.message_rx = 0; session->stats.message_tx = 0; diff --git a/code/bngblaster/src/isis/isis.c b/code/bngblaster/src/isis/isis.c index ce907306..d40ccab1 100644 --- a/code/bngblaster/src/isis/isis.c +++ b/code/bngblaster/src/isis/isis.c @@ -111,20 +111,20 @@ isis_handler_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth) result = isis_pdu_load(&pdu, isis->pdu, isis->pdu_len); if(result != PROTOCOL_SUCCESS) { LOG(ISIS, "ISIS RX %s PDU decode error on interface %s\n", - isis_pdu_sype_string(pdu.pdu_type), interface->name); + isis_pdu_type_string(pdu.pdu_type), interface->name); interface->stats.isis_rx_error++; return; } if(!isis_pdu_validate_checksum(&pdu)) { LOG(ISIS, "ISIS RX %s PDU checksum error on interface %s\n", - isis_pdu_sype_string(pdu.pdu_type), interface->name); + isis_pdu_type_string(pdu.pdu_type), interface->name); interface->stats.isis_rx_error++; return; } LOG(DEBUG, "ISIS RX %s on interface %s\n", - isis_pdu_sype_string(pdu.pdu_type), interface->name); + isis_pdu_type_string(pdu.pdu_type), interface->name); switch (pdu.pdu_type) { case ISIS_PDU_P2P_HELLO: diff --git a/code/bngblaster/src/isis/isis_adjacency.c b/code/bngblaster/src/isis/isis_adjacency.c index 31582c66..aa965415 100644 --- a/code/bngblaster/src/isis/isis_adjacency.c +++ b/code/bngblaster/src/isis/isis_adjacency.c @@ -140,7 +140,7 @@ isis_adjacency_down(isis_adjacency_s *adjacency) timer_del(adjacency->timer_retry); timer_del(adjacency->timer_csnp); timer_del(adjacency->timer_csnp_next); - timer_del(adjacency->timer_holding); + timer_del(adjacency->timer_hold); if(g_ctx->routing_sessions) g_ctx->routing_sessions--; } \ No newline at end of file diff --git a/code/bngblaster/src/isis/isis_csnp.c b/code/bngblaster/src/isis/isis_csnp.c index 26b59ea4..185b1199 100644 --- a/code/bngblaster/src/isis/isis_csnp.c +++ b/code/bngblaster/src/isis/isis_csnp.c @@ -147,8 +147,9 @@ isis_csnp_job(timer_s *timer) isis.pdu_len = pdu.pdu_len; if(bbl_txq_to_buffer(adjacency->interface->txq, ð) == BBL_TXQ_OK) { LOG(DEBUG, "ISIS TX %s on interface %s\n", - isis_pdu_sype_string(isis.type), adjacency->interface->name); + isis_pdu_type_string(isis.type), adjacency->interface->name); adjacency->stats.csnp_tx++; + adjacency->interface->stats.isis_tx++; /* Clear PSNP tree after CSNP was send */ hb_tree_clear(adjacency->psnp_tree, isis_psnp_free); timer_del(adjacency->timer_psnp_next); diff --git a/code/bngblaster/src/isis/isis_ctrl.c b/code/bngblaster/src/isis/isis_ctrl.c index 3305850e..d32d4737 100644 --- a/code/bngblaster/src/isis/isis_ctrl.c +++ b/code/bngblaster/src/isis/isis_ctrl.c @@ -21,7 +21,7 @@ isis_ctrl_adjacency(isis_adjacency_s *adjacency) peer = json_pack("{ss si}", "system-id", isis_system_id_to_str(adjacency->peer->system_id), - "holding-timer", adjacency->peer->holding_time); + "hold-timer", adjacency->peer->hold_time); root = json_pack("{ss ss ss si ss so}", "interface", adjacency->interface->name, @@ -50,7 +50,7 @@ isis_ctrl_adjacency_p2p(isis_adjacency_p2p_s *adjacency) peer = json_pack("{ss si}", "system-id", isis_system_id_to_str(adjacency->peer->system_id), - "holding-timer", adjacency->peer->holding_time); + "hold-timer", adjacency->peer->hold_time); root = json_pack("{ss ss, ss si ss so}", "interface", adjacency->interface->name, diff --git a/code/bngblaster/src/isis/isis_def.h b/code/bngblaster/src/isis/isis_def.h index 3c3d3593..698beb7d 100644 --- a/code/bngblaster/src/isis/isis_def.h +++ b/code/bngblaster/src/isis/isis_def.h @@ -62,7 +62,7 @@ #define ISIS_DEFAULT_HELLO_INTERVAL 10 #define ISIS_DEFAULT_CSNP_INTERVAL 30 -#define ISIS_DEFAULT_HOLDING_TIME 30 +#define ISIS_DEFAULT_HOLD_TIME 30 #define ISIS_DEFAULT_LSP_LIFETIME 65535 #define ISIS_DEFAULT_LSP_RETRY_IVL 5 #define ISIS_DEFAULT_LSP_REFRESH_IVL 300 @@ -130,7 +130,7 @@ typedef enum isis_pdu_type_ { /* IS-IS TLV Codepoints * https://www.iana.org/assignments/isis-tlv-codepoints/isis-tlv-codepoints.xhtml */ -typedef enum isis_tlv_sype_ { +typedef enum isis_tlv_type_ { ISIS_TLV_AREA_ADDRESSES = 1, ISIS_TLV_PADDING = 8, ISIS_TLV_LSP_ENTRIES = 9, @@ -145,7 +145,7 @@ typedef enum isis_tlv_sype_ { ISIS_TLV_IPV6_REACHABILITY = 236, ISIS_TLV_P2P_ADJACENCY_STATE = 240, ISIS_TLV_ROUTER_CAPABILITY = 242 -} isis_tlv_sype; +} isis_tlv_type; /* STRUCTURES ... */ @@ -203,7 +203,7 @@ typedef struct isis_config_ { uint16_t lsp_refresh_interval; uint16_t lsp_lifetime; uint16_t hello_interval; - uint16_t holding_time; + uint16_t hold_time; uint16_t teardown_time; const char *hostname; @@ -238,7 +238,7 @@ typedef struct isis_config_ { typedef struct isis_peer_ { uint8_t level; uint8_t system_id[ISIS_SYSTEM_ID_LEN]; - uint16_t holding_time; + uint16_t hold_time; char *hostname; } isis_peer_s; @@ -260,7 +260,7 @@ typedef struct isis_adjacency_ { struct timer_ *timer_csnp; struct timer_ *timer_csnp_next; struct timer_ *timer_psnp_next; - struct timer_ *timer_holding; + struct timer_ *timer_hold; bool timer_psnp_started; diff --git a/code/bngblaster/src/isis/isis_lsp.c b/code/bngblaster/src/isis/isis_lsp.c index aee22e9c..79230e88 100644 --- a/code/bngblaster/src/isis/isis_lsp.c +++ b/code/bngblaster/src/isis/isis_lsp.c @@ -291,6 +291,7 @@ isis_lsp_sx_job(timer_s *timer) entry->tx_timestamp.tv_sec = now.tv_sec; entry->tx_timestamp.tv_nsec = now.tv_nsec; adjacency->stats.lsp_tx++; + adjacency->interface->stats.isis_tx++; if(window) window--; if(window == 0) break; } diff --git a/code/bngblaster/src/isis/isis_p2p_hello.c b/code/bngblaster/src/isis/isis_p2p_hello.c index ab059f0f..cc0024ae 100644 --- a/code/bngblaster/src/isis/isis_p2p_hello.c +++ b/code/bngblaster/src/isis/isis_p2p_hello.c @@ -16,7 +16,7 @@ isis_p2p_hello_timeout(timer_s *timer) } void -isis_p2p_holding_timeout(timer_s *timer) +isis_p2p_hold_timeout(timer_s *timer) { isis_adjacency_s *adjacency = timer->data; @@ -24,7 +24,7 @@ isis_p2p_holding_timeout(timer_s *timer) return; } - LOG(ISIS, "ISIS %s holding timeout to %s on interface %s\n", + LOG(ISIS, "ISIS %s hold timeout to %s on interface %s\n", isis_level_string(adjacency->level), isis_system_id_to_str(adjacency->peer->system_id), adjacency->interface->name); @@ -36,16 +36,16 @@ isis_p2p_holding_timeout(timer_s *timer) } static void -isis_p2p_restart_holding_timers(bbl_network_interface_s *interface) +isis_p2p_restart_hold_timers(bbl_network_interface_s *interface) { isis_adjacency_s *adjacency; for(int i=0; iisis_adjacency[i]; if(adjacency) { - timer_add(&g_ctx->timer_root, &adjacency->timer_holding, - "ISIS holding", adjacency->peer->holding_time, 0, adjacency, - &isis_p2p_holding_timeout); + timer_add(&g_ctx->timer_root, &adjacency->timer_hold, + "ISIS Hold", adjacency->peer->hold_time, 0, adjacency, + &isis_p2p_hold_timeout); } } } @@ -77,7 +77,7 @@ isis_p2p_hello_encode(bbl_network_interface_s *interface, /* Start next timer ... */ timer_add(&g_ctx->timer_root, &interface->timer_isis_hello, - "ISIS hello", config->hello_interval, 0, interface, + "ISIS Hello", config->hello_interval, 0, interface, &isis_p2p_hello_timeout); if(config->level1_auth && config->level1_key) { @@ -93,7 +93,7 @@ isis_p2p_hello_encode(bbl_network_interface_s *interface, /* PDU header */ isis_pdu_add_u8(&pdu, adjacency->level); isis_pdu_add_bytes(&pdu, config->system_id, ISIS_SYSTEM_ID_LEN); - isis_pdu_add_u16(&pdu, config->holding_time); + isis_pdu_add_u16(&pdu, config->hold_time); isis_pdu_add_u16(&pdu, 0); isis_pdu_add_u8(&pdu, 0x1); /* TLV section */ @@ -118,8 +118,9 @@ isis_p2p_hello_encode(bbl_network_interface_s *interface, result = encode_ethernet(buf, len, eth); if(result == PROTOCOL_SUCCESS) { LOG(DEBUG, "ISIS TX %s on interface %s\n", - isis_pdu_sype_string(isis.type), interface->name); + isis_pdu_type_string(isis.type), interface->name); adjacency->stats.hello_tx++; + adjacency->interface->stats.isis_tx++; } return result; } @@ -170,9 +171,9 @@ isis_p2p_hello_handler_rx(bbl_network_interface_s *interface, isis_pdu_s *pdu) peer = adjacency->peer; peer->level = *PDU_OFFSET(pdu, ISIS_OFFSET_P2P_HELLO_LEVEL) & 0x03; memcpy(peer->system_id, PDU_OFFSET(pdu, ISIS_OFFSET_P2P_HELLO_SYSTEM_ID), ISIS_SYSTEM_ID_LEN); - peer->holding_time = be16toh(*(uint16_t*)PDU_OFFSET(pdu, ISIS_OFFSET_P2P_HELLO_HOLD_TIME)); + peer->hold_time = be16toh(*(uint16_t*)PDU_OFFSET(pdu, ISIS_OFFSET_P2P_HELLO_HOLD_TIME)); - isis_p2p_restart_holding_timers(interface); + isis_p2p_restart_hold_timers(interface); tlv = isis_pdu_first_tlv(pdu); while(tlv) { diff --git a/code/bngblaster/src/isis/isis_psnp.c b/code/bngblaster/src/isis/isis_psnp.c index 11fa2f5a..3bfd02ab 100644 --- a/code/bngblaster/src/isis/isis_psnp.c +++ b/code/bngblaster/src/isis/isis_psnp.c @@ -129,8 +129,9 @@ isis_psnp_job (timer_s *timer) isis.pdu_len = pdu.pdu_len; if(bbl_txq_to_buffer(adjacency->interface->txq, ð) == BBL_TXQ_OK) { LOG(DEBUG, "ISIS TX %s on interface %s\n", - isis_pdu_sype_string(isis.type), adjacency->interface->name); + isis_pdu_type_string(isis.type), adjacency->interface->name); adjacency->stats.psnp_tx++; + adjacency->interface->stats.isis_tx++; } return; } diff --git a/code/bngblaster/src/isis/isis_utils.c b/code/bngblaster/src/isis/isis_utils.c index b410be3a..5c17fac5 100644 --- a/code/bngblaster/src/isis/isis_utils.c +++ b/code/bngblaster/src/isis/isis_utils.c @@ -52,7 +52,7 @@ isis_adjacency_state_string(uint8_t state) } const char * -isis_pdu_sype_string(uint8_t type) +isis_pdu_type_string(uint8_t type) { switch(type) { case ISIS_PDU_L1_HELLO: return "L1-Hello"; diff --git a/code/bngblaster/src/isis/isis_utils.h b/code/bngblaster/src/isis/isis_utils.h index 703ba443..697c7a24 100644 --- a/code/bngblaster/src/isis/isis_utils.h +++ b/code/bngblaster/src/isis/isis_utils.h @@ -22,7 +22,7 @@ const char * isis_adjacency_state_string(uint8_t state); const char * -isis_pdu_sype_string(uint8_t type); +isis_pdu_type_string(uint8_t type); bool isis_str_to_area(const char *str, isis_area_s *area); diff --git a/code/bngblaster/src/ldp/ldp.c b/code/bngblaster/src/ldp/ldp.c new file mode 100644 index 00000000..3273286d --- /dev/null +++ b/code/bngblaster/src/ldp/ldp.c @@ -0,0 +1,63 @@ +/* + * BNG Blaster (BBL) - LDP Functions + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +/** + * ldp_init + * + * This function inits all LDP sessions. + */ +bool +ldp_init() +{ + ldp_config_s *config = g_ctx->config.ldp_config; + ldp_instance_s *instance = NULL; + + while(config) { + LOG(LDP, "Init LDP instance %u\n", config->id); + if(instance) { + instance->next = calloc(1, sizeof(ldp_instance_s)); + instance = instance->next; + } else { + instance = calloc(1, sizeof(ldp_instance_s)); + g_ctx->ldp_instances = instance; + } + instance->config = config; + + config = config->next; + } + return true; +} + +void +ldp_teardown_job(timer_s *timer) { + ldp_instance_s *instance = timer->data; + UNUSED(instance); +} + +/** + * ldp_teardown + * + * This function stops all LDP sessions. + */ +void +ldp_teardown() +{ + ldp_instance_s *instance = g_ctx->ldp_instances; + while(instance) { + if(!instance->teardown) { + LOG(LDP, "Teardown LDP instance %u\n", instance->config->id); + instance->teardown = true; + timer_add(&g_ctx->timer_root, &instance->teardown_timer, + "LDP TEARDOWN", instance->config->teardown_time, 0, instance, + &ldp_teardown_job); + } + instance = instance->next; + } +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp.h b/code/bngblaster/src/ldp/ldp.h new file mode 100644 index 00000000..8ebebe70 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp.h @@ -0,0 +1,24 @@ +/* + * BNG Blaster (BBL) - LDP Main + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_H__ +#define __BBL_LDP_H__ + +#include "../bbl.h" +#include "ldp_def.h" +#include "ldp_pdu.h" +#include "ldp_hello.h" +#include "ldp_interface.h" + +bool +ldp_init(); + +void +ldp_teardown(); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h new file mode 100644 index 00000000..633ec129 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -0,0 +1,201 @@ +/* + * BNG Blaster (BBL) - LDP Definitions + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_DEF_H__ +#define __BBL_LDP_DEF_H__ + +/* DEFINITIONS ... */ + +#define LDP_PORT 646 +#define LDP_IDENTIFIER_LEN 6U +#define LDP_MAX_PDU_LEN_INIT 4096U + +#define LDP_MESSAGE_TYPE_NOTIFICATION 0x0001 +#define LDP_MESSAGE_TYPE_HELLO 0x0100 +#define LDP_MESSAGE_TYPE_INITIALIZATION 0x0200 +#define LDP_MESSAGE_TYPE_KEEPALIVE 0x0201 +#define LDP_MESSAGE_TYPE_ADDRESS 0x0300 +#define LDP_MESSAGE_TYPE_ADDRESS_WITHDRAW 0x0301 +#define LDP_MESSAGE_TYPE_LABEL_MAPPING 0x0400 +#define LDP_MESSAGE_TYPE_LABEL_REQUEST 0x0401 +#define LDP_MESSAGE_TYPE_LABEL_WITHDRAW 0x0402 +#define LDP_MESSAGE_TYPE_LABEL_RELEASE 0x0403 +#define LDP_MESSAGE_TYPE_ABORT_REQUEST 0x0404 + +#define LDP_TLV_TYPE_FEC 0x0100 +#define LDP_TLV_TYPE_ADDRESS_LIST 0x0101 +#define LDP_TLV_TYPE_HOP_COUNT 0x0103 +#define LDP_TLV_TYPE_PATH_VECTOR 0x0104 +#define LDP_TLV_TYPE_GENERIC_LABEL 0x0200 +#define LDP_TLV_TYPE_STATUS 0x0300 +#define LDP_TLV_TYPE_EXTENDED_STATUS 0x0301 +#define LDP_TLV_TYPE_RETURNED_PDU 0x0302 +#define LDP_TLV_TYPE_RETURNED_MESSAGE 0x0303 +#define LDP_TLV_TYPE_COMMON_HELLO_PARAMETERS 0x0400 +#define LDP_TLV_TYPE_IPV4_TRANSPORT_ADDRESS 0x0401 +#define LDP_TLV_TYPE_CONFIG_SEQ_NUMBER 0x0402 +#define LDP_TLV_TYPE_IPV6_TRANSPORT_ADDRESS 0x0403 +#define LDP_TLV_TYPE_COMMON_SESSION_PARAMETERS 0x0500 +#define LDP_TLV_TYPE_LABEL_REQUEST_ID 0x0600 + +#define LDP_TLV_LEN_MIN 4 + +#define LDP_DEFAULT_HELLO_INTERVAL 10 +#define LDP_DEFAULT_HOLD_TIME 30 +#define LDP_DEFAULT_TEARDOWN_TIME 5 + +typedef enum ldp_state_ { + LDP_NON_EXISTENT, + LDP_INITIALIZED, + LDP_OPENREC, + LDP_OPENSENT, + LDP_OPERATIONAL, +} ldp_state_t; + +typedef struct ldp_instance_ ldp_instance_s; +typedef struct ldp_session_ ldp_session_s; +typedef struct ldp_adjacency_ ldp_adjacency_s; + +/* + * LDP Type-Length-Value (TLV). + */ +typedef struct ldp_tlv_ { + bool u_bit; /* Unknown TLV bit. */ + bool f_bit; /* Forward unknown TLV bit. */ + uint16_t type; + uint16_t len; + uint8_t *value; + struct ldp_tlv_ *next; +} ldp_tlv_s; + +/* + * LDP Message which contains + * one or more LDP TLV. + */ +typedef struct ldp_message_ { + bool u_bit; /* Unknown message bit. */ + uint16_t type; + uint32_t msg_id; + ldp_tlv_s *tlv; + struct ldp_message_ *next; +} ldp_message_s; + +/* + * LDP Protocol Data Unit (PDU) which contains + * one or more LDP messages. + */ +typedef struct ldp_pdu_ { + uint16_t version; + uint16_t len; + uint32_t lsr_id; + uint16_t label_space_id; + ldp_message_s *message; +} ldp_pdu_s; + +/* + * LDP Instance Configuration. + */ +typedef struct ldp_config_ { + + uint16_t id; /* LDP instance identifier */ + uint32_t lsr_id; + uint32_t ipv4_transport_address; + const char *lsr_id_str; + const char *hostname; + + bool overload; + + uint16_t hello_interval; + uint16_t hold_time; + uint16_t teardown_time; + + /* Pointer to next instance. */ + struct ldp_config_ *next; +} ldp_config_s; + +/* + * LDP Session. + */ +typedef struct ldp_session_ { + struct { + uint32_t ipv4_address; + uint32_t lsr_id; + uint16_t label_space_id; + uint16_t hold_time; + } local; + + struct { + uint32_t ipv4_address; + uint32_t lsr_id; + uint16_t label_space_id; + uint16_t hold_time; + } peer; + + struct { + uint32_t message_rx; + uint32_t message_tx; + uint32_t keepalive_rx; + uint32_t keepalive_tx; + } stats; + + struct { + bool e_bit; /* Fatal error bit. */ + bool f_bit; /* Forward bit. */ + uint32_t code; + uint16_t msg_type; + } status; + + uint16_t max_pdu_len; + + ldp_instance_s *instance; + ldp_state_t state; + + io_buffer_t read_buf; + io_buffer_t write_buf; + + /* Pointer to next peer of + * corresponding instance. */ + struct ldp_session_ *next; +} ldp_session_s; + +/* + * LDP Adjacency. + */ +typedef struct ldp_adjacency_ { + bbl_network_interface_s *interface; + ldp_instance_s *instance; + ldp_session_s *session; + + struct timer_ *hello_timer; + + /* Pointer to next adjacency of + * corresponding instance with. */ + struct ldp_adjacency_ *next; +} ldp_adjacency_s; + +/* + * LDP Instance + */ +typedef struct ldp_instance_ { + ldp_config_s *config; + + bool overload; + bool teardown; + + struct timer_ *teardown_timer; + + ldp_adjacency_s *adjacencies; + ldp_session_s *sessions; + + hb_tree *ldb; /* Label database. */ + + /* Pointer to next instance. */ + struct ldp_instance_ *next; +} ldp_instance_s; + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_hello.c b/code/bngblaster/src/ldp/ldp_hello.c new file mode 100644 index 00000000..bd466840 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_hello.c @@ -0,0 +1,106 @@ +/* + * BNG Blaster (BBL) - LDP Hello + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +void +ldp_hello_job(timer_s *timer) +{ + ldp_adjacency_s *adjacency = timer->data; + bbl_network_interface_s *interface = adjacency->interface; + interface->send_requests |= BBL_IF_SEND_LDP_HELLO; +} + +/** + * ldp_hello_start + * + * @param config LDP configuration + * @param adjacency LDP adjacency + */ +void +ldp_hello_start(ldp_config_s *config, ldp_adjacency_s *adjacency) +{ + timer_add_periodic(&g_ctx->timer_root, &adjacency->hello_timer, + "LDP Hello", config->hello_interval, 0, adjacency, + &ldp_hello_job); +} + +/** + * ldp_hello_encode + * + * @param interface send interface + * @param buf send buffer + * @param len send buffer length + * @param eth send ethernet parent structure + * @return PROTOCOL_SUCCESS on success + */ +protocol_error_t +ldp_hello_encode(bbl_network_interface_s *interface, + uint8_t *buf, uint16_t *len, + bbl_ethernet_header_s *eth) +{ + protocol_error_t result; + + bbl_ipv4_s ipv4 = {0}; + bbl_udp_s udp = {0}; + bbl_ldp_hello_s ldp = {0}; + + ldp_adjacency_s *adjacency = interface->ldp_adjacency; + ldp_instance_s *instance = adjacency->instance; + ldp_config_s *config = instance->config; + + /* Build packet ... */ + eth->type = ETH_TYPE_IPV4; + eth->next = &ipv4; + eth->dst = (uint8_t*)all_routers_mac; + + ipv4.dst = IPV4_MC_ALL_ROUTERS; + ipv4.src = interface->ip.address; + ipv4.ttl = 1; + ipv4.protocol = PROTOCOL_IPV4_UDP; + ipv4.router_alert_option = true; + ipv4.next = &udp; + udp.src = LDP_PORT; + udp.dst = LDP_PORT; + udp.protocol = UDP_PROTOCOL_LDP; + udp.next = &ldp; + ldp.lsr_id = config->lsr_id; + ldp.hold_time = config->hold_time; + ldp.ipv4_transport_address = config->ipv4_transport_address; + result = encode_ethernet(buf, len, eth); + if(result == PROTOCOL_SUCCESS) { + LOG(DEBUG, "LDP TX hello on interface %s\n", interface->name); + adjacency->interface->stats.ldp_udp_tx++; + } + return result; +} + +/** + * ldp_hello_rx + * + * This function handles all received LDP hello packets. + * + * @param interface receiving interface + * @param eth received ethernet header + * @param ipv4 received ipv4 header + * @param ldp LDP header of received packet + */ +void +ldp_hello_rx(bbl_network_interface_s *interface, + bbl_ethernet_header_s *eth, + bbl_ipv4_s *ipv4, + bbl_ldp_hello_s *ldp) +{ + ldp_adjacency_s *adjacency = interface->ldp_adjacency; + + UNUSED(adjacency); + UNUSED(eth); + UNUSED(ipv4); + UNUSED(ldp); + +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_hello.h b/code/bngblaster/src/ldp/ldp_hello.h new file mode 100644 index 00000000..a2079192 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_hello.h @@ -0,0 +1,26 @@ +/* + * BNG Blaster (BBL) - LDP Hello + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_HELLO_H__ +#define __BBL_LDP_HELLO_H__ + +void +ldp_hello_start(ldp_config_s *config, ldp_adjacency_s *adjacency); + +protocol_error_t +ldp_hello_encode(bbl_network_interface_s *interface, + uint8_t *buf, uint16_t *len, + bbl_ethernet_header_s *eth); + +void +ldp_hello_rx(bbl_network_interface_s *interface, + bbl_ethernet_header_s *eth, + bbl_ipv4_s *ipv4, + bbl_ldp_hello_s *ldp); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_interface.c b/code/bngblaster/src/ldp/ldp_interface.c new file mode 100644 index 00000000..ce4a610a --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_interface.c @@ -0,0 +1,49 @@ +/* + * BNG Blaster (BBL) - LDP Interface + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +void +ldp_interface_hello_job(timer_s *timer) +{ + ldp_adjacency_s *adjacency = timer->data; + bbl_network_interface_s *interface = adjacency->interface; + + interface->send_requests |= BBL_IF_SEND_LDP_HELLO; +} + +/** + * ldp_interface_init + * + * This function inits the LDP interface. + * + * @param interface network interface + * @param config network interface configuration + * @param instance LDP instance + */ +bool +ldp_interface_init(bbl_network_interface_s *interface, + bbl_network_config_s *interface_config, + ldp_instance_s *instance) +{ + ldp_config_s *config = instance->config; + ldp_adjacency_s *adjacency; + + LOG(LDP, "Add network interface %s to LDP instance %u\n", + interface->name, interface_config->ldp_instance_id); + + adjacency = calloc(1, sizeof(ldp_adjacency_s)); + adjacency->next = instance->adjacencies; + instance->adjacencies = adjacency; + adjacency->instance = instance; + adjacency->interface = interface; + interface->ldp_adjacency = adjacency; + + ldp_hello_start(config, adjacency); + return true; +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_interface.h b/code/bngblaster/src/ldp/ldp_interface.h new file mode 100644 index 00000000..8711bf4c --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_interface.h @@ -0,0 +1,17 @@ +/* + * BNG Blaster (BBL) - LDP Interface + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_INTERFACE_H__ +#define __BBL_LDP_INTERFACE_H__ + +bool +ldp_interface_init(bbl_network_interface_s *interface, + bbl_network_config_s *interface_config, + ldp_instance_s *instance); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_pdu.c b/code/bngblaster/src/ldp/ldp_pdu.c new file mode 100644 index 00000000..00c1b1ba --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_pdu.c @@ -0,0 +1,9 @@ +/* + * BNG Blaster (BBL) - LDP PDU + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" diff --git a/code/bngblaster/src/ldp/ldp_pdu.h b/code/bngblaster/src/ldp/ldp_pdu.h new file mode 100644 index 00000000..aedfa4be --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_pdu.h @@ -0,0 +1,12 @@ +/* + * BNG Blaster (BBL) - LDP PDU + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_PDU_H__ +#define __BBL_LDP_PDU_H__ + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c new file mode 100644 index 00000000..963657c3 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -0,0 +1,176 @@ + +/* + * BNG Blaster (BBL) - LDP Message Receive Functions + * + * Christian Giese, March 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +struct keyval_ ldp_msg_names[] = { + { LDP_MESSAGE_TYPE_NOTIFICATION, "notification" }, + { LDP_MESSAGE_TYPE_HELLO, "hello" }, + { LDP_MESSAGE_TYPE_INITIALIZATION, "initialization" }, + { LDP_MESSAGE_TYPE_KEEPALIVE, "keepalive" }, + { LDP_MESSAGE_TYPE_ADDRESS, "address" }, + { LDP_MESSAGE_TYPE_ADDRESS_WITHDRAW, "address-withdraw" }, + { LDP_MESSAGE_TYPE_LABEL_MAPPING, "label-mapping" }, + { LDP_MESSAGE_TYPE_LABEL_REQUEST, "label-request" }, + { LDP_MESSAGE_TYPE_LABEL_WITHDRAW, "label-withdraw" }, + { LDP_MESSAGE_TYPE_LABEL_RELEASE, "label-release" }, + { LDP_MESSAGE_TYPE_ABORT_REQUEST, "abort-request" }, + { 0, NULL} +}; + +/* + * When there is only little data left and + * the buffer start is close to buffer end, + * then 'rebase' the buffer by copying + * the tail data to the buffer head. + */ +static void +ldp_rebase_buffer(io_buffer_t *buffer) +{ + uint32_t size; + + size = buffer->idx - buffer->start_idx; + if(size) { + /* Copy what is left to the buffer start. */ + memcpy(buffer->data, buffer->data+buffer->start_idx, size); + } + buffer->start_idx = 0; + buffer->idx = size; +} + +static void +ldp_read(ldp_session_s *session) +{ + uint32_t size; + uint16_t length; + + io_buffer_t *buffer = &session->read_buf; + + uint32_t lsr_id; + uint16_t label_space_id; + + uint8_t *pdu_start; + uint16_t pdu_version; + uint16_t pdu_length; + + uint8_t *msg_start; + uint16_t msg_type; + uint16_t msg_length; + + while(true) { + pdu_start = buffer->data+buffer->start_idx; + size = buffer->idx - buffer->start_idx; + + /* Minimum PDU size */ + if(size < 4) { + break; + } + + pdu_version = read_be_uint(pdu_start, 2); + pdu_length = read_be_uint(pdu_start+2, 2); + + /* The PDU length is defined as two octet integer specifying + * the total length of the PDU in octets, excluding the version + * and PDU length fields. */ + + if(pdu_version != 1 || + pdu_length < LDP_IDENTIFIER_LEN || + pdu_length > session->max_pdu_len) { + //ldp_decode_error(session); + break; + } + + length = pdu_length+4; + + /* Full message on the wire to consume? */ + if(length > size) { + break; + } + + /* Read LDP Identifier. */ + lsr_id = read_be_uint(pdu_start+4, 4); + label_space_id = read_be_uint(pdu_start+8, 2); + + if(lsr_id != session->peer.lsr_id || + label_space_id != session->peer.label_space_id) { + /* TODO: INVALID MESSAGE!!!! */ + break; + } + + pdu_length -= LDP_IDENTIFIER_LEN; + msg_start = pdu_start+10; + while(pdu_length >= 4) { + msg_type = read_be_uint(msg_start, 2); + msg_length = read_be_uint(msg_start+2, 2); + + UNUSED(msg_length); + + LOG(DEBUG, "LDP (%s - %s) read %s message\n", + format_ipv4_address(&session->local.ipv4_address), + format_ipv4_address(&session->peer.ipv4_address), + keyval_get_key(ldp_msg_names, msg_type)); + + session->stats.message_rx++; + switch(msg_type) { + case LDP_MESSAGE_TYPE_NOTIFICATION: + break; + case LDP_MESSAGE_TYPE_INITIALIZATION: + break; + case LDP_MESSAGE_TYPE_KEEPALIVE: + session->stats.keepalive_rx++; + break; + case LDP_MESSAGE_TYPE_ADDRESS: + case LDP_MESSAGE_TYPE_ADDRESS_WITHDRAW: + case LDP_MESSAGE_TYPE_LABEL_MAPPING: + case LDP_MESSAGE_TYPE_LABEL_REQUEST: + case LDP_MESSAGE_TYPE_LABEL_WITHDRAW: + case LDP_MESSAGE_TYPE_LABEL_RELEASE: + case LDP_MESSAGE_TYPE_ABORT_REQUEST: + break; + default: + break; + } + } + + /* Reset hold timer */ + //ldp_restart_hold_timer(session, session->instance->config->hold_time); + + /* Progress pointer to next LDP PDU. */ + buffer->start_idx += length; + } + ldp_rebase_buffer(buffer); +} + +void +ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) +{ + ldp_session_s *session = (ldp_session_s*)arg; + io_buffer_t *buffer = &session->read_buf; + if(buf) { + if(buffer->idx+len > buffer->size) { + LOG(ERROR, "LDP (%s - %s) receive error (read buffer exhausted)\n", + format_ipv4_address(&session->local.ipv4_address), + format_ipv4_address(&session->peer.ipv4_address)); + +#if 0 + if(!session->status_code) { + peer->status_code = 0x00000019; /* Cease */ + session->error_subcode = 8; /* Out of resources */ + } +#endif + //ldp_session_close(session); + return; + } + memcpy(buffer->data+buffer->idx, buf, len); + buffer->idx+=len; + } else { + ldp_read(session); + } +} + diff --git a/code/common/src/logging.h b/code/common/src/logging.h index 4cfc588a..41e5838a 100644 --- a/code/common/src/logging.h +++ b/code/common/src/logging.h @@ -36,6 +36,7 @@ enum { L2TP, DHCP, ISIS, + LDP, BGP, TCP, LSDB, diff --git a/docsrc/sources/configuration/bgp.rst b/docsrc/sources/configuration/bgp.rst index 584080c8..16aa5fdf 100644 --- a/docsrc/sources/configuration/bgp.rst +++ b/docsrc/sources/configuration/bgp.rst @@ -25,8 +25,8 @@ * - `peer-as` - BGP peer AS - local AS - * - `holdtime` - - BGP holdtime in seconds + * - `hold-time` + - BGP hold-time in seconds - 90 * - `id` - BGP identifier diff --git a/docsrc/sources/configuration/isis.rst b/docsrc/sources/configuration/isis.rst index 85341a4b..adde659a 100644 --- a/docsrc/sources/configuration/isis.rst +++ b/docsrc/sources/configuration/isis.rst @@ -43,8 +43,8 @@ * - `hello-padding` - ISIS hello padding - false - * - `holding-time` - - ISIS holding time in seconds + * - `hold-time` + - ISIS hold time in seconds - 30 * - `lsp-lifetime` - ISIS LSP lifetime in seconds diff --git a/docsrc/sources/configuration/ldp.rst b/docsrc/sources/configuration/ldp.rst new file mode 100644 index 00000000..83e69a37 --- /dev/null +++ b/docsrc/sources/configuration/ldp.rst @@ -0,0 +1,33 @@ +.. code-block:: json + + { "ldp": {} } + + +.. list-table:: + :widths: 25 50 25 + :header-rows: 1 + + * - Attribute + - Description + - Default + * - `instance-id` + - LDP instance identifier + - + * - `overload` + - LDP overload + - false + * - `hello-interval` + - LDP hello interval in seconds + - 10 + * - `hold-time` + - LDP hold time in seconds + - 30 + * - `hostname` + - LDP hostname + - bngblaster + * - `router-id` + - LDP router identifier + - 10.10.10.10 + * - `teardown-time` + - LDP teardown time in seconds + - 5 \ No newline at end of file diff --git a/docsrc/sources/quickstart.rst b/docsrc/sources/quickstart.rst index 160f7bba..bac45f87 100644 --- a/docsrc/sources/quickstart.rst +++ b/docsrc/sources/quickstart.rst @@ -519,7 +519,7 @@ Finally, start the BNG Blaster in another terminal window. Apr 08 14:53:52.904389 All network interfaces resolved Apr 08 14:53:53.904448 BGP (veth1.2 192.168.92.2 - 192.168.92.1) state changed from idle -> connect Apr 08 14:53:53.905659 BGP (veth1.2 192.168.92.2 - 192.168.92.1) state changed from connect -> opensent - Apr 08 14:53:53.907888 BGP (veth1.2 192.168.92.2 - 192.168.92.1) open message received with peer AS: 65001, holdtime: 90s + Apr 08 14:53:53.907888 BGP (veth1.2 192.168.92.2 - 192.168.92.1) open message received with peer AS: 65001, hold-time: 90s Apr 08 14:53:53.907903 BGP (veth1.2 192.168.92.2 - 192.168.92.1) state changed from opensent -> openconfirm Apr 08 14:53:53.907917 BGP (veth1.2 192.168.92.2 - 192.168.92.1) state changed from openconfirm -> established Apr 08 14:53:54.907989 BGP (veth1.2 192.168.92.2 - 192.168.92.1) raw update start @@ -544,11 +544,11 @@ from where you started the BNG Blaster and enter the following command. "local-address": "192.168.92.2", "local-id": "1.2.3.4", "local-as": 65001, - "local-holdtime": 90, + "local-hold-time": 90, "peer-address": "192.168.92.1", "peer-id": "1.92.168.192", "peer-as": 65001, - "peer-holdtime": 90, + "peer-hold-time": 90, "state": "established", "raw-update-state": "done", "raw-update-file": "out.bgp", diff --git a/docsrc/sources/routing/index.rst b/docsrc/sources/routing/index.rst index bfc7e839..79827a8f 100644 --- a/docsrc/sources/routing/index.rst +++ b/docsrc/sources/routing/index.rst @@ -9,5 +9,6 @@ router testing. :maxdepth: 1 isis.rst - bgp.rst + ldp.rst mpls.rst + bgp.rst diff --git a/docsrc/sources/routing/ldp.rst b/docsrc/sources/routing/ldp.rst new file mode 100644 index 00000000..3e3ef8ed --- /dev/null +++ b/docsrc/sources/routing/ldp.rst @@ -0,0 +1,62 @@ +.. _ldp: + +LDP +--- + +The Label Distribution Protocol (LDP) is a protocol defined for +distributing labels. + +Configuration +~~~~~~~~~~~~~ + +Following an example LDP configuration with one instance +attached to two network interfaces. + +.. code-block:: json + + { + "interfaces": { + "network": [ + { + "interface": "eth1", + "address": "10.0.1.2/24", + "gateway": "10.0.1.1", + "address-ipv6": "fc66:1337:7331:1::2/64", + "gateway-ipv6": "fc66:1337:7331:1::1", + "ldp-instance-id": 1, + }, + { + "interface": "eth2", + "address": "10.0.2.2/24", + "gateway": "10.0.2.1", + "address-ipv6": "fc66:1337:7331:2::2/64", + "gateway-ipv6": "fc66:1337:7331:2::1", + "ldp-instance-id": 1 + } + ] + }, + "ldp": [ + { + "instance-id": 1, + "lsr-id": "10.10.10.10", + "hostname": "R1", + } + ] + } + +.. include:: ../configuration/ldp.rst + +The support for multiple instances allows different use cases. One example might +be to create two instances connected to the device or network under test. Now +inject an LSP on one instance and check if learned over the tested network on +the other instance. + +Peers +~~~~~ + +Database +~~~~~~~~ + +Limitations +~~~~~~~~~~~ + From dcd63af6a1b870261f0d633d565b3a14f7169d32 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Fri, 9 Dec 2022 18:23:24 +0000 Subject: [PATCH 04/27] LDP initial session setup --- code/bngblaster/src/bbl_config.c | 11 +- code/bngblaster/src/bbl_tcp.c | 114 +++++- code/bngblaster/src/bbl_tcp.h | 7 + code/bngblaster/src/bgp/bgp_def.h | 2 - code/bngblaster/src/bgp/bgp_receive.c | 26 +- code/bngblaster/src/bgp/bgp_session.c | 4 +- code/bngblaster/src/ldp/ldp.h | 4 +- code/bngblaster/src/ldp/ldp_def.h | 140 ++++--- code/bngblaster/src/ldp/ldp_hello.c | 103 +++-- code/bngblaster/src/ldp/ldp_hello.h | 8 +- code/bngblaster/src/ldp/ldp_interface.c | 12 +- code/bngblaster/src/ldp/ldp_message.c | 160 ++++++++ code/bngblaster/src/ldp/ldp_message.h | 21 + code/bngblaster/src/ldp/ldp_pdu.c | 9 - code/bngblaster/src/ldp/ldp_pdu.h | 12 - code/bngblaster/src/ldp/ldp_receive.c | 127 ++++-- code/bngblaster/src/ldp/ldp_receive.h | 15 + code/bngblaster/src/ldp/ldp_session.c | 516 ++++++++++++++++++++++++ code/bngblaster/src/ldp/ldp_session.h | 25 ++ code/common/src/common.h | 3 + docsrc/sources/install.rst | 9 +- 21 files changed, 1140 insertions(+), 188 deletions(-) create mode 100644 code/bngblaster/src/ldp/ldp_message.c create mode 100644 code/bngblaster/src/ldp/ldp_message.h delete mode 100644 code/bngblaster/src/ldp/ldp_pdu.c delete mode 100644 code/bngblaster/src/ldp/ldp_pdu.h create mode 100644 code/bngblaster/src/ldp/ldp_receive.h create mode 100644 code/bngblaster/src/ldp/ldp_session.c create mode 100644 code/bngblaster/src/ldp/ldp_session.h diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index f2bb2aba..16f1f4df 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1379,16 +1379,11 @@ json_parse_ldp_config(json_t *ldp, ldp_config_s *ldp_config) return false; } - value = json_object_get(ldp, "overload"); - if(json_is_boolean(value)) { - ldp_config->overload = json_boolean_value(value); - } - - value = json_object_get(ldp, "hello-interval"); + value = json_object_get(ldp, "keepalive-interval"); if(json_is_number(value)) { - ldp_config->hello_interval = json_number_value(value); + ldp_config->keepalive_interval = json_number_value(value); } else { - ldp_config->hello_interval = LDP_DEFAULT_HELLO_INTERVAL; + ldp_config->keepalive_interval = LDP_DEFAULT_KEEPALIVE_INTERVAL; } value = json_object_get(ldp, "hold-time"); diff --git a/code/bngblaster/src/bbl_tcp.c b/code/bngblaster/src/bbl_tcp.c index a2e156c1..4dfc6e30 100644 --- a/code/bngblaster/src/bbl_tcp.c +++ b/code/bngblaster/src/bbl_tcp.c @@ -77,29 +77,29 @@ bbl_tcp_ctx_free(bbl_tcp_ctx_s *tcpc) { static bbl_tcp_ctx_s * bbl_tcp_ctx_new(bbl_network_interface_s *interface) { - bbl_tcp_ctx_s *tcp; + bbl_tcp_ctx_s *tcpc; /* Init TCP context */ - tcp = calloc(1, sizeof(bbl_tcp_ctx_s)); - if(!tcp) { + tcpc = calloc(1, sizeof(bbl_tcp_ctx_s)); + if(!tcpc) { return NULL; } - tcp->interface = interface; + tcpc->interface = interface; /* Init TCP PCB */ - tcp->pcb = tcp_new(); - if(!tcp->pcb) { - free(tcp); + tcpc->pcb = tcp_new(); + if(!tcpc->pcb) { + free(tcpc); return NULL; } /* Bind local network interface */ - tcp_bind_netif(tcp->pcb, &interface->netif); + tcp_bind_netif(tcpc->pcb, &interface->netif); /* Add BBL TCP context as argument */ - tcp_arg(tcp->pcb, tcp); + tcp_arg(tcpc->pcb, tcpc); - return tcp; + return tcpc; } err_t @@ -207,7 +207,8 @@ bbl_tcp_error_cb(void *arg, err_t err) { * callback function! */ err_t -bbl_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) { +bbl_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) +{ bbl_tcp_ctx_s *tcpc = arg; if(tcpc->poll_cb) { return (tcpc->poll_cb)(tcpc->arg, tpcb); @@ -216,7 +217,8 @@ bbl_tcp_poll_cb(void *arg, struct tcp_pcb *tpcb) { } err_t -bbl_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { +bbl_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ bbl_tcp_ctx_s *tcpc = arg; UNUSED(err); /* TODO!!! */ @@ -250,6 +252,87 @@ bbl_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { return ERR_OK; } +err_t +bbl_tcp_ipv4_listen_accept(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + bbl_tcp_ctx_s *listen = arg; + bbl_tcp_ctx_s *tcpc; + + UNUSED(err); /* TODO!!! */ + + //tcp_setprio(tpcb, TCP_PRIO_MIN); + + tcpc = calloc(1, sizeof(bbl_tcp_ctx_s)); + if(!tcpc) { + return ERR_MEM; + } + tcpc->interface = listen->interface; + tcpc->af = listen->af; + tcpc->local_port = listen->local_port; + tcpc->local_ipv4 = listen->local_ipv4; + + tcpc->pcb = tpcb; + tcp_arg(tpcb, tcpc); + + if(listen->accepted_cb) { + (listen->accepted_cb)(tcpc, listen->arg); + } + + /* Add send/receive callback functions. */ + tcp_sent(tpcb, bbl_tcp_sent_cb); + tcp_recv(tpcb, bbl_tcp_recv_cb); + if(tcpc->poll_cb && tcpc->poll_interval) { + tcp_poll(tpcb, bbl_tcp_poll_cb, tcpc->poll_interval); + } + tcp_err(tpcb, bbl_tcp_error_cb); + + return ERR_OK; +} + +/** + * bbl_tcp_ipv4_listen + * + * @param interface interface + * @param address local address + * @param port local port + * @return TCP context + */ +bbl_tcp_ctx_s * +bbl_tcp_ipv4_listen(bbl_network_interface_s *interface, ipv4addr_t *address, uint16_t port) +{ + bbl_tcp_ctx_s *tcpc; + + if(!g_ctx->tcp) { + /* TCP not enabled! */ + return NULL; + } + + tcpc = bbl_tcp_ctx_new(interface); + if(!tcpc) { + return NULL; + } + + /* Bind local IP address and port */ + if(tcp_bind(tcpc->pcb, (const ip_addr_t*)address, port) != ERR_OK) { + bbl_tcp_ctx_free(tcpc); + } + + tcpc->pcb = tcp_listen(tcpc->pcb); + tcp_accept(tcpc->pcb, bbl_tcp_ipv4_listen_accept); + + tcpc->af = AF_INET; + tcpc->local_port = port; + tcpc->local_ipv4 = *address; + tcpc->pcb->local_ip.type = IPADDR_TYPE_V4; + tcpc->pcb->remote_ip.type = IPADDR_TYPE_V4; + tcpc->state = BBL_TCP_STATE_LISTEN; + LOG(TCP, "TCP (%s %s:%u) listen\n", + interface->name, + format_ipv4_address(&tcpc->local_ipv4), tcpc->local_port); + + return tcpc; +} + /** * bbl_tcp_ipv4_connect * @@ -260,8 +343,8 @@ bbl_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { * @return TCP context */ bbl_tcp_ctx_s * -bbl_tcp_ipv4_connect(bbl_network_interface_s *interface, ipv4addr_t *src, ipv4addr_t *dst, uint16_t port) { - +bbl_tcp_ipv4_connect(bbl_network_interface_s *interface, ipv4addr_t *src, ipv4addr_t *dst, uint16_t port) +{ bbl_tcp_ctx_s *tcpc; if(!g_ctx->tcp) { @@ -444,8 +527,7 @@ bbl_tcp_netif_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t */ err_t bbl_tcp_netif_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) { - bbl_tcp_ctx_s *tcpc = netif->state; - bbl_network_interface_s *interface = tcpc->interface; + bbl_network_interface_s *interface = netif->state; bbl_ethernet_header_s eth = {0}; UNUSED(ipaddr); diff --git a/code/bngblaster/src/bbl_tcp.h b/code/bngblaster/src/bbl_tcp.h index ab80cb7d..0ccafc11 100644 --- a/code/bngblaster/src/bbl_tcp.h +++ b/code/bngblaster/src/bbl_tcp.h @@ -22,8 +22,10 @@ typedef enum bbl_tcp_state_ { BBL_TCP_STATE_CONNECTING, BBL_TCP_STATE_IDLE, BBL_TCP_STATE_SENDING, + BBL_TCP_STATE_LISTEN, } bbl_tcp_state_t; +typedef void (*bbl_tcp_accepted_fn)(bbl_tcp_ctx_s *tcpc, void *arg); typedef void (*bbl_tcp_callback_fn)(void *arg); typedef void (*bbl_tcp_receive_fn)(void *arg, uint8_t *buf, uint16_t len); typedef void (*bbl_tcp_error_fn)(void *arg, err_t err); @@ -33,6 +35,7 @@ typedef struct bbl_tcp_ctx_ { bbl_network_interface_s *interface; + bool listen; uint8_t af; /* AF_INET or AF_INET6 */ uint16_t local_port; @@ -45,6 +48,7 @@ typedef struct bbl_tcp_ctx_ struct tcp_pcb *pcb; + bbl_tcp_accepted_fn accepted_cb; /* accepted callback (listen) */ bbl_tcp_callback_fn connected_cb; /* application connected callback */ bbl_tcp_callback_fn idle_cb; /* application idle callback */ @@ -82,6 +86,9 @@ bbl_tcp_close(bbl_tcp_ctx_s *tcpc); void bbl_tcp_ctx_free(bbl_tcp_ctx_s *tcpc); +bbl_tcp_ctx_s * +bbl_tcp_ipv4_listen(bbl_network_interface_s *interface, ipv4addr_t *address, uint16_t port); + bbl_tcp_ctx_s * bbl_tcp_ipv4_connect(bbl_network_interface_s *interface, ipv4addr_t *src, ipv4addr_t *dst, uint16_t port); diff --git a/code/bngblaster/src/bgp/bgp_def.h b/code/bngblaster/src/bgp/bgp_def.h index ad4bfdf2..c1c67d2b 100644 --- a/code/bngblaster/src/bgp/bgp_def.h +++ b/code/bngblaster/src/bgp/bgp_def.h @@ -84,8 +84,6 @@ typedef struct bgp_session_ { bbl_tcp_ctx_s *tcpc; struct timer_ *connect_timer; - struct timer_ *send_open_timer; - struct timer_ *open_sent_timer; struct timer_ *keepalive_timer; struct timer_ *hold_timer; struct timer_ *close_timer; diff --git a/code/bngblaster/src/bgp/bgp_receive.c b/code/bngblaster/src/bgp/bgp_receive.c index 5441d1ba..8bf21667 100644 --- a/code/bngblaster/src/bgp/bgp_receive.c +++ b/code/bngblaster/src/bgp/bgp_receive.c @@ -84,12 +84,11 @@ bgp_decode_error(bgp_session_s *session) bgp_session_close(session); } -static void +static bool bgp_open(bgp_session_s *session, uint8_t *start, uint16_t length) { if(length < 28) { - bgp_decode_error(session); - return; + return false; } session->peer.as = read_be_uint(start+20, 2); session->peer.hold_time = read_be_uint(start+22, 2); @@ -102,17 +101,16 @@ bgp_open(bgp_session_s *session, uint8_t *start, uint16_t length) session->peer.as, session->peer.hold_time); bgp_session_state_change(session, BGP_OPENCONFIRM); - return; + return true; } -static void +static bool bgp_notification(bgp_session_s *session, uint8_t *start, uint16_t length) { uint8_t error_code, error_subcode; if(length < 21) { - bgp_decode_error(session); - return; + return false; } error_code = *(start+19); @@ -160,7 +158,7 @@ bgp_notification(bgp_session_s *session, uint8_t *start, uint16_t length) } session->error_code = 0; bgp_session_close(session); - return; + return true; } /* @@ -206,7 +204,7 @@ bgp_read(bgp_session_s *session) if(length < BGP_MIN_MESSAGE_SIZE || length > BGP_MAX_MESSAGE_SIZE) { bgp_decode_error(session); - break; + return; } /* Full message on the wire to consume? */ @@ -225,10 +223,16 @@ bgp_read(bgp_session_s *session) switch(type) { case BGP_MSG_OPEN: - bgp_open(session, start, length); + if(!bgp_open(session, start, length)) { + bgp_decode_error(session); + return; + } break; case BGP_MSG_NOTIFICATION: - bgp_notification(session, start, length); + if(!bgp_notification(session, start, length)) { + bgp_decode_error(session); + return; + } return; case BGP_MSG_KEEPALIVE: session->stats.keepalive_rx++; diff --git a/code/bngblaster/src/bgp/bgp_session.c b/code/bngblaster/src/bgp/bgp_session.c index f8702bae..9bfb87de 100644 --- a/code/bngblaster/src/bgp/bgp_session.c +++ b/code/bngblaster/src/bgp/bgp_session.c @@ -216,7 +216,7 @@ bgp_session_state_change(bgp_session_s *session, bgp_state_t new_state) session->state = new_state; - switch (new_state) { + switch(new_state) { case BGP_OPENSENT: bgp_session_state_opensent(session); break; @@ -376,8 +376,6 @@ bgp_session_close(bgp_session_s *session) /* Stop all timers */ timer_del(session->connect_timer); - timer_del(session->send_open_timer); - timer_del(session->open_sent_timer); timer_del(session->keepalive_timer); timer_del(session->hold_timer); timer_del(session->update_timer); diff --git a/code/bngblaster/src/ldp/ldp.h b/code/bngblaster/src/ldp/ldp.h index 8ebebe70..801327f0 100644 --- a/code/bngblaster/src/ldp/ldp.h +++ b/code/bngblaster/src/ldp/ldp.h @@ -11,9 +11,11 @@ #include "../bbl.h" #include "ldp_def.h" -#include "ldp_pdu.h" +#include "ldp_message.h" #include "ldp_hello.h" #include "ldp_interface.h" +#include "ldp_receive.h" +#include "ldp_session.h" bool ldp_init(); diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index 633ec129..d0ff5296 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -14,6 +14,9 @@ #define LDP_PORT 646 #define LDP_IDENTIFIER_LEN 6U #define LDP_MAX_PDU_LEN_INIT 4096U +#define LDP_MIN_PDU_LEN 10 +#define LDP_MIN_MSG_LEN 8 +#define LDP_MIN_TLV_LEN 4 #define LDP_MESSAGE_TYPE_NOTIFICATION 0x0001 #define LDP_MESSAGE_TYPE_HELLO 0x0100 @@ -45,57 +48,64 @@ #define LDP_TLV_LEN_MIN 4 -#define LDP_DEFAULT_HELLO_INTERVAL 10 -#define LDP_DEFAULT_HOLD_TIME 30 +#define LDP_STATUS_SUCCESS 0x00000000 +#define LDP_STATUS_BAD_IDENTIFIER 0x00000001 +#define LDP_STATUS_BAD_VERSION 0x00000002 +#define LDP_STATUS_BAD_MSG_LEN 0x00000005 +#define LDP_STATUS_BAD_TLV_LEN 0x00000007 +#define LDP_STATUS_BAD_TLV_VALUE 0x00000008 +#define LDP_STATUS_HOLD_TIMER_EXPIRED 0x00000009 +#define LDP_STATUS_KEEPALIVE_TIMER_EXPIRED 0x00000014 + +#define LDP_STATUS_SHUTDOWN 0x0000000A +#define LDP_STATUS_INTERNAL_ERROR 0x00000019 + +#define LDP_DEFAULT_KEEPALIVE_INTERVAL 15 +#define LDP_DEFAULT_HOLD_TIME 15 #define LDP_DEFAULT_TEARDOWN_TIME 5 typedef enum ldp_state_ { - LDP_NON_EXISTENT, + LDP_CLOSED, + LDP_IDLE, + LDP_LISTEN, + LDP_CONNECT, LDP_INITIALIZED, LDP_OPENREC, LDP_OPENSENT, LDP_OPERATIONAL, + LDP_CLOSING, + LDP_ERROR } ldp_state_t; +typedef enum ldp_event_ { + LDP_EVENT_START, + LDP_EVENT_RX_INITIALIZED, + LDP_EVENT_RX_KEEPALIVE, +} ldp_event_t; + +typedef enum ldp_adjacency_state_ { + LDP_ADJACENCY_STATE_DOWN = 0, + LDP_ADJACENCY_STATE_UP = 1 +} ldp_adjacency_state; + typedef struct ldp_instance_ ldp_instance_s; typedef struct ldp_session_ ldp_session_s; typedef struct ldp_adjacency_ ldp_adjacency_s; /* - * LDP Type-Length-Value (TLV). + * LDP RAW Update File */ -typedef struct ldp_tlv_ { - bool u_bit; /* Unknown TLV bit. */ - bool f_bit; /* Forward unknown TLV bit. */ - uint16_t type; - uint16_t len; - uint8_t *value; - struct ldp_tlv_ *next; -} ldp_tlv_s; +typedef struct ldp_raw_update_ { + const char *file; -/* - * LDP Message which contains - * one or more LDP TLV. - */ -typedef struct ldp_message_ { - bool u_bit; /* Unknown message bit. */ - uint16_t type; - uint32_t msg_id; - ldp_tlv_s *tlv; - struct ldp_message_ *next; -} ldp_message_s; + uint8_t *buf; + uint32_t len; + uint32_t pdu; /* PDU counter */ + uint32_t messages; /* Message counter*/ -/* - * LDP Protocol Data Unit (PDU) which contains - * one or more LDP messages. - */ -typedef struct ldp_pdu_ { - uint16_t version; - uint16_t len; - uint32_t lsr_id; - uint16_t label_space_id; - ldp_message_s *message; -} ldp_pdu_s; + /* Pointer to next instance */ + struct ldp_raw_update_ *next; +} ldp_raw_update_s; /* * LDP Instance Configuration. @@ -108,9 +118,7 @@ typedef struct ldp_config_ { const char *lsr_id_str; const char *hostname; - bool overload; - - uint16_t hello_interval; + uint16_t keepalive_interval; uint16_t hold_time; uint16_t teardown_time; @@ -122,41 +130,65 @@ typedef struct ldp_config_ { * LDP Session. */ typedef struct ldp_session_ { + ldp_instance_s *instance; + bbl_network_interface_s *interface; + bbl_tcp_ctx_s *tcpc; + + struct timer_ *connect_timer; + struct timer_ *keepalive_timer; + struct timer_ *close_timer; + + struct timer_ *update_timer; + struct timer_ *teardown_timer; + + io_buffer_t read_buf; + io_buffer_t write_buf; + + uint32_t pdu_start_idx; + uint32_t msg_start_idx; + uint32_t tlv_start_idx; + uint32_t message_id; + uint32_t error_code; + + bool active; + ldp_state_t state; + uint16_t max_pdu_len; + uint16_t keepalive_time; + struct { uint32_t ipv4_address; uint32_t lsr_id; uint16_t label_space_id; - uint16_t hold_time; + uint16_t keepalive_time; + uint16_t max_pdu_len; } local; struct { uint32_t ipv4_address; uint32_t lsr_id; uint16_t label_space_id; - uint16_t hold_time; + uint16_t keepalive_time; + uint16_t max_pdu_len; } peer; struct { + uint32_t pdu_rx; + uint32_t pdu_tx; uint32_t message_rx; uint32_t message_tx; uint32_t keepalive_rx; uint32_t keepalive_tx; } stats; - struct { - bool e_bit; /* Fatal error bit. */ - bool f_bit; /* Forward bit. */ - uint32_t code; - uint16_t msg_type; - } status; + ldp_raw_update_s *raw_update_start; + ldp_raw_update_s *raw_update; + bool raw_update_sending; - uint16_t max_pdu_len; + struct timespec operational_timestamp; + struct timespec update_start_timestamp; + struct timespec update_stop_timestamp; - ldp_instance_s *instance; - ldp_state_t state; - - io_buffer_t read_buf; - io_buffer_t write_buf; + bool teardown; /* Pointer to next peer of * corresponding instance. */ @@ -169,9 +201,13 @@ typedef struct ldp_session_ { typedef struct ldp_adjacency_ { bbl_network_interface_s *interface; ldp_instance_s *instance; - ldp_session_s *session; struct timer_ *hello_timer; + struct timer_ *hold_timer; + + uint16_t hold_time; + + ldp_adjacency_state state; /* Pointer to next adjacency of * corresponding instance with. */ diff --git a/code/bngblaster/src/ldp/ldp_hello.c b/code/bngblaster/src/ldp/ldp_hello.c index bd466840..3e125d07 100644 --- a/code/bngblaster/src/ldp/ldp_hello.c +++ b/code/bngblaster/src/ldp/ldp_hello.c @@ -8,28 +8,6 @@ */ #include "ldp.h" -void -ldp_hello_job(timer_s *timer) -{ - ldp_adjacency_s *adjacency = timer->data; - bbl_network_interface_s *interface = adjacency->interface; - interface->send_requests |= BBL_IF_SEND_LDP_HELLO; -} - -/** - * ldp_hello_start - * - * @param config LDP configuration - * @param adjacency LDP adjacency - */ -void -ldp_hello_start(ldp_config_s *config, ldp_adjacency_s *adjacency) -{ - timer_add_periodic(&g_ctx->timer_root, &adjacency->hello_timer, - "LDP Hello", config->hello_interval, 0, adjacency, - &ldp_hello_job); -} - /** * ldp_hello_encode * @@ -58,7 +36,6 @@ ldp_hello_encode(bbl_network_interface_s *interface, eth->type = ETH_TYPE_IPV4; eth->next = &ipv4; eth->dst = (uint8_t*)all_routers_mac; - ipv4.dst = IPV4_MC_ALL_ROUTERS; ipv4.src = interface->ip.address; ipv4.ttl = 1; @@ -80,6 +57,53 @@ ldp_hello_encode(bbl_network_interface_s *interface, return result; } +void +ldp_hello_job(timer_s *timer) +{ + ldp_adjacency_s *adjacency = timer->data; + bbl_network_interface_s *interface = adjacency->interface; + interface->send_requests |= BBL_IF_SEND_LDP_HELLO; +} + +/** + * ldp_hello_start + * + * @param config LDP configuration + * @param adjacency LDP adjacency + */ +void +ldp_hello_start(ldp_adjacency_s *adjacency) +{ + time_t hello_interval = adjacency->hold_time/3U; + if(!hello_interval) { + hello_interval = 1; + } + timer_add_periodic(&g_ctx->timer_root, &adjacency->hello_timer, + "LDP Hello", hello_interval, 0, adjacency, + &ldp_hello_job); +} + +void +ldp_hello_hold_timeout_job(timer_s *timer) +{ + ldp_adjacency_s *adjacency = timer->data; + + if(adjacency->state == LDP_ADJACENCY_STATE_DOWN) { + return; + } + + adjacency->state = LDP_ADJACENCY_STATE_DOWN; + LOG(LDP, "LDP hold timeout on interface %s\n", adjacency->interface->name); +} + +static void +ldp_hello_restart_hold_timeout(ldp_adjacency_s *adjacency) +{ + adjacency->state = LDP_ADJACENCY_STATE_UP; + timer_add(&g_ctx->timer_root, &adjacency->hold_timer, + "LDP HOLD TIMEOUT", adjacency->hold_time, 0, adjacency, &ldp_hello_hold_timeout_job); +} + /** * ldp_hello_rx * @@ -97,10 +121,37 @@ ldp_hello_rx(bbl_network_interface_s *interface, bbl_ldp_hello_s *ldp) { ldp_adjacency_s *adjacency = interface->ldp_adjacency; + ldp_instance_s *instance; + ldp_session_s *session; - UNUSED(adjacency); UNUSED(eth); - UNUSED(ipv4); - UNUSED(ldp); + interface->stats.ldp_udp_rx++; + if(!adjacency) { + return; + } + + instance = adjacency->instance; + session = instance->sessions; + + if(ldp->hold_time > 0 && ldp->hold_time < adjacency->hold_time) { + adjacency->hold_time = ldp->hold_time; + ldp_hello_start(adjacency); + } + ldp_hello_restart_hold_timeout(adjacency); + + while(session) { + if(session->peer.lsr_id == ldp->lsr_id && + session->peer.label_space_id == ldp->label_space_id) { + if(session->state == LDP_CLOSED) { + break; + } else { + return; + } + } + session = session->next; + } + + /* Init LDP session. */ + ldp_session_init(session, adjacency, ipv4, ldp); } \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_hello.h b/code/bngblaster/src/ldp/ldp_hello.h index a2079192..a9eae30a 100644 --- a/code/bngblaster/src/ldp/ldp_hello.h +++ b/code/bngblaster/src/ldp/ldp_hello.h @@ -9,15 +9,15 @@ #ifndef __BBL_LDP_HELLO_H__ #define __BBL_LDP_HELLO_H__ -void -ldp_hello_start(ldp_config_s *config, ldp_adjacency_s *adjacency); - protocol_error_t ldp_hello_encode(bbl_network_interface_s *interface, uint8_t *buf, uint16_t *len, bbl_ethernet_header_s *eth); -void +void +ldp_hello_start(ldp_adjacency_s *adjacency); + +void ldp_hello_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_ipv4_s *ipv4, diff --git a/code/bngblaster/src/ldp/ldp_interface.c b/code/bngblaster/src/ldp/ldp_interface.c index ce4a610a..fe0247dd 100644 --- a/code/bngblaster/src/ldp/ldp_interface.c +++ b/code/bngblaster/src/ldp/ldp_interface.c @@ -8,15 +8,6 @@ */ #include "ldp.h" -void -ldp_interface_hello_job(timer_s *timer) -{ - ldp_adjacency_s *adjacency = timer->data; - bbl_network_interface_s *interface = adjacency->interface; - - interface->send_requests |= BBL_IF_SEND_LDP_HELLO; -} - /** * ldp_interface_init * @@ -42,8 +33,9 @@ ldp_interface_init(bbl_network_interface_s *interface, instance->adjacencies = adjacency; adjacency->instance = instance; adjacency->interface = interface; + adjacency->hold_time = config->hold_time; interface->ldp_adjacency = adjacency; - ldp_hello_start(config, adjacency); + ldp_hello_start(adjacency); return true; } \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_message.c b/code/bngblaster/src/ldp/ldp_message.c new file mode 100644 index 00000000..e757ad22 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_message.c @@ -0,0 +1,160 @@ +/* + * BNG Blaster (BBL) - LDP Protocol Messages + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +static void +ldp_pdu_close(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + uint16_t len; + + if(session->pdu_start_idx) { + /* update PDU length */ + len = buffer->idx - buffer->start_idx; + write_be_uint(buffer->data+session->pdu_start_idx-2, 2, len); + session->pdu_start_idx = 0; + } +} + +static bool +ldp_pdu_init(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + + if(session->pdu_start_idx) { + ldp_pdu_close(session); + } + + if(IO_BUF_REMAINING(buffer) < LDP_MIN_PDU_LEN) { + return false; + } + + push_be_uint(buffer, 2, 1); /* PDU Version */ + push_be_uint(buffer, 2, 0); /* PDU Length */ + session->pdu_start_idx = buffer->idx; + push_data(buffer, (uint8_t*)&session->local.lsr_id, 4); + push_be_uint(buffer, 2, session->local.label_space_id); + return true; +} + +static void +ldp_msg_close(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + uint16_t len; + + if(session->msg_start_idx) { + /* update message length */ + len = buffer->idx - buffer->start_idx; + write_be_uint(buffer->data+session->msg_start_idx-2, 2, len); + session->msg_start_idx = 0; + } +} + +static bool +ldp_msg_init(ldp_session_s *session, uint16_t type) +{ + io_buffer_t *buffer = &session->write_buf; + + if(session->msg_start_idx) { + ldp_msg_close(session); + } + + if(IO_BUF_REMAINING(buffer) < LDP_MIN_MSG_LEN) { + return false; + } + + push_be_uint(buffer, 2, type); /* Type */ + push_be_uint(buffer, 2, 0); /* Length */ + session->msg_start_idx = buffer->idx; + push_be_uint(buffer, session->message_id++, 4); + return true; +} + +static void +ldp_tlv_close(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + uint16_t len; + + if(session->tlv_start_idx) { + /* update length */ + len = buffer->idx - buffer->start_idx; + write_be_uint(buffer->data+session->tlv_start_idx-2, 2, len); + session->tlv_start_idx = 0; + } +} + +static bool +ldp_tlv_init(ldp_session_s *session, uint16_t type) +{ + io_buffer_t *buffer = &session->write_buf; + + if(session->tlv_start_idx) { + ldp_tlv_close(session); + } + + if(IO_BUF_REMAINING(buffer) < LDP_MIN_TLV_LEN) { + return false; + } + + push_be_uint(buffer, 2, type); /* Type */ + push_be_uint(buffer, 2, 0); /* Length */ + session->tlv_start_idx = buffer->idx; + push_be_uint(buffer, session->message_id++, 4); + return true; +} + +void +ldp_push_init_message(ldp_session_s *session, bool keepalive) +{ + io_buffer_t *buffer = &session->write_buf; + + ldp_pdu_init(session); + ldp_msg_init(session, LDP_MESSAGE_TYPE_INITIALIZATION); + ldp_tlv_init(session, LDP_TLV_TYPE_COMMON_SESSION_PARAMETERS); + push_be_uint(buffer, 2, 1); + push_be_uint(buffer, 2, session->local.keepalive_time); + push_be_uint(buffer, 2, 0); + push_be_uint(buffer, 2, LDP_MAX_PDU_LEN_INIT); + push_data(buffer, (uint8_t*)&session->peer.lsr_id, 4); + push_be_uint(buffer, 2, session->peer.label_space_id); + ldp_tlv_close(session); + ldp_msg_close(session); + if(!keepalive) { + ldp_msg_init(session, LDP_MESSAGE_TYPE_KEEPALIVE); + ldp_msg_close(session); + } + ldp_pdu_close(session); +} + +void +ldp_push_keepalive_message(ldp_session_s *session) +{ + ldp_pdu_init(session); + ldp_msg_init(session, LDP_MESSAGE_TYPE_KEEPALIVE); + ldp_msg_close(session); + ldp_pdu_close(session); +} + +void +ldp_push_notification_message(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + + ldp_pdu_init(session); + ldp_msg_init(session, LDP_MESSAGE_TYPE_NOTIFICATION); + ldp_tlv_init(session, LDP_TLV_TYPE_STATUS); + push_be_uint(buffer, 4, session->error_code); + push_be_uint(buffer, 4, 0); + push_be_uint(buffer, 2, 0); + ldp_tlv_close(session); + ldp_msg_close(session); + ldp_pdu_close(session); +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_message.h b/code/bngblaster/src/ldp/ldp_message.h new file mode 100644 index 00000000..825f08c7 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_message.h @@ -0,0 +1,21 @@ +/* + * BNG Blaster (BBL) - LDP Protocol Messages + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_MESSAGE_H__ +#define __BBL_LDP_MESSAGE_H__ + +void +ldp_push_init_message(ldp_session_s *session, bool keepalive); + +void +ldp_push_keepalive_message(ldp_session_s *session); + +void +ldp_push_notification_message(ldp_session_s *session); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_pdu.c b/code/bngblaster/src/ldp/ldp_pdu.c deleted file mode 100644 index 00c1b1ba..00000000 --- a/code/bngblaster/src/ldp/ldp_pdu.c +++ /dev/null @@ -1,9 +0,0 @@ -/* - * BNG Blaster (BBL) - LDP PDU - * - * Christian Giese, November 2022 - * - * Copyright (C) 2020-2022, RtBrick, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ -#include "ldp.h" diff --git a/code/bngblaster/src/ldp/ldp_pdu.h b/code/bngblaster/src/ldp/ldp_pdu.h deleted file mode 100644 index aedfa4be..00000000 --- a/code/bngblaster/src/ldp/ldp_pdu.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * BNG Blaster (BBL) - LDP PDU - * - * Christian Giese, November 2022 - * - * Copyright (C) 2020-2022, RtBrick, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ -#ifndef __BBL_LDP_PDU_H__ -#define __BBL_LDP_PDU_H__ - -#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index 963657c3..17e778cc 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -1,6 +1,6 @@ /* - * BNG Blaster (BBL) - LDP Message Receive Functions + * BNG Blaster (BBL) - LDP Receive Functions * * Christian Giese, March 2022 * @@ -24,6 +24,60 @@ struct keyval_ ldp_msg_names[] = { { 0, NULL} }; +static void +ldp_decode_error(ldp_session_s *session) +{ + LOG(BGP, "LDP (%s:%u - %s:%u) invalid PDU received\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + + if(!session->error_code) { + session->error_code = LDP_STATUS_INTERNAL_ERROR; + } + ldp_session_close(session); +} + +static bool +ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) +{ + UNUSED(session); + UNUSED(start); + UNUSED(length); + return true; +} + +static bool +ldp_initialization(ldp_session_s *session, uint8_t *start, uint16_t length) +{ + uint8_t *tlv_start = start; + uint16_t tlv_type; + uint16_t tlv_length; + + while(length > LDP_TLV_LEN_MIN) { + tlv_type = read_be_uint(tlv_start, 2) & 0x3FFF; + tlv_length = read_be_uint(tlv_start+2, 2); + if(tlv_length+2 > length) { + return false; + } + + switch(tlv_type) { + case LDP_TLV_TYPE_COMMON_SESSION_PARAMETERS: + if(tlv_length < 14) { + return false; + } + session->peer.keepalive_time = read_be_uint(tlv_start+6, 2); + session->peer.max_pdu_len = read_be_uint(tlv_start+10, 2); + break; + default: + break; + } + length -= (tlv_length+2); + tlv_start += (tlv_length+2); + } + ldp_session_fsm(session, LDP_EVENT_RX_INITIALIZED); + return true; +} + /* * When there is only little data left and * the buffer start is close to buffer end, @@ -31,7 +85,7 @@ struct keyval_ ldp_msg_names[] = { * the tail data to the buffer head. */ static void -ldp_rebase_buffer(io_buffer_t *buffer) +ldp_rebase_read_buffer(io_buffer_t *buffer) { uint32_t size; @@ -62,13 +116,14 @@ ldp_read(ldp_session_s *session) uint8_t *msg_start; uint16_t msg_type; uint16_t msg_length; + uint32_t msg_id; while(true) { pdu_start = buffer->data+buffer->start_idx; size = buffer->idx - buffer->start_idx; /* Minimum PDU size */ - if(size < 4) { + if(size < LDP_MIN_PDU_LEN) { break; } @@ -82,16 +137,16 @@ ldp_read(ldp_session_s *session) if(pdu_version != 1 || pdu_length < LDP_IDENTIFIER_LEN || pdu_length > session->max_pdu_len) { - //ldp_decode_error(session); - break; + ldp_decode_error(session); + return; } - length = pdu_length+4; - /* Full message on the wire to consume? */ + length = pdu_length+4; if(length > size) { break; } + session->stats.pdu_rx++; /* Read LDP Identifier. */ lsr_id = read_be_uint(pdu_start+4, 4); @@ -99,31 +154,44 @@ ldp_read(ldp_session_s *session) if(lsr_id != session->peer.lsr_id || label_space_id != session->peer.label_space_id) { - /* TODO: INVALID MESSAGE!!!! */ - break; + ldp_decode_error(session); + return; } pdu_length -= LDP_IDENTIFIER_LEN; msg_start = pdu_start+10; - while(pdu_length >= 4) { + while(pdu_length >= LDP_MIN_MSG_LEN) { + session->stats.message_rx++; + msg_type = read_be_uint(msg_start, 2); msg_length = read_be_uint(msg_start+2, 2); + msg_id = read_be_uint(msg_start+4, 4); + if(msg_length+4 > pdu_length) { + ldp_decode_error(session); + return; + } - UNUSED(msg_length); + LOG(DEBUG, "LDP (%s:%u - %s:%u) read %s message (%u)\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + keyval_get_key(ldp_msg_names, msg_type), msg_id); - LOG(DEBUG, "LDP (%s - %s) read %s message\n", - format_ipv4_address(&session->local.ipv4_address), - format_ipv4_address(&session->peer.ipv4_address), - keyval_get_key(ldp_msg_names, msg_type)); - - session->stats.message_rx++; switch(msg_type) { case LDP_MESSAGE_TYPE_NOTIFICATION: + if(!ldp_notification(session, msg_start+8, msg_length-4)) { + ldp_decode_error(session); + return; + } break; case LDP_MESSAGE_TYPE_INITIALIZATION: + if(!ldp_initialization(session, msg_start+8, msg_length-4)) { + ldp_decode_error(session); + return; + } break; case LDP_MESSAGE_TYPE_KEEPALIVE: session->stats.keepalive_rx++; + ldp_session_fsm(session, LDP_EVENT_RX_KEEPALIVE); break; case LDP_MESSAGE_TYPE_ADDRESS: case LDP_MESSAGE_TYPE_ADDRESS_WITHDRAW: @@ -136,15 +204,13 @@ ldp_read(ldp_session_s *session) default: break; } + msg_start += msg_length+4; } - /* Reset hold timer */ - //ldp_restart_hold_timer(session, session->instance->config->hold_time); - /* Progress pointer to next LDP PDU. */ buffer->start_idx += length; } - ldp_rebase_buffer(buffer); + ldp_rebase_read_buffer(buffer); } void @@ -154,17 +220,13 @@ ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) io_buffer_t *buffer = &session->read_buf; if(buf) { if(buffer->idx+len > buffer->size) { - LOG(ERROR, "LDP (%s - %s) receive error (read buffer exhausted)\n", - format_ipv4_address(&session->local.ipv4_address), - format_ipv4_address(&session->peer.ipv4_address)); - -#if 0 - if(!session->status_code) { - peer->status_code = 0x00000019; /* Cease */ - session->error_subcode = 8; /* Out of resources */ + LOG(ERROR, "LDP (%s:%u - %s:%u) receive error (read buffer exhausted)\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + if(!session->error_code) { + session->error_code = LDP_STATUS_INTERNAL_ERROR; } -#endif - //ldp_session_close(session); + ldp_session_close(session); return; } memcpy(buffer->data+buffer->idx, buf, len); @@ -172,5 +234,4 @@ ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) } else { ldp_read(session); } -} - +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_receive.h b/code/bngblaster/src/ldp/ldp_receive.h new file mode 100644 index 00000000..0055e156 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_receive.h @@ -0,0 +1,15 @@ +/* + * BNG Blaster (BBL) - LDP Receive Functions + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_RECEIVE_H__ +#define __BBL_LDP_RECEIVE_H__ + +void +ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c new file mode 100644 index 00000000..b9e4b71f --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -0,0 +1,516 @@ +/* + * BNG Blaster (BBL) - LDP Session + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" +extern bool g_init_phase; +extern volatile bool g_teardown; + +const char * +ldp_session_state_string(ldp_state_t state) +{ + switch(state) { + case LDP_CLOSED: return "closed"; + case LDP_IDLE: return "idle"; + case LDP_LISTEN: return "listen"; + case LDP_CONNECT: return "connect"; + case LDP_INITIALIZED: return "initialized"; + case LDP_OPENREC: return "open-received"; + case LDP_OPENSENT: return "open-sent"; + case LDP_OPERATIONAL: return "operational"; + case LDP_CLOSING: return "closing"; + case LDP_ERROR: return "error"; + default: return "unknown"; + } +} + +static void +ldp_session_state_change(ldp_session_s *session, ldp_state_t new_state) +{ + if(session->state != new_state) { + LOG(LDP, "LDP (%s:%u - %s:%u) state changed from %s -> %s\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + ldp_session_state_string(session->state), + ldp_session_state_string(new_state)); + session->state = new_state; + } +} + +/** + * ldp_session_reset_read_buffer + * + * @param session LDP session + */ +void +ldp_session_reset_read_buffer(ldp_session_s *session) +{ + session->read_buf.idx = 0; + session->read_buf.start_idx = 0; +} + +/** + * ldp_session_reset_write_buffer + * + * @param session LDP session + */ +void +ldp_session_reset_write_buffer(ldp_session_s *session) +{ + if(session->tcpc && session->tcpc->state == BBL_TCP_STATE_SENDING) { + return; + } + session->write_buf.idx = 0; + session->write_buf.start_idx = 0; +} + +/** + * ldp_session_send + * + * @param session LDP session + */ +static bool +ldp_session_send(ldp_session_s *session) +{ + bbl_tcp_ctx_s *tcpc = session->tcpc; + if(tcpc && tcpc->state == BBL_TCP_STATE_SENDING && + tcpc->tx.buf == session->write_buf.data && + tcpc->tx.len < session->write_buf.idx) { + tcpc->tx.len = session->write_buf.idx; + return true; + } + return bbl_tcp_send(session->tcpc, session->write_buf.data, session->write_buf.idx); +} + +void +ldp_raw_update_stop_cb(void *arg) +{ + ldp_session_s *session = (ldp_session_s*)arg; + struct timespec time_diff; + + session->tcpc->idle_cb = NULL; + + clock_gettime(CLOCK_MONOTONIC, &session->update_stop_timestamp); + timespec_sub(&time_diff, + &session->update_stop_timestamp, + &session->update_start_timestamp); + + session->raw_update_sending = false; + session->stats.pdu_tx += session->raw_update->pdu; + session->stats.message_tx += session->raw_update->messages; + + LOG(LDP, "LDP (%s:%u - %s:%u) raw update stop after %lds\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + time_diff.tv_sec); +} + +void +ldp_session_update_job(timer_s *timer) +{ + ldp_session_s *session = timer->data; + + if(session->state == LDP_OPERATIONAL) { + if(session->raw_update && !session->raw_update_sending) { + if(bbl_tcp_send(session->tcpc, session->raw_update->buf, session->raw_update->len)) { + session->raw_update_sending = true; + + LOG(LDP, "LDP (%s:%u - %s:%u) raw update start\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + + clock_gettime(CLOCK_MONOTONIC, &session->update_start_timestamp); + session->tcpc->idle_cb = ldp_raw_update_stop_cb; + } else { + goto RETRY; + } + } + } + timer->periodic = false; + return; + +RETRY: + /* Try again ... */ + timer_add_periodic(&g_ctx->timer_root, &session->connect_timer, + "LDP UPDATE", 1, 0, session, + &ldp_session_update_job); + +} + +void +ldp_session_keepalive_job(timer_s *timer) +{ + ldp_session_s *session = timer->data; + + if(session->state == LDP_OPERATIONAL) { + if(session->tcpc && session->tcpc->state == BBL_TCP_STATE_IDLE) { + ldp_session_reset_write_buffer(session); + ldp_push_keepalive_message(session); + if(ldp_session_send(session)) { + session->stats.pdu_tx++; + session->stats.message_tx++; + session->stats.keepalive_tx++; + } + } + } +} + +void +ldp_session_keepalive_timeout_job(timer_s *timer) +{ + ldp_session_s *session = timer->data; + + LOG(LDP, "LDP (%s:%u - %s:%u) keepalive timer expired\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + + if(!session->error_code) { + session->error_code = LDP_STATUS_KEEPALIVE_TIMER_EXPIRED; + } + ldp_session_close(session); +} + +static void +ldp_session_restart_keepalive_timeout(ldp_session_s *session) +{ + timer_add(&g_ctx->timer_root, &session->keepalive_timer, + "LDP TIMEOUT", session->keepalive_time, 0, session, &ldp_session_keepalive_timeout_job); +} + +static void +ldp_session_operational(ldp_session_s *session) +{ + time_t keepalive_interval; + + ldp_session_state_change(session, LDP_OPERATIONAL); + clock_gettime(CLOCK_MONOTONIC, &session->operational_timestamp); + + /* Select max PDU length. */ + if(session->peer.max_pdu_len > 255 && + session->peer.max_pdu_len < session->local.max_pdu_len) { + session->max_pdu_len = session->peer.max_pdu_len; + } else { + session->max_pdu_len = session->local.max_pdu_len; + } + + /* Start LDP keepalive */ + if(session->peer.keepalive_time > 0 && + session->peer.keepalive_time < session->local.keepalive_time) { + session->keepalive_time = session->peer.keepalive_time; + } else { + session->keepalive_time = session->local.keepalive_time; + } + keepalive_interval = session->keepalive_time/2U; + if(!keepalive_interval) { + keepalive_interval = 1; + } + + timer_add_periodic(&g_ctx->timer_root, &session->keepalive_timer, + "LDP KEEPALIVE", keepalive_interval, 0, session, + &ldp_session_keepalive_job); + + /* Start LDP updates */ + timer_add(&g_ctx->timer_root, &session->update_timer, + "LDP UPDATE", 0, 0, session, + &ldp_session_update_job); +} + +void +ldp_session_fsm(ldp_session_s *session, ldp_event_t event) +{ + switch(event) { + case LDP_EVENT_START: + ldp_session_state_change(session, LDP_INITIALIZED); + if(session->active) { + ldp_session_reset_write_buffer(session); + ldp_push_init_message(session, false); + ldp_session_send(session); + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENSENT); + } + break; + case LDP_EVENT_RX_INITIALIZED: + if(session->state == LDP_INITIALIZED) { + ldp_session_reset_write_buffer(session); + ldp_push_init_message(session, true); + ldp_session_send(session); + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENREC); + } else if(session->state == LDP_OPENSENT) { + ldp_session_reset_write_buffer(session); + ldp_push_keepalive_message(session); + ldp_session_send(session); + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENREC); + } else { + if(!session->error_code) { + session->error_code = LDP_STATUS_INTERNAL_ERROR; + } + ldp_session_close(session); + } + break; + case LDP_EVENT_RX_KEEPALIVE: + if(session->state == LDP_OPENREC) { + ldp_session_operational(session); + } + ldp_session_restart_keepalive_timeout(session); + break; + default: + break; + } +} + +void +ldp_connected_cb(void *arg) +{ + ldp_session_s *session = (ldp_session_s*)arg; + ldp_session_fsm(session, LDP_EVENT_START); +} + +void +ldp_error_cb(void *arg, err_t err) { + ldp_session_s *session = (ldp_session_s*)arg; + + LOG(LDP, "LDP (%s:%u - %s:%u) TCP error %d (%s)\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + err, tcp_err_string(err)); + + ldp_session_state_change(session, LDP_ERROR); + ldp_session_close(session); +} + +void +ldp_session_connect_job(timer_s *timer) +{ + ldp_session_s *session = timer->data; + time_t timeout = 5; + + if(g_init_phase) { + /* Wait for all network interfaces to be resolved */ + timeout = 1; + } else if(session->state == LDP_IDLE) { + /* Connect TCP session */ + session->tcpc = bbl_tcp_ipv4_connect( + session->interface, + &session->local.ipv4_address, + &session->peer.ipv4_address, + LDP_PORT); + + if(session->tcpc) { + session->tcpc->arg = session; + session->tcpc->connected_cb = ldp_connected_cb; + session->tcpc->receive_cb = ldp_receive_cb; + session->tcpc->error_cb = ldp_error_cb; + ldp_session_state_change(session, LDP_CONNECT); + /* Close session if not established within 60 seconds */ + timeout = 60; + } else { + LOG(LDP, "LDP (%s:%u - %s:%u) TCP connect failed\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + } + } else if(session->state == LDP_OPERATIONAL) { + timer->periodic = false; + return; + } else { + LOG(LDP, "LDP (%s:%u - %s:%u) connect timeout\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + + ldp_session_close(session); + timer->periodic = false; + return; + } + + timer_add_periodic(&g_ctx->timer_root, &session->connect_timer, + "LDP CONNECT", timeout, 0, session, + &ldp_session_connect_job); +} + +static void +ldp_session_listen(ldp_session_s *session) +{ + session->tcpc = bbl_tcp_ipv4_listen( + session->interface, + &session->local.ipv4_address, + LDP_PORT); + + if(session->tcpc) { + session->tcpc->arg = session; + session->tcpc->connected_cb = ldp_connected_cb; + session->tcpc->receive_cb = ldp_receive_cb; + session->tcpc->error_cb = ldp_error_cb; + + ldp_session_state_change(session, LDP_LISTEN); + timer_add_periodic(&g_ctx->timer_root, &session->connect_timer, + "LDP CONNECT", 60, 0, session, + &ldp_session_connect_job); + } else { + LOG(LDP, "LDP (%s:%u - %s:%u) TCP listen failed\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + ldp_session_close(session); + } +} + +/** + * ldp_session_connect + * + * @param session BGP session + * @param delay delay + */ +void +ldp_session_connect(ldp_session_s *session, time_t delay) +{ + if(!session->teardown && session->state == LDP_CLOSED) { + bbl_tcp_ctx_free(session->tcpc); + session->tcpc = NULL; + + ldp_session_reset_read_buffer(session); + ldp_session_reset_write_buffer(session); + + session->pdu_start_idx = 0; + session->msg_start_idx = 0; + session->tlv_start_idx = 0; + session->message_id = 0; + session->error_code = 0; + + session->max_pdu_len = LDP_MAX_PDU_LEN_INIT; + session->keepalive_time = session->local.keepalive_time; + + session->stats.pdu_rx = 0; + session->stats.pdu_tx = 0; + session->stats.message_rx = 0; + session->stats.message_tx = 0; + session->stats.keepalive_rx = 0; + session->stats.keepalive_tx = 0; + + session->raw_update = session->raw_update_start; + session->raw_update_sending = false; + + session->operational_timestamp.tv_sec = 0; + session->operational_timestamp.tv_nsec = 0; + session->update_start_timestamp.tv_sec = 0; + session->update_start_timestamp.tv_nsec = 0; + session->update_stop_timestamp.tv_sec = 0; + session->update_stop_timestamp.tv_nsec = 0; + + if(session->active) { + ldp_session_state_change(session, LDP_IDLE); + timer_add(&g_ctx->timer_root, &session->connect_timer, + "LDP CONNECT", delay, 0, session, + &ldp_session_connect_job); + } else { + ldp_session_listen(session); + } + } +} + +/** + * ldp_session_init + * + * @param session LDP session (optional) + * @param adjacency LDP adjacency + * @param ipv4 received IPv4 header + * @param ldp received LDP hello PDU + */ +void +ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, + bbl_ipv4_s *ipv4, bbl_ldp_hello_s *ldp) +{ + ldp_instance_s *instance = adjacency->instance; + ldp_config_s *config = instance->config; + + if(!session) { + session = calloc(1, sizeof(ldp_session_s)); + session->next = instance->sessions; + instance->sessions = session; + session->local.ipv4_address = config->ipv4_transport_address; + session->local.lsr_id = config->lsr_id; + session->local.label_space_id = 0; + session->local.keepalive_time = config->keepalive_interval; + session->local.max_pdu_len = LDP_MAX_PDU_LEN_INIT; + } + session->max_pdu_len = session->local.max_pdu_len; + session->keepalive_time = session->local.keepalive_time; + + if(ldp->ipv4_transport_address) { + session->peer.ipv4_address = ldp->ipv4_transport_address; + } else { + session->peer.ipv4_address = ipv4->src; + } + session->peer.lsr_id = ldp->lsr_id; + session->peer.label_space_id = ldp->label_space_id; + session->peer.keepalive_time = 0; + session->peer.max_pdu_len = 0; + + if(be32toh(session->local.ipv4_address) > be32toh(session->peer.ipv4_address)) { + session->active = true; + } else { + session->active = false; + } + + ldp_session_connect(session, 0); +} + +void +ldp_session_close_job(timer_s *timer) +{ + ldp_session_s *session = timer->data; + if(session->state > LDP_IDLE) { + /* Close TCP session */ + bbl_tcp_close(session->tcpc); + } + ldp_session_state_change(session, LDP_CLOSED); + if(!session->teardown) { + ldp_session_connect(session, 5); + } +} + +/** + * ldp_session_close + * + * @param session LDP session + */ +void +ldp_session_close(ldp_session_s *session) +{ + time_t delay = 0; + + /* Stop all timers */ + timer_del(session->connect_timer); + timer_del(session->keepalive_timer); + timer_del(session->update_timer); + + if(!session->error_code) { + session->error_code = LDP_STATUS_SHUTDOWN; + } + + if(session->state > LDP_CONNECT && session->state < LDP_CLOSING) { + LOG(LDP, "LDP (%s:%u - %s:%u) send notification message\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + + ldp_session_reset_write_buffer(session); + ldp_push_notification_message(session); + ldp_session_send(session); + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_CLOSING); + delay = 3; + } + + timer_add(&g_ctx->timer_root, &session->close_timer, + "LDP CLOSE", delay, 0, session, + &ldp_session_close_job); +} + + diff --git a/code/bngblaster/src/ldp/ldp_session.h b/code/bngblaster/src/ldp/ldp_session.h new file mode 100644 index 00000000..a2a5499a --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_session.h @@ -0,0 +1,25 @@ +/* + * BNG Blaster (BBL) - LDP Session + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_SESSION_H__ +#define __BBL_LDP_SESSION_H__ + +void +ldp_session_fsm(ldp_session_s *session, ldp_event_t event); + +void +ldp_session_connect(ldp_session_s *session, time_t delay); + +void +ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, + bbl_ipv4_s *ipv4, bbl_ldp_hello_s *ldp); + +void +ldp_session_close(ldp_session_s *session); + +#endif \ No newline at end of file diff --git a/code/common/src/common.h b/code/common/src/common.h index 6595bdc8..1eb804b2 100644 --- a/code/common/src/common.h +++ b/code/common/src/common.h @@ -53,6 +53,9 @@ #define POWEROF2(x) ((((x)-1) & (x)) == 0) /* true if x is a power of 2 */ #define BITS_TO_BYTES(_len) ((_len+7) >> 3) +#define IO_BUF_REMAINING(_buf) (_buf->size - _buf->idx) + + /* Key-Value structure. */ typedef struct keyval_ { uint32_t val; /* value */ diff --git a/docsrc/sources/install.rst b/docsrc/sources/install.rst index ceb7e29d..888f2716 100644 --- a/docsrc/sources/install.rst +++ b/docsrc/sources/install.rst @@ -152,7 +152,14 @@ The following steps are required to build the BNG Blaster with experimental Tested with DPDK version 21.11.2 (LTS) and Ubuntu 22.04 (LTS)! -Download and Install DPDK: +It is recommended to install the DPDK development package if possible: + +.. code-block:: none + + sudo apt install dpdk libdpdk-dev + +This package does not support all NIC types (e.g. Mellanox, ...), +which requires to download and installing DPDK manually: https://doc.dpdk.org/guides/linux_gsg/build_dpdk.html .. code-block:: none From bf29000c58dd193aabdac117866ca842acb99e82 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Fri, 9 Dec 2022 23:21:11 +0000 Subject: [PATCH 05/27] LDP fixes --- code/bngblaster/src/bbl_config.c | 2 ++ code/bngblaster/src/bbl_protocols.c | 10 +++++----- code/bngblaster/src/ldp/ldp_hello.c | 4 +++- code/bngblaster/src/ldp/ldp_session.c | 1 + 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index 16f1f4df..e931cd97 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1371,6 +1371,8 @@ json_parse_ldp_config(json_t *ldp, ldp_config_s *ldp_config) json_t *value = NULL; const char *s = NULL; + g_ctx->tcp = true; + value = json_object_get(ldp, "instance-id"); if(value) { ldp_config->id = json_number_value(value); diff --git a/code/bngblaster/src/bbl_protocols.c b/code/bngblaster/src/bbl_protocols.c index c9f4ec50..273c9e1a 100644 --- a/code/bngblaster/src/bbl_protocols.c +++ b/code/bngblaster/src/bbl_protocols.c @@ -565,7 +565,7 @@ encode_ldp_hello(uint8_t *buf, uint16_t *len, bbl_ldp_hello_s *ldp) BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); /* LDP identifier (LSR ID + label space) */ - *(uint32_t*)buf = htobe32(ldp->lsr_id); + *(uint32_t*)buf = ldp->lsr_id; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); *(uint16_t*)buf = htobe16(ldp->label_space_id); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); @@ -595,7 +595,7 @@ encode_ldp_hello(uint8_t *buf, uint16_t *len, bbl_ldp_hello_s *ldp) BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); *(uint16_t*)buf = htobe16(4); BUMP_WRITE_BUFFER(buf, len, sizeof(uint16_t)); - *(uint32_t*)buf = htobe32(ldp->ipv4_transport_address); + *(uint32_t*)buf = ldp->ipv4_transport_address; BUMP_WRITE_BUFFER(buf, len, sizeof(uint32_t)); return PROTOCOL_SUCCESS; @@ -2843,8 +2843,8 @@ decode_ldp_hello(uint8_t *buf, uint16_t len, len = pdu_len; /* LDP identifier (LSR ID + label space) */ - ldp->lsr_id = be32toh(*(uint32_t*)buf); - BUMP_BUFFER(buf, len, sizeof(uint16_t)); + ldp->lsr_id = *(uint32_t*)buf; + BUMP_BUFFER(buf, len, sizeof(uint32_t)); ldp->label_space_id = be16toh(*(uint16_t*)buf); BUMP_BUFFER(buf, len, sizeof(uint16_t)); @@ -2887,7 +2887,7 @@ decode_ldp_hello(uint8_t *buf, uint16_t len, if(tlv_len != 4) { return DECODE_ERROR; } - ldp->ipv4_transport_address = be32toh(*(uint16_t*)buf); + ldp->ipv4_transport_address = *(uint32_t*)buf; break; default: break; diff --git a/code/bngblaster/src/ldp/ldp_hello.c b/code/bngblaster/src/ldp/ldp_hello.c index 3e125d07..38ac2bc5 100644 --- a/code/bngblaster/src/ldp/ldp_hello.c +++ b/code/bngblaster/src/ldp/ldp_hello.c @@ -52,7 +52,7 @@ ldp_hello_encode(bbl_network_interface_s *interface, result = encode_ethernet(buf, len, eth); if(result == PROTOCOL_SUCCESS) { LOG(DEBUG, "LDP TX hello on interface %s\n", interface->name); - adjacency->interface->stats.ldp_udp_tx++; + adjacency->interface->stats.ldp_udp_tx++; } return result; } @@ -131,6 +131,8 @@ ldp_hello_rx(bbl_network_interface_s *interface, return; } + LOG(DEBUG, "LDP RX hello on interface %s\n", interface->name); + instance = adjacency->instance; session = instance->sessions; diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index b9e4b71f..f8c6735e 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -439,6 +439,7 @@ ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, session->local.keepalive_time = config->keepalive_interval; session->local.max_pdu_len = LDP_MAX_PDU_LEN_INIT; } + session->interface = adjacency->interface; session->max_pdu_len = session->local.max_pdu_len; session->keepalive_time = session->local.keepalive_time; From 29fb098c9792e9711b6aa8faca4006a5aa89bc68 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Mon, 12 Dec 2022 16:52:14 +0000 Subject: [PATCH 06/27] LDP session setup working --- code/bngblaster/src/bbl_tcp.c | 114 ++++++++++++++++++-------- code/bngblaster/src/bbl_tcp.h | 4 +- code/bngblaster/src/ldp/ldp.c | 7 ++ code/bngblaster/src/ldp/ldp_def.h | 5 ++ code/bngblaster/src/ldp/ldp_message.c | 11 ++- code/bngblaster/src/ldp/ldp_receive.c | 15 ++-- code/bngblaster/src/ldp/ldp_session.c | 86 +++++++++++++------ code/bngblaster/src/ldp/ldp_session.h | 3 + 8 files changed, 175 insertions(+), 70 deletions(-) diff --git a/code/bngblaster/src/bbl_tcp.c b/code/bngblaster/src/bbl_tcp.c index 4dfc6e30..496ce5d3 100644 --- a/code/bngblaster/src/bbl_tcp.c +++ b/code/bngblaster/src/bbl_tcp.c @@ -12,7 +12,8 @@ #endif const char * -tcp_err_string(err_t err) { +tcp_err_string(err_t err) +{ switch(err) { case ERR_OK: return "ok"; case ERR_MEM: return "out of memory error"; @@ -43,14 +44,17 @@ tcp_err_string(err_t err) { * @param tcpc TCP context */ void -bbl_tcp_close(bbl_tcp_ctx_s *tcpc) { +bbl_tcp_close(bbl_tcp_ctx_s *tcpc) +{ if(tcpc) { if(tcpc->pcb) { - tcp_arg(tcpc->pcb, NULL); - tcp_sent(tcpc->pcb, NULL); - tcp_recv(tcpc->pcb, NULL); - tcp_err(tcpc->pcb, NULL); - tcp_poll(tcpc->pcb, NULL, 0); + if(!tcpc->listen) { + tcp_arg(tcpc->pcb, NULL); + tcp_sent(tcpc->pcb, NULL); + tcp_recv(tcpc->pcb, NULL); + tcp_err(tcpc->pcb, NULL); + tcp_poll(tcpc->pcb, NULL, 0); + } tcp_close(tcpc->pcb); } tcpc->state = BBL_TCP_STATE_CLOSED; @@ -75,8 +79,8 @@ bbl_tcp_ctx_free(bbl_tcp_ctx_s *tcpc) { } static bbl_tcp_ctx_s * -bbl_tcp_ctx_new(bbl_network_interface_s *interface) { - +bbl_tcp_ctx_new(bbl_network_interface_s *interface) +{ bbl_tcp_ctx_s *tcpc; /* Init TCP context */ @@ -103,7 +107,8 @@ bbl_tcp_ctx_new(bbl_network_interface_s *interface) { } err_t -bbl_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) { +bbl_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ bbl_tcp_ctx_s *tcpc = arg; uint16_t tx = tcp_sndbuf(tpcb); err_t result = ERR_OK; @@ -138,7 +143,8 @@ bbl_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) { } err_t -bbl_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { +bbl_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ bbl_tcp_ctx_s *tcpc = arg; struct pbuf *_p; @@ -172,7 +178,8 @@ bbl_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { * ERR_RST: the connection was reset by the remote host */ void -bbl_tcp_error_cb(void *arg, err_t err) { +bbl_tcp_error_cb(void *arg, err_t err) +{ bbl_tcp_ctx_s *tcpc = arg; tcpc->state = BBL_TCP_STATE_CLOSED; tcpc->pcb = NULL; @@ -253,15 +260,13 @@ bbl_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) } err_t -bbl_tcp_ipv4_listen_accept(void *arg, struct tcp_pcb *tpcb, err_t err) +bbl_tcp_ipv4_listen_accepted(void *arg, struct tcp_pcb *tpcb, err_t err) { bbl_tcp_ctx_s *listen = arg; bbl_tcp_ctx_s *tcpc; UNUSED(err); /* TODO!!! */ - //tcp_setprio(tpcb, TCP_PRIO_MIN); - tcpc = calloc(1, sizeof(bbl_tcp_ctx_s)); if(!tcpc) { return ERR_MEM; @@ -269,15 +274,20 @@ bbl_tcp_ipv4_listen_accept(void *arg, struct tcp_pcb *tpcb, err_t err) tcpc->interface = listen->interface; tcpc->af = listen->af; tcpc->local_port = listen->local_port; - tcpc->local_ipv4 = listen->local_ipv4; + tcpc->remote_port = tpcb->remote_port; + + tcpc->accepted_cb = listen->accepted_cb; + tcpc->connected_cb = listen->connected_cb; + tcpc->idle_cb = listen->idle_cb; + tcpc->receive_cb = listen->receive_cb; + tcpc->error_cb = listen->error_cb; + tcpc->poll_cb = listen->poll_cb; + tcpc->poll_interval = listen->poll_interval; + tcpc->arg = listen->arg; tcpc->pcb = tpcb; tcp_arg(tpcb, tcpc); - if(listen->accepted_cb) { - (listen->accepted_cb)(tcpc, listen->arg); - } - /* Add send/receive callback functions. */ tcp_sent(tpcb, bbl_tcp_sent_cb); tcp_recv(tpcb, bbl_tcp_recv_cb); @@ -286,6 +296,38 @@ bbl_tcp_ipv4_listen_accept(void *arg, struct tcp_pcb *tpcb, err_t err) } tcp_err(tpcb, bbl_tcp_error_cb); + if(tcpc->af == AF_INET) { + tcpc->local_ipv4 = tpcb->local_ip.u_addr.ip4.addr; + tcpc->remote_ipv4 = tpcb->remote_ip.u_addr.ip4.addr; + LOG(TCP, "TCP (%s %s:%u - %s:%u) session accepted\n", + tcpc->interface->name, + format_ipv4_address(&tcpc->local_ipv4), tcpc->local_port, + format_ipv4_address(&tcpc->remote_ipv4), tcpc->remote_port); + } else { + memcpy(tcpc->local_ipv6, tpcb->local_ip.u_addr.ip6.addr, IPV6_ADDR_LEN); + memcpy(tcpc->remote_ipv6, tpcb->remote_ip.u_addr.ip6.addr, IPV6_ADDR_LEN); + LOG(TCP, "TCP (%s %s:%u - %s:%u) session accepted\n", + tcpc->interface->name, + format_ipv6_address(&tcpc->local_ipv6), tcpc->local_port, + format_ipv6_address(&tcpc->remote_ipv6), tcpc->remote_port); + } + + /* Call application TCP accepted callback function. */ + if(listen->accepted_cb) { + if((listen->accepted_cb)(tcpc, listen->arg) != ERR_OK) { + free(tcpc); + tcp_abort(tpcb); + return ERR_ABRT; + }; + } + + tcpc->state = BBL_TCP_STATE_IDLE; + + /* Call application TCP connected callback function. */ + if(tcpc->connected_cb) { + (tcpc->connected_cb)(tcpc->arg); + } + bbl_tcp_sent_cb(tcpc, tpcb, 0); return ERR_OK; } @@ -318,8 +360,9 @@ bbl_tcp_ipv4_listen(bbl_network_interface_s *interface, ipv4addr_t *address, uin } tcpc->pcb = tcp_listen(tcpc->pcb); - tcp_accept(tcpc->pcb, bbl_tcp_ipv4_listen_accept); + tcp_accept(tcpc->pcb, bbl_tcp_ipv4_listen_accepted); + tcpc->listen = true; tcpc->af = AF_INET; tcpc->local_port = port; tcpc->local_ipv4 = *address; @@ -432,8 +475,8 @@ bbl_tcp_ipv4_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, * @return TCP context */ bbl_tcp_ctx_s * -bbl_tcp_ipv6_connect(bbl_network_interface_s *interface, ipv6addr_t *src, ipv6addr_t *dst, uint16_t port) { - +bbl_tcp_ipv6_connect(bbl_network_interface_s *interface, ipv6addr_t *src, ipv6addr_t *dst, uint16_t port) +{ if(!g_ctx->tcp) { /* TCP not enabled! */ return NULL; @@ -454,7 +497,8 @@ bbl_tcp_ipv6_connect(bbl_network_interface_s *interface, ipv6addr_t *src, ipv6ad * @param interface receiving interface */ void -bbl_tcp_ipv6_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_ipv6_s *ipv6) { +bbl_tcp_ipv6_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, bbl_ipv6_s *ipv6) +{ struct pbuf *pbuf; UNUSED(eth); @@ -484,8 +528,8 @@ bbl_tcp_ipv6_rx(bbl_network_interface_s *interface, bbl_ethernet_header_s *eth, * @return true if successful */ bool -bbl_tcp_send(bbl_tcp_ctx_s *tcpc, uint8_t *buf, uint32_t len) { - +bbl_tcp_send(bbl_tcp_ctx_s *tcpc, uint8_t *buf, uint32_t len) +{ if(tcpc->state == BBL_TCP_STATE_SENDING) { return false; } @@ -504,7 +548,8 @@ bbl_tcp_send(bbl_tcp_ctx_s *tcpc, uint8_t *buf, uint32_t len) { * Function of type netif_output_fn */ err_t -bbl_tcp_netif_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) { +bbl_tcp_netif_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) +{ bbl_network_interface_s *interface = netif->state; bbl_ethernet_header_s eth = {0}; UNUSED(ipaddr); @@ -526,7 +571,8 @@ bbl_tcp_netif_output_ipv4(struct netif *netif, struct pbuf *p, const ip4_addr_t * Function of type netif_output_ip6_fn */ err_t -bbl_tcp_netif_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) { +bbl_tcp_netif_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) +{ bbl_network_interface_s *interface = netif->state; bbl_ethernet_header_s eth = {0}; UNUSED(ipaddr); @@ -545,7 +591,8 @@ bbl_tcp_netif_output_ipv6(struct netif *netif, struct pbuf *p, const ip6_addr_t } err_t -bbl_tcp_netif_init(struct netif *netif) { +bbl_tcp_netif_init(struct netif *netif) +{ netif->output = bbl_tcp_netif_output_ipv4; netif->output_ip6 = bbl_tcp_netif_output_ipv6; netif_set_up(netif); @@ -562,7 +609,8 @@ bbl_tcp_netif_init(struct netif *netif) { * @return return true if successfully */ bool -bbl_tcp_network_interface_init(bbl_network_interface_s *interface, bbl_network_config_s *config) { +bbl_tcp_network_interface_init(bbl_network_interface_s *interface, bbl_network_config_s *config) +{ if(!g_ctx->tcp) { /* TCP not enabled! */ return true; @@ -577,7 +625,8 @@ bbl_tcp_network_interface_init(bbl_network_interface_s *interface, bbl_network_c } void -bbl_tcp_simer(timer_s *timer) { +bbl_tcp_simer(timer_s *timer) +{ UNUSED(timer); sys_check_timeouts(); } @@ -588,7 +637,8 @@ bbl_tcp_simer(timer_s *timer) { * Init TCP (LwIP) and start global TCP timer job. */ void -bbl_tcp_init() { +bbl_tcp_init() +{ if(!g_ctx->tcp) { /* TCP not enabled! */ return; diff --git a/code/bngblaster/src/bbl_tcp.h b/code/bngblaster/src/bbl_tcp.h index 0ccafc11..0a3b3f3f 100644 --- a/code/bngblaster/src/bbl_tcp.h +++ b/code/bngblaster/src/bbl_tcp.h @@ -19,13 +19,13 @@ typedef enum bbl_tcp_state_ { BBL_TCP_STATE_CLOSED, + BBL_TCP_STATE_LISTEN, BBL_TCP_STATE_CONNECTING, BBL_TCP_STATE_IDLE, BBL_TCP_STATE_SENDING, - BBL_TCP_STATE_LISTEN, } bbl_tcp_state_t; -typedef void (*bbl_tcp_accepted_fn)(bbl_tcp_ctx_s *tcpc, void *arg); +typedef err_t (*bbl_tcp_accepted_fn)(bbl_tcp_ctx_s *tcpc, void *arg); typedef void (*bbl_tcp_callback_fn)(void *arg); typedef void (*bbl_tcp_receive_fn)(void *arg, uint8_t *buf, uint16_t len); typedef void (*bbl_tcp_error_fn)(void *arg, err_t err); diff --git a/code/bngblaster/src/ldp/ldp.c b/code/bngblaster/src/ldp/ldp.c index 3273286d..a40365cb 100644 --- a/code/bngblaster/src/ldp/ldp.c +++ b/code/bngblaster/src/ldp/ldp.c @@ -50,10 +50,17 @@ void ldp_teardown() { ldp_instance_s *instance = g_ctx->ldp_instances; + ldp_session_s *session; while(instance) { if(!instance->teardown) { LOG(LDP, "Teardown LDP instance %u\n", instance->config->id); instance->teardown = true; + session = instance->sessions; + while(session) { + session->teardown = true; + ldp_session_close(session); + session = session->next; + } timer_add(&g_ctx->timer_root, &instance->teardown_timer, "LDP TEARDOWN", instance->config->teardown_time, 0, instance, &ldp_teardown_job); diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index d0ff5296..b9641952 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -18,6 +18,8 @@ #define LDP_MIN_MSG_LEN 8 #define LDP_MIN_TLV_LEN 4 +#define LDP_BUF_SIZE 256*1024 + #define LDP_MESSAGE_TYPE_NOTIFICATION 0x0001 #define LDP_MESSAGE_TYPE_HELLO 0x0100 #define LDP_MESSAGE_TYPE_INITIALIZATION 0x0200 @@ -133,9 +135,11 @@ typedef struct ldp_session_ { ldp_instance_s *instance; bbl_network_interface_s *interface; bbl_tcp_ctx_s *tcpc; + bbl_tcp_ctx_s *listen_tcpc; struct timer_ *connect_timer; struct timer_ *keepalive_timer; + struct timer_ *keepalive_timeout_timer; struct timer_ *close_timer; struct timer_ *update_timer; @@ -150,6 +154,7 @@ typedef struct ldp_session_ { uint32_t message_id; uint32_t error_code; + bool decode_error; bool active; ldp_state_t state; uint16_t max_pdu_len; diff --git a/code/bngblaster/src/ldp/ldp_message.c b/code/bngblaster/src/ldp/ldp_message.c index e757ad22..40c1cbd4 100644 --- a/code/bngblaster/src/ldp/ldp_message.c +++ b/code/bngblaster/src/ldp/ldp_message.c @@ -16,7 +16,7 @@ ldp_pdu_close(ldp_session_s *session) if(session->pdu_start_idx) { /* update PDU length */ - len = buffer->idx - buffer->start_idx; + len = buffer->idx - session->pdu_start_idx; write_be_uint(buffer->data+session->pdu_start_idx-2, 2, len); session->pdu_start_idx = 0; } @@ -51,7 +51,7 @@ ldp_msg_close(ldp_session_s *session) if(session->msg_start_idx) { /* update message length */ - len = buffer->idx - buffer->start_idx; + len = buffer->idx - session->msg_start_idx; write_be_uint(buffer->data+session->msg_start_idx-2, 2, len); session->msg_start_idx = 0; } @@ -73,7 +73,7 @@ ldp_msg_init(ldp_session_s *session, uint16_t type) push_be_uint(buffer, 2, type); /* Type */ push_be_uint(buffer, 2, 0); /* Length */ session->msg_start_idx = buffer->idx; - push_be_uint(buffer, session->message_id++, 4); + push_be_uint(buffer, 4, session->message_id++); return true; } @@ -85,7 +85,7 @@ ldp_tlv_close(ldp_session_s *session) if(session->tlv_start_idx) { /* update length */ - len = buffer->idx - buffer->start_idx; + len = buffer->idx - session->tlv_start_idx; write_be_uint(buffer->data+session->tlv_start_idx-2, 2, len); session->tlv_start_idx = 0; } @@ -107,7 +107,6 @@ ldp_tlv_init(ldp_session_s *session, uint16_t type) push_be_uint(buffer, 2, type); /* Type */ push_be_uint(buffer, 2, 0); /* Length */ session->tlv_start_idx = buffer->idx; - push_be_uint(buffer, session->message_id++, 4); return true; } @@ -127,7 +126,7 @@ ldp_push_init_message(ldp_session_s *session, bool keepalive) push_be_uint(buffer, 2, session->peer.label_space_id); ldp_tlv_close(session); ldp_msg_close(session); - if(!keepalive) { + if(keepalive) { ldp_msg_init(session, LDP_MESSAGE_TYPE_KEEPALIVE); ldp_msg_close(session); } diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index 17e778cc..cde3ded2 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -27,10 +27,11 @@ struct keyval_ ldp_msg_names[] = { static void ldp_decode_error(ldp_session_s *session) { - LOG(BGP, "LDP (%s:%u - %s:%u) invalid PDU received\n", + LOG(LDP, "LDP (%s:%u - %s:%u) invalid PDU received\n", format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + session->decode_error = true; if(!session->error_code) { session->error_code = LDP_STATUS_INTERNAL_ERROR; } @@ -118,7 +119,7 @@ ldp_read(ldp_session_s *session) uint16_t msg_length; uint32_t msg_id; - while(true) { + while(!session->decode_error) { pdu_start = buffer->data+buffer->start_idx; size = buffer->idx - buffer->start_idx; @@ -149,7 +150,7 @@ ldp_read(ldp_session_s *session) session->stats.pdu_rx++; /* Read LDP Identifier. */ - lsr_id = read_be_uint(pdu_start+4, 4); + lsr_id = *(uint32_t*)(pdu_start+4); label_space_id = read_be_uint(pdu_start+8, 2); if(lsr_id != session->peer.lsr_id || @@ -159,7 +160,7 @@ ldp_read(ldp_session_s *session) } pdu_length -= LDP_IDENTIFIER_LEN; - msg_start = pdu_start+10; + msg_start = pdu_start+LDP_MIN_PDU_LEN; while(pdu_length >= LDP_MIN_MSG_LEN) { session->stats.message_rx++; @@ -176,6 +177,8 @@ ldp_read(ldp_session_s *session) format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, keyval_get_key(ldp_msg_names, msg_type), msg_id); + ldp_session_restart_keepalive_timeout(session); + switch(msg_type) { case LDP_MESSAGE_TYPE_NOTIFICATION: if(!ldp_notification(session, msg_start+8, msg_length-4)) { @@ -204,7 +207,8 @@ ldp_read(ldp_session_s *session) default: break; } - msg_start += msg_length+4; + pdu_length -= (msg_length+4); + msg_start += (msg_length+4); } /* Progress pointer to next LDP PDU. */ @@ -218,6 +222,7 @@ ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) { ldp_session_s *session = (ldp_session_s*)arg; io_buffer_t *buffer = &session->read_buf; + if(buf) { if(buffer->idx+len > buffer->size) { LOG(ERROR, "LDP (%s:%u - %s:%u) receive error (read buffer exhausted)\n", diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index f8c6735e..221b6d3f 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -174,10 +174,10 @@ ldp_session_keepalive_timeout_job(timer_s *timer) ldp_session_close(session); } -static void +void ldp_session_restart_keepalive_timeout(ldp_session_s *session) { - timer_add(&g_ctx->timer_root, &session->keepalive_timer, + timer_add(&g_ctx->timer_root, &session->keepalive_timeout_timer, "LDP TIMEOUT", session->keepalive_time, 0, session, &ldp_session_keepalive_timeout_job); } @@ -204,7 +204,7 @@ ldp_session_operational(ldp_session_s *session) } else { session->keepalive_time = session->local.keepalive_time; } - keepalive_interval = session->keepalive_time/2U; + keepalive_interval = session->keepalive_time/3U; if(!keepalive_interval) { keepalive_interval = 1; } @@ -228,27 +228,30 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) if(session->active) { ldp_session_reset_write_buffer(session); ldp_push_init_message(session, false); - ldp_session_send(session); - session->stats.pdu_tx++; - session->stats.message_tx++; - ldp_session_state_change(session, LDP_OPENSENT); + if(ldp_session_send(session)) { + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENSENT); + } } break; case LDP_EVENT_RX_INITIALIZED: if(session->state == LDP_INITIALIZED) { ldp_session_reset_write_buffer(session); ldp_push_init_message(session, true); - ldp_session_send(session); - session->stats.pdu_tx++; - session->stats.message_tx++; - ldp_session_state_change(session, LDP_OPENREC); + if(ldp_session_send(session)) { + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENREC); + } } else if(session->state == LDP_OPENSENT) { ldp_session_reset_write_buffer(session); ldp_push_keepalive_message(session); - ldp_session_send(session); - session->stats.pdu_tx++; - session->stats.message_tx++; - ldp_session_state_change(session, LDP_OPENREC); + if(ldp_session_send(session)) { + session->stats.pdu_tx++; + session->stats.message_tx++; + ldp_session_state_change(session, LDP_OPENREC); + } } else { if(!session->error_code) { session->error_code = LDP_STATUS_INTERNAL_ERROR; @@ -260,17 +263,29 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) if(session->state == LDP_OPENREC) { ldp_session_operational(session); } - ldp_session_restart_keepalive_timeout(session); break; default: break; } } +err_t +ldp_accepted_cb(bbl_tcp_ctx_s *tcpc, void *arg) +{ + ldp_session_s *session = (ldp_session_s*)arg; + if(session->state == LDP_LISTEN) { + session->tcpc = tcpc; + } else { + return ERR_ABRT; + } + return ERR_OK; +} + void ldp_connected_cb(void *arg) { ldp_session_s *session = (ldp_session_s*)arg; + g_ctx->routing_sessions++; ldp_session_fsm(session, LDP_EVENT_START); } @@ -338,16 +353,17 @@ ldp_session_connect_job(timer_s *timer) static void ldp_session_listen(ldp_session_s *session) { - session->tcpc = bbl_tcp_ipv4_listen( + session->listen_tcpc = bbl_tcp_ipv4_listen( session->interface, &session->local.ipv4_address, LDP_PORT); - if(session->tcpc) { - session->tcpc->arg = session; - session->tcpc->connected_cb = ldp_connected_cb; - session->tcpc->receive_cb = ldp_receive_cb; - session->tcpc->error_cb = ldp_error_cb; + if(session->listen_tcpc) { + session->listen_tcpc->arg = session; + session->listen_tcpc->accepted_cb = ldp_accepted_cb; + session->listen_tcpc->connected_cb = ldp_connected_cb; + session->listen_tcpc->receive_cb = ldp_receive_cb; + session->listen_tcpc->error_cb = ldp_error_cb; ldp_session_state_change(session, LDP_LISTEN); timer_add_periodic(&g_ctx->timer_root, &session->connect_timer, @@ -372,7 +388,9 @@ ldp_session_connect(ldp_session_s *session, time_t delay) { if(!session->teardown && session->state == LDP_CLOSED) { bbl_tcp_ctx_free(session->tcpc); + bbl_tcp_ctx_free(session->listen_tcpc); session->tcpc = NULL; + session->listen_tcpc = NULL; ldp_session_reset_read_buffer(session); ldp_session_reset_write_buffer(session); @@ -382,7 +400,7 @@ ldp_session_connect(ldp_session_s *session, time_t delay) session->tlv_start_idx = 0; session->message_id = 0; session->error_code = 0; - + session->decode_error = false; session->max_pdu_len = LDP_MAX_PDU_LEN_INIT; session->keepalive_time = session->local.keepalive_time; @@ -453,6 +471,12 @@ ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, session->peer.keepalive_time = 0; session->peer.max_pdu_len = 0; + /* Init read/write buffer */ + session->read_buf.data = malloc(LDP_BUF_SIZE); + session->read_buf.size = LDP_BUF_SIZE; + session->write_buf.data = malloc(LDP_BUF_SIZE); + session->write_buf.size = LDP_BUF_SIZE; + if(be32toh(session->local.ipv4_address) > be32toh(session->peer.ipv4_address)) { session->active = true; } else { @@ -466,9 +490,16 @@ void ldp_session_close_job(timer_s *timer) { ldp_session_s *session = timer->data; + if(g_ctx->routing_sessions) g_ctx->routing_sessions--; + + /* Close TCP session */ + if(session->listen_tcpc) { + bbl_tcp_ctx_free(session->listen_tcpc); + session->listen_tcpc = NULL; + } if(session->state > LDP_IDLE) { - /* Close TCP session */ - bbl_tcp_close(session->tcpc); + bbl_tcp_ctx_free(session->tcpc); + session->tcpc = NULL; } ldp_session_state_change(session, LDP_CLOSED); if(!session->teardown) { @@ -486,9 +517,14 @@ ldp_session_close(ldp_session_s *session) { time_t delay = 0; + LOG(LDP, "LDP (%s:%u - %s:%u) close session\n", + format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, + format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + /* Stop all timers */ timer_del(session->connect_timer); timer_del(session->keepalive_timer); + timer_del(session->keepalive_timeout_timer); timer_del(session->update_timer); if(!session->error_code) { diff --git a/code/bngblaster/src/ldp/ldp_session.h b/code/bngblaster/src/ldp/ldp_session.h index a2a5499a..c920f702 100644 --- a/code/bngblaster/src/ldp/ldp_session.h +++ b/code/bngblaster/src/ldp/ldp_session.h @@ -9,6 +9,9 @@ #ifndef __BBL_LDP_SESSION_H__ #define __BBL_LDP_SESSION_H__ +void +ldp_session_restart_keepalive_timeout(ldp_session_s *session); + void ldp_session_fsm(ldp_session_s *session, ldp_event_t event); From 86fdbe5f1342dcc2261689ddcf314dadeb82f19c Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Mon, 12 Dec 2022 22:00:52 +0000 Subject: [PATCH 07/27] LDP commands --- code/bngblaster/src/bbl_config.c | 27 +- code/bngblaster/src/bbl_ctrl.c | 6 + code/bngblaster/src/bbl_ctx.h | 1 + code/bngblaster/src/bbl_session.c | 2 +- code/bngblaster/src/bgp/bgp_def.h | 1 - code/bngblaster/src/ldp/ldp.h | 6 +- code/bngblaster/src/ldp/ldp_ctrl.c | 407 +++++++++++++++++++++++ code/bngblaster/src/ldp/ldp_ctrl.h | 30 ++ code/bngblaster/src/ldp/ldp_def.h | 6 +- code/bngblaster/src/ldp/ldp_raw_update.c | 123 +++++++ code/bngblaster/src/ldp/ldp_raw_update.h | 15 + code/bngblaster/src/ldp/ldp_receive.c | 2 +- code/bngblaster/src/ldp/ldp_session.c | 11 +- code/bngblaster/src/ldp/ldp_session.h | 6 + 14 files changed, 629 insertions(+), 14 deletions(-) create mode 100644 code/bngblaster/src/ldp/ldp_ctrl.c create mode 100644 code/bngblaster/src/ldp/ldp_ctrl.h create mode 100644 code/bngblaster/src/ldp/ldp_raw_update.c create mode 100644 code/bngblaster/src/ldp/ldp_raw_update.h diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index e931cd97..3ce0ae62 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1381,11 +1381,11 @@ json_parse_ldp_config(json_t *ldp, ldp_config_s *ldp_config) return false; } - value = json_object_get(ldp, "keepalive-interval"); + value = json_object_get(ldp, "keepalive-time"); if(json_is_number(value)) { - ldp_config->keepalive_interval = json_number_value(value); + ldp_config->keepalive_time = json_number_value(value); } else { - ldp_config->keepalive_interval = LDP_DEFAULT_KEEPALIVE_INTERVAL; + ldp_config->keepalive_time = LDP_DEFAULT_KEEPALIVE_TIME; } value = json_object_get(ldp, "hold-time"); @@ -1425,6 +1425,13 @@ json_parse_ldp_config(json_t *ldp, ldp_config_s *ldp_config) } else { ldp_config->ipv4_transport_address = ldp_config->lsr_id; } + + if(json_unpack(ldp, "{s:s}", "raw-update-file", &s) == 0) { + ldp_config->raw_update_file = strdup(s); + if(!ldp_raw_update_load(ldp_config->raw_update_file, true)) { + return false; + } + } return true; } @@ -2333,6 +2340,20 @@ json_parse_config(json_t *root) } } + /* Pre-Load LDP RAW update files */ + sub = json_object_get(root, "ldp-raw-update-files"); + if(json_is_array(sub)) { + size = json_array_size(sub); + for(i = 0; i < size; i++) { + s = json_string_value(json_array_get(sub, i)); + if(s) { + if(!ldp_raw_update_load(s, true)) { + return false; + } + } + } + } + /* Interface Configuration */ section = json_object_get(root, "interfaces"); if(json_is_object(section)) { diff --git a/code/bngblaster/src/bbl_ctrl.c b/code/bngblaster/src/bbl_ctrl.c index 378346fe..17ae1b4a 100644 --- a/code/bngblaster/src/bbl_ctrl.c +++ b/code/bngblaster/src/bbl_ctrl.c @@ -156,6 +156,12 @@ struct action actions[] = { {"bgp-teardown", bgp_ctrl_teardown, true}, {"bgp-raw-update-list", bgp_ctrl_raw_update_list, true}, {"bgp-raw-update", bgp_ctrl_raw_update, false}, + {"ldp-adjacencies", ldp_ctrl_adjacencies, true}, + {"ldp-sessions", ldp_ctrl_sessions, true}, + {"ldp-disconnect", ldp_ctrl_disconnect, false}, + {"ldp-teardown", ldp_ctrl_teardown, true}, + {"ldp-raw-update-list", ldp_ctrl_raw_update_list, true}, + {"ldp-raw-update", ldp_ctrl_raw_update, false}, {"monkey-start", bbl_session_ctrl_monkey_start, false}, {"monkey-stop", bbl_session_ctrl_monkey_stop, false}, {"lag-info", bbl_lag_ctrl_info, true}, diff --git a/code/bngblaster/src/bbl_ctx.h b/code/bngblaster/src/bbl_ctx.h index 414e1c9e..a9d16ca8 100644 --- a/code/bngblaster/src/bbl_ctx.h +++ b/code/bngblaster/src/bbl_ctx.h @@ -96,6 +96,7 @@ typedef struct bbl_ctx_ bgp_raw_update_s *bgp_raw_updates; isis_instance_s *isis_instances; ldp_instance_s *ldp_instances; + ldp_raw_update_s *ldp_raw_updates; /* Scratchpad memory */ uint8_t *sp; diff --git a/code/bngblaster/src/bbl_session.c b/code/bngblaster/src/bbl_session.c index 2452ef7b..9d087524 100644 --- a/code/bngblaster/src/bbl_session.c +++ b/code/bngblaster/src/bbl_session.c @@ -1384,7 +1384,7 @@ bbl_session_ctrl_terminate(int fd, uint32_t session_id, json_t *arguments) /* Terminate single matching session ... */ session = bbl_session_get(session_id); if(session) { - json_unpack(arguments, "{s:i}", "reconnect-delay", &session->reconnect_delay); + json_unpack(arguments, "{s:i}", "reconnect-delay", &reconnect_delay); if(reconnect_delay > 0) { session->reconnect_delay = reconnect_delay; } diff --git a/code/bngblaster/src/bgp/bgp_def.h b/code/bngblaster/src/bgp/bgp_def.h index c1c67d2b..ab905c2c 100644 --- a/code/bngblaster/src/bgp/bgp_def.h +++ b/code/bngblaster/src/bgp/bgp_def.h @@ -65,7 +65,6 @@ typedef struct bgp_config_ { bool start_traffic; char *network_interface; - char *mrt_file; char *raw_update_file; /* Pointer to next instance */ diff --git a/code/bngblaster/src/ldp/ldp.h b/code/bngblaster/src/ldp/ldp.h index 801327f0..38dafc7f 100644 --- a/code/bngblaster/src/ldp/ldp.h +++ b/code/bngblaster/src/ldp/ldp.h @@ -11,11 +11,13 @@ #include "../bbl.h" #include "ldp_def.h" -#include "ldp_message.h" #include "ldp_hello.h" #include "ldp_interface.h" -#include "ldp_receive.h" #include "ldp_session.h" +#include "ldp_message.h" +#include "ldp_receive.h" +#include "ldp_raw_update.h" +#include "ldp_ctrl.h" bool ldp_init(); diff --git a/code/bngblaster/src/ldp/ldp_ctrl.c b/code/bngblaster/src/ldp/ldp_ctrl.c new file mode 100644 index 00000000..ce2ee2c8 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_ctrl.c @@ -0,0 +1,407 @@ +/* + * BNG Blaster (BBL) - LDP CTRL (Control Commands) + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" +#include "../bbl_ctrl.h" + +static const char * +raw_update_state(ldp_session_s *session) +{ + if(session->raw_update) { + if(session->update_start_timestamp.tv_sec) { + if(session->raw_update_sending) { + return "sending"; + } + if(session->update_stop_timestamp.tv_sec) { + return "done"; + } + } else { + return "wait"; + } + } + return NULL; +} + +int +ldp_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root, *adjacencies, *adjacency; + + ldp_instance_s *ldp_instance = g_ctx->ldp_instances; + ldp_adjacency_s *ldp_adjacency; + + int ldp_instance_id = 0; + + /* Unpack further arguments */ + json_unpack(arguments, "{s:i}", "ldp-instance-id", &ldp_instance_id); + + adjacencies = json_array(); + while(ldp_instance) { + if(ldp_instance_id > 0 && ldp_instance_id != ldp_instance->config->id) { + ldp_instance = ldp_instance->next; + continue; + } + ldp_adjacency = ldp_instance->adjacencies; + while(ldp_adjacency) { + adjacency = json_pack("{si ss ss}", + "ldp-instance-id", ldp_adjacency->instance->config->id, + "interface", ldp_adjacency->interface->name, + "state", ldp_adjacency->state == LDP_ADJACENCY_STATE_UP ? "up" : "down"); + if(adjacency) { + json_array_append(adjacencies, adjacency); + } + ldp_adjacency = ldp_adjacency->next; + } + ldp_instance = ldp_instance->next; + } + + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "ldp-adjacencies", adjacencies); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(adjacencies); + } + return result; +} + +static json_t * +ldp_ctrl_session_json(ldp_session_s *session) +{ + json_t *root = NULL; + json_t *stats = NULL; + + const char *raw_update_file = NULL; + + if(!session) { + return NULL; + } + + if(session->raw_update) { + raw_update_file = session->raw_update->file; + } + + stats = json_pack("{si si si si si si}", + "pdu-rx", session->stats.pdu_rx, + "pdu-tx", session->stats.pdu_tx, + "messages-rx", session->stats.message_rx, + "messages-tx", session->stats.message_tx, + "keepalive-rx", session->stats.keepalive_rx, + "keepalive-tx", session->stats.keepalive_tx); + + if(!stats) { + return NULL; + } + + root = json_pack("{si ss ss ss si ss ss si ss ss* ss* so*}", + "ldp-instance-id", session->instance->config->id, + "interface", session->interface->name, + "local-address", format_ipv4_address(&session->local.ipv4_address), + "local-lsr-id", format_ipv4_address(&session->local.lsr_id), + "local-label-space-id", session->local.label_space_id, + "peer-address", format_ipv4_address(&session->peer.ipv4_address), + "peer-lsr-id", format_ipv4_address(&session->peer.lsr_id), + "peer-label-space-id", session->peer.label_space_id, + "state", ldp_session_state_string(session->state), + "raw-update-state", raw_update_state(session), + "raw-update-file", raw_update_file, + "stats", stats); + + if(!root) { + if(stats) json_decref(stats); + } + return root; +} + +int +ldp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root, *sessions, *session; + + ldp_instance_s *ldp_instance = g_ctx->ldp_instances; + ldp_session_s *ldp_session; + + const char *s; + uint32_t ipv4_local_address = 0; + uint32_t ipv4_peer_address = 0; + int ldp_instance_id = 0; + + /* Unpack further arguments */ + json_unpack(arguments, "{s:i}", "ldp-instance-id", &ldp_instance_id); + if(json_unpack(arguments, "{s:s}", "local-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_local_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid local-ipv4-address"); + } + } + if(json_unpack(arguments, "{s:s}", "peer-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_peer_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid peer-ipv4-address"); + } + } + + sessions = json_array(); + while(ldp_instance) { + if(ldp_instance_id > 0 && ldp_instance_id != ldp_instance->config->id) { + ldp_instance = ldp_instance->next; + continue; + } + ldp_session = ldp_instance->sessions; + while(ldp_session) { + if(ipv4_local_address && ldp_session->local.ipv4_address != ipv4_local_address) { + ldp_session = ldp_session->next; + continue; + } + if(ipv4_peer_address && ldp_session->peer.ipv4_address != ipv4_peer_address) { + ldp_session = ldp_session->next; + continue; + } + session = ldp_ctrl_session_json(ldp_session); + if(session) { + json_array_append(sessions, session); + } + ldp_session = ldp_session->next; + } + ldp_instance = ldp_instance->next; + } + + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "ldp-sessions", sessions); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(sessions); + } + return result; +} + +int +ldp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + ldp_teardown(); + return bbl_ctrl_status(fd, "ok", 200, NULL); +} + +int +ldp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root; + + ldp_instance_s *ldp_instance = g_ctx->ldp_instances; + ldp_session_s *ldp_session; + ldp_raw_update_s *raw_update; + + const char *s; + const char *file_path; + + uint16_t started = 0; + uint16_t skipped = 0; + uint16_t filtered = 0; + + uint32_t ipv4_local_address = 0; + uint32_t ipv4_peer_address = 0; + int ldp_instance_id = 0; + + /* Unpack further arguments */ + if(json_unpack(arguments, "{s:s}", "file", &file_path) != 0) { + return bbl_ctrl_status(fd, "error", 400, "missing argument file"); + } + json_unpack(arguments, "{s:i}", "ldp-instance-id", &ldp_instance_id); + if(json_unpack(arguments, "{s:s}", "local-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_local_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid local-ipv4-address"); + } + } + if(json_unpack(arguments, "{s:s}", "peer-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_peer_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid peer-ipv4-address"); + } + } + + /* Load file. */ + raw_update = ldp_raw_update_load(file_path, true); + if(!raw_update) { + return bbl_ctrl_status(fd, "error", 400, "failed to load file"); + } + + while(ldp_instance) { + ldp_session = ldp_instance->sessions; + while(ldp_session) { + if(ldp_instance_id > 0 && ldp_instance_id != ldp_instance->config->id) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ipv4_local_address && ldp_session->local.ipv4_address != ipv4_local_address) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ipv4_peer_address && ldp_session->peer.ipv4_address != ipv4_peer_address) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ldp_session->raw_update_sending) { + ldp_session = ldp_session->next; + skipped++; + continue; + } + ldp_session->raw_update = raw_update; + timer_add(&g_ctx->timer_root, &ldp_session->update_timer, + "LDP UPDATE", 0, 0, ldp_session, + &ldp_session_update_job); + + started++; + ldp_session = ldp_session->next; + } + ldp_instance = ldp_instance->next; + } + + root = json_pack("{ss si s{si si si}}", + "status", "ok", + "code", 200, + "ldp-raw-update", + "started", started, + "skipped", skipped, + "filtered", filtered); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + } + return result; +} + +int +ldp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))) +{ + int result = 0; + ldp_raw_update_s *raw_update = g_ctx->ldp_raw_updates; + json_t *root, *updates, *update; + + updates = json_array(); + + while(raw_update){ + update = json_pack("{ss* si si si}", + "file", raw_update->file, + "len", raw_update->len, + "pdu", raw_update->pdu, + "messages", raw_update->messages); + if(update) { + json_array_append(updates, update); + } + raw_update = raw_update->next; + } + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "ldp-raw-update-list", updates); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(updates); + } + return result; +} + +int +ldp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root; + + ldp_instance_s *ldp_instance = g_ctx->ldp_instances; + ldp_session_s *ldp_session; + + const char *s; + + uint16_t disconnected = 0; + uint16_t skipped = 0; + uint16_t filtered = 0; + + uint32_t ipv4_local_address = 0; + uint32_t ipv4_peer_address = 0; + int ldp_instance_id = 0; + + /* Unpack further arguments */ + json_unpack(arguments, "{s:i}", "ldp-instance-id", &ldp_instance_id); + if(json_unpack(arguments, "{s:s}", "local-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_local_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid local-ipv4-address"); + } + } + if(json_unpack(arguments, "{s:s}", "peer-ipv4-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &ipv4_peer_address)) { + return bbl_ctrl_status(fd, "error", 400, "invalid peer-ipv4-address"); + } + } + + while(ldp_instance) { + ldp_session = ldp_instance->sessions; + while(ldp_session) { + if(ldp_instance_id > 0 && ldp_instance_id != ldp_instance->config->id) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ipv4_local_address && ldp_session->local.ipv4_address != ipv4_local_address) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ipv4_peer_address && ldp_session->peer.ipv4_address != ipv4_peer_address) { + ldp_session = ldp_session->next; + filtered++; + continue; + } + if(ldp_session->state == LDP_CLOSED || ldp_session->state == LDP_CLOSING) { + ldp_session = ldp_session->next; + skipped++; + continue; + } + if(!ldp_session->error_code) { + ldp_session->error_code = LDP_STATUS_SHUTDOWN; + } + ldp_session_close(ldp_session); + disconnected++; + ldp_session = ldp_session->next; + } + ldp_instance = ldp_instance->next; + } + + root = json_pack("{ss si s{si si si}}", + "status", "ok", + "code", 200, + "ldp-disconnect", + "disconnected", disconnected, + "skipped", skipped, + "filtered", filtered); + + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + } + return result; +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_ctrl.h b/code/bngblaster/src/ldp/ldp_ctrl.h new file mode 100644 index 00000000..96e0a43a --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_ctrl.h @@ -0,0 +1,30 @@ +/* + * BNG Blaster (BBL) - LDP CTRL (Control Commands) + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_CTRL_H__ +#define __BBL_LDP_CTRL_H__ + +int +ldp_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +ldp_ctrl_sessions(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +ldp_ctrl_teardown(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +ldp_ctrl_raw_update(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +int +ldp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments __attribute__((unused))); + +int +ldp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index b9641952..58162c2b 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -62,7 +62,7 @@ #define LDP_STATUS_SHUTDOWN 0x0000000A #define LDP_STATUS_INTERNAL_ERROR 0x00000019 -#define LDP_DEFAULT_KEEPALIVE_INTERVAL 15 +#define LDP_DEFAULT_KEEPALIVE_TIME 15 #define LDP_DEFAULT_HOLD_TIME 15 #define LDP_DEFAULT_TEARDOWN_TIME 5 @@ -120,10 +120,12 @@ typedef struct ldp_config_ { const char *lsr_id_str; const char *hostname; - uint16_t keepalive_interval; + uint16_t keepalive_time; uint16_t hold_time; uint16_t teardown_time; + char *raw_update_file; + /* Pointer to next instance. */ struct ldp_config_ *next; } ldp_config_s; diff --git a/code/bngblaster/src/ldp/ldp_raw_update.c b/code/bngblaster/src/ldp/ldp_raw_update.c new file mode 100644 index 00000000..d8d8a020 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_raw_update.c @@ -0,0 +1,123 @@ +/* + * BNG Blaster (BBL) - LDP RAW Update Functions + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +static ldp_raw_update_s * +ldp_raw_update_load_file(const char *file, bool decode_file) +{ + ldp_raw_update_s *raw_update = NULL; + long fsize; + double fsize_kb; + + uint8_t *buf = NULL; + uint32_t len = 0; + + uint16_t pdu_length; + uint16_t msg_len; + + /* Open file */ + FILE *f = fopen(file, "rb"); + if(f == NULL) { + LOG(ERROR, "Failed to open LDP RAW update file %s\n", file); + return NULL; + } + + /* Get file size */ + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fsize_kb = fsize/1024.0; + fseek(f, 0, SEEK_SET); + + /* Load file into memory */ + raw_update = calloc(1, sizeof(ldp_raw_update_s)); + raw_update->file = strdup(file); + raw_update->buf = malloc(fsize); + raw_update->len = fsize; + if(fread(raw_update->buf, fsize, 1, f) != 1) { + fclose(f); + LOG(ERROR, "Failed to read LDP RAW update file %s\n", file); + goto ERROR; + } + fclose(f); + + if(decode_file) { + /* Decode update stream */ + buf = raw_update->buf; + len = raw_update->len; + while(len) { + if(len < LDP_MIN_PDU_LEN) { + goto DECODE_ERROR; + } + raw_update->pdu++; + + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + pdu_length = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + if(pdu_length > len) { + goto DECODE_ERROR; + } + BUMP_BUFFER(buf, len, LDP_IDENTIFIER_LEN); + while(pdu_length > LDP_MIN_MSG_LEN) { + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + msg_len = be16toh(*(uint16_t*)buf); + BUMP_BUFFER(buf, len, sizeof(uint16_t)); + pdu_length -= 4; + if(msg_len > pdu_length) { + goto DECODE_ERROR; + } + BUMP_BUFFER(buf, len, msg_len); + pdu_length -= msg_len; + raw_update->messages++; + } + } + } + LOG(INFO, "Loaded LDP RAW update file %s (%.2f KB, %u pdu, %u messages)\n", + file, fsize_kb, raw_update->pdu, raw_update->messages); + return raw_update; + +DECODE_ERROR: + LOG(ERROR, "Failed to decode LDP RAW update file %s\n", file); +ERROR: + if(raw_update) { + if(raw_update->buf) { + free(raw_update->buf); + } + free(raw_update); + } + return NULL; +} + +/** + * ldp_raw_update_load + * + * @param file update file + * @param decode_file decode/parse file content if true + * @return LDP RAW update structure + */ +ldp_raw_update_s * +ldp_raw_update_load(const char *file, bool decode_file) +{ + ldp_raw_update_s *raw_update = g_ctx->ldp_raw_updates; + + /* Check if file is already loaded */ + while(raw_update){ + if(strcmp(file, raw_update->file) == 0) { + return raw_update; + } + raw_update = raw_update->next; + } + raw_update = ldp_raw_update_load_file(file, decode_file); + if(raw_update) { + raw_update->next = g_ctx->ldp_raw_updates; + g_ctx->ldp_raw_updates = raw_update; + return raw_update; + } else { + return NULL; + } +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_raw_update.h b/code/bngblaster/src/ldp/ldp_raw_update.h new file mode 100644 index 00000000..91883951 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_raw_update.h @@ -0,0 +1,15 @@ +/* + * BNG Blaster (BBL) - LDP RAW Update Functions + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_RAW_UPDATE_H__ +#define __BBL_LDP_RAW_UPDATE_H__ + +ldp_raw_update_s * +ldp_raw_update_load(const char *file, bool decode_file); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index cde3ded2..8b96ba10 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -2,7 +2,7 @@ /* * BNG Blaster (BBL) - LDP Receive Functions * - * Christian Giese, March 2022 + * Christian Giese, November 2022 * * Copyright (C) 2020-2022, RtBrick, Inc. * SPDX-License-Identifier: BSD-3-Clause diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index 221b6d3f..5bc430c8 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -241,7 +241,8 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) ldp_push_init_message(session, true); if(ldp_session_send(session)) { session->stats.pdu_tx++; - session->stats.message_tx++; + session->stats.message_tx += 2; + session->stats.keepalive_tx++; ldp_session_state_change(session, LDP_OPENREC); } } else if(session->state == LDP_OPENSENT) { @@ -250,6 +251,7 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) if(ldp_session_send(session)) { session->stats.pdu_tx++; session->stats.message_tx++; + session->stats.keepalive_tx++; ldp_session_state_change(session, LDP_OPENREC); } } else { @@ -449,13 +451,14 @@ ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, if(!session) { session = calloc(1, sizeof(ldp_session_s)); - session->next = instance->sessions; - instance->sessions = session; + session->instance = instance; session->local.ipv4_address = config->ipv4_transport_address; session->local.lsr_id = config->lsr_id; session->local.label_space_id = 0; - session->local.keepalive_time = config->keepalive_interval; + session->local.keepalive_time = config->keepalive_time; session->local.max_pdu_len = LDP_MAX_PDU_LEN_INIT; + session->next = instance->sessions; + instance->sessions = session; } session->interface = adjacency->interface; session->max_pdu_len = session->local.max_pdu_len; diff --git a/code/bngblaster/src/ldp/ldp_session.h b/code/bngblaster/src/ldp/ldp_session.h index c920f702..e97232bf 100644 --- a/code/bngblaster/src/ldp/ldp_session.h +++ b/code/bngblaster/src/ldp/ldp_session.h @@ -9,6 +9,12 @@ #ifndef __BBL_LDP_SESSION_H__ #define __BBL_LDP_SESSION_H__ +const char * +ldp_session_state_string(ldp_state_t state); + +void +ldp_session_update_job(timer_s *timer); + void ldp_session_restart_keepalive_timeout(ldp_session_s *session); From 4dfcc8d4b64f05860f1de61166a1814cdb37c217 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Mon, 12 Dec 2022 22:01:39 +0000 Subject: [PATCH 08/27] LDP docu --- docsrc/sources/api/index.rst | 4 ++ docsrc/sources/api/ldp.rst | 27 +++++++++++++ docsrc/sources/conf.py | 2 +- docsrc/sources/configuration/index.rst | 6 ++- docsrc/sources/configuration/ldp.rst | 21 +++++----- docsrc/sources/routing/bgp.rst | 4 +- docsrc/sources/routing/index.rst | 2 +- docsrc/sources/routing/ldp.rst | 53 +++++++++++++++++++------- 8 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 docsrc/sources/api/ldp.rst diff --git a/docsrc/sources/api/index.rst b/docsrc/sources/api/index.rst index 66798ba5..cc0bbb7a 100644 --- a/docsrc/sources/api/index.rst +++ b/docsrc/sources/api/index.rst @@ -189,6 +189,10 @@ BGP --- .. include:: bgp.rst +LDP +--- +.. include:: ldp.rst + CFM --- .. include:: cfm.rst diff --git a/docsrc/sources/api/ldp.rst b/docsrc/sources/api/ldp.rst new file mode 100644 index 00000000..c3e5236d --- /dev/null +++ b/docsrc/sources/api/ldp.rst @@ -0,0 +1,27 @@ +.. list-table:: + :header-rows: 1 + + * - Attribute + - Description + - Mandatory Arguments + - Optional Arguments + * - `ldp-sessions` + - Display all matching LDP sessions + - + - `ldp-instance-id`, `local-ipv4-address`, `peer-ipv4-address` + * - `ldp-disconnect` + - Disconnect all matching LDP sessions + - + - `ldp-instance-id`, `local-ipv4-address`, `peer-ipv4-address` + * - `ldp-teardown` + - Teardown LDP + - + - + * - `ldp-raw-update-list` + - List all loaded LDP RAW update files + - + - + * - `ldp-raw-update` + - Update all matching LDP session + - `file` + - `ldp-instance-id`, `local-ipv4-address`, `peer-ipv4-address` diff --git a/docsrc/sources/conf.py b/docsrc/sources/conf.py index a5e88739..33d74a20 100644 --- a/docsrc/sources/conf.py +++ b/docsrc/sources/conf.py @@ -6,7 +6,7 @@ project = 'BNG Blaster' copyright = '2020-2022, RtBrick, Inc.' author = 'Christian Giese' release = '0.8' -version = '0.8.1' +version = '0.8.X' # -- General configuration diff --git a/docsrc/sources/configuration/index.rst b/docsrc/sources/configuration/index.rst index ec6412a5..a691ae9d 100644 --- a/docsrc/sources/configuration/index.rst +++ b/docsrc/sources/configuration/index.rst @@ -114,4 +114,8 @@ ISIS External Connections BGP --- -.. include:: bgp.rst \ No newline at end of file +.. include:: bgp.rst + +LDP +--- +.. include:: ldp.rst \ No newline at end of file diff --git a/docsrc/sources/configuration/ldp.rst b/docsrc/sources/configuration/ldp.rst index 83e69a37..ed1ec783 100644 --- a/docsrc/sources/configuration/ldp.rst +++ b/docsrc/sources/configuration/ldp.rst @@ -13,21 +13,24 @@ * - `instance-id` - LDP instance identifier - - * - `overload` - - LDP overload - - false - * - `hello-interval` - - LDP hello interval in seconds - - 10 + * - `keepalive-time` + - LDP keepalive time in seconds + - 15 * - `hold-time` - LDP hold time in seconds - 30 * - `hostname` - LDP hostname - bngblaster - * - `router-id` - - LDP router identifier + * - `lsr-id` + - LDP LSR identifier - 10.10.10.10 * - `teardown-time` - LDP teardown time in seconds - - 5 \ No newline at end of file + - 5 + * - `ipv4-transport-address` + - LDP transport address + - `lsr-id` + * - `raw-update-file` + - LDP RAW update file + - \ No newline at end of file diff --git a/docsrc/sources/routing/bgp.rst b/docsrc/sources/routing/bgp.rst index 513c5ac0..34ef4245 100644 --- a/docsrc/sources/routing/bgp.rst +++ b/docsrc/sources/routing/bgp.rst @@ -67,8 +67,8 @@ but not limited to update messages. .. code-block:: none - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + diff --git a/docsrc/sources/routing/index.rst b/docsrc/sources/routing/index.rst index 79827a8f..6583eed0 100644 --- a/docsrc/sources/routing/index.rst +++ b/docsrc/sources/routing/index.rst @@ -9,6 +9,6 @@ router testing. :maxdepth: 1 isis.rst - ldp.rst mpls.rst bgp.rst + ldp.rst diff --git a/docsrc/sources/routing/ldp.rst b/docsrc/sources/routing/ldp.rst index 3e3ef8ed..7867180c 100644 --- a/docsrc/sources/routing/ldp.rst +++ b/docsrc/sources/routing/ldp.rst @@ -31,32 +31,59 @@ attached to two network interfaces. "gateway": "10.0.2.1", "address-ipv6": "fc66:1337:7331:2::2/64", "gateway-ipv6": "fc66:1337:7331:2::1", - "ldp-instance-id": 1 + "ldp-instance-id": 2 } ] }, "ldp": [ { "instance-id": 1, - "lsr-id": "10.10.10.10", + "lsr-id": "10.10.10.11", "hostname": "R1", + }, + { + "instance-id": 1, + "lsr-id": "10.10.10.12", + "hostname": "R2", } ] } .. include:: ../configuration/ldp.rst -The support for multiple instances allows different use cases. One example might -be to create two instances connected to the device or network under test. Now -inject an LSP on one instance and check if learned over the tested network on -the other instance. - -Peers -~~~~~ - -Database -~~~~~~~~ - Limitations ~~~~~~~~~~~ +LDP authentication is currently not supported but already +planned as an enhancement in one of the next releases. + +RAW Update Files +~~~~~~~~~~~~~~~~ + +The BNG Blaster can inject LDP PDU from a pre-compiled +RAW update file into the defined sessions. A RAW update file is not +more than a pre-compiled binary stream of LDP PDU. + +.. code-block:: none + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Version | PDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LDP Identifier | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . LDP Messages + . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Version | PDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | LDP Identifier | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . LDP Messages + . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ From 99a41745e1f71020a899457aa3339e6fce61b6ee Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Mon, 12 Dec 2022 23:05:23 +0000 Subject: [PATCH 09/27] LDP raw update fix --- code/bngblaster/src/ldp/ldp_session.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index 5bc430c8..743d2023 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -457,6 +457,9 @@ ldp_session_init(ldp_session_s *session, ldp_adjacency_s *adjacency, session->local.label_space_id = 0; session->local.keepalive_time = config->keepalive_time; session->local.max_pdu_len = LDP_MAX_PDU_LEN_INIT; + if(config->raw_update_file) { + session->raw_update_start = ldp_raw_update_load(config->raw_update_file, true); + } session->next = instance->sessions; instance->sessions = session; } From 05ce7c7284642fc9530d3c39935403b8ca38676d Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Tue, 13 Dec 2022 10:14:53 +0000 Subject: [PATCH 10/27] LDP self update --- code/bngblaster/src/ldp/ldp_def.h | 1 - code/bngblaster/src/ldp/ldp_message.c | 93 ++++++++++++++++++++++----- code/bngblaster/src/ldp/ldp_message.h | 14 +++- code/bngblaster/src/ldp/ldp_session.c | 57 ++++++++-------- 4 files changed, 119 insertions(+), 46 deletions(-) diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index 58162c2b..e1406109 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -227,7 +227,6 @@ typedef struct ldp_adjacency_ { typedef struct ldp_instance_ { ldp_config_s *config; - bool overload; bool teardown; struct timer_ *teardown_timer; diff --git a/code/bngblaster/src/ldp/ldp_message.c b/code/bngblaster/src/ldp/ldp_message.c index 40c1cbd4..4fcf4d61 100644 --- a/code/bngblaster/src/ldp/ldp_message.c +++ b/code/bngblaster/src/ldp/ldp_message.c @@ -8,7 +8,7 @@ */ #include "ldp.h" -static void +void ldp_pdu_close(ldp_session_s *session) { io_buffer_t *buffer = &session->write_buf; @@ -20,9 +20,10 @@ ldp_pdu_close(ldp_session_s *session) write_be_uint(buffer->data+session->pdu_start_idx-2, 2, len); session->pdu_start_idx = 0; } + session->stats.pdu_tx++; } -static bool +bool ldp_pdu_init(ldp_session_s *session) { io_buffer_t *buffer = &session->write_buf; @@ -55,6 +56,7 @@ ldp_msg_close(ldp_session_s *session) write_be_uint(buffer->data+session->msg_start_idx-2, 2, len); session->msg_start_idx = 0; } + session->stats.message_tx++; } static bool @@ -111,11 +113,9 @@ ldp_tlv_init(ldp_session_s *session, uint16_t type) } void -ldp_push_init_message(ldp_session_s *session, bool keepalive) +ldp_push_init_message(ldp_session_s *session) { io_buffer_t *buffer = &session->write_buf; - - ldp_pdu_init(session); ldp_msg_init(session, LDP_MESSAGE_TYPE_INITIALIZATION); ldp_tlv_init(session, LDP_TLV_TYPE_COMMON_SESSION_PARAMETERS); push_be_uint(buffer, 2, 1); @@ -126,28 +126,20 @@ ldp_push_init_message(ldp_session_s *session, bool keepalive) push_be_uint(buffer, 2, session->peer.label_space_id); ldp_tlv_close(session); ldp_msg_close(session); - if(keepalive) { - ldp_msg_init(session, LDP_MESSAGE_TYPE_KEEPALIVE); - ldp_msg_close(session); - } - ldp_pdu_close(session); } void ldp_push_keepalive_message(ldp_session_s *session) { - ldp_pdu_init(session); ldp_msg_init(session, LDP_MESSAGE_TYPE_KEEPALIVE); ldp_msg_close(session); - ldp_pdu_close(session); + session->stats.keepalive_tx++; } void ldp_push_notification_message(ldp_session_s *session) { io_buffer_t *buffer = &session->write_buf; - - ldp_pdu_init(session); ldp_msg_init(session, LDP_MESSAGE_TYPE_NOTIFICATION); ldp_tlv_init(session, LDP_TLV_TYPE_STATUS); push_be_uint(buffer, 4, session->error_code); @@ -155,5 +147,76 @@ ldp_push_notification_message(ldp_session_s *session) push_be_uint(buffer, 2, 0); ldp_tlv_close(session); ldp_msg_close(session); - ldp_pdu_close(session); +} + +void +ldp_push_label_mapping_message(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label) +{ + io_buffer_t *buffer = &session->write_buf; + uint8_t prefix_bytes = BITS_TO_BYTES(prefix->len); + + ldp_msg_init(session, LDP_MESSAGE_TYPE_LABEL_MAPPING); + ldp_tlv_init(session, LDP_TLV_TYPE_FEC); + push_be_uint(buffer, 1, 2); /* Prefix FEC */ + push_be_uint(buffer, 2, 1); /* IPv4 */ + push_be_uint(buffer, 1, prefix->len); /* IPv4 */ + push_data(buffer, (uint8_t*)&prefix->address, prefix_bytes); + ldp_tlv_close(session); + ldp_tlv_init(session, LDP_TLV_TYPE_GENERIC_LABEL); + push_be_uint(buffer, 4, label); + ldp_tlv_close(session); + ldp_msg_close(session); +} + +void +ldp_push_self_message(ldp_session_s *session) +{ + io_buffer_t *buffer = &session->write_buf; + ldp_adjacency_s *adjacency = session->instance->adjacencies; + uint32_t lsr_id = session->instance->config->lsr_id; + uint32_t local_ipv4 = session->local.ipv4_address; + uint32_t ipv4; + + uint8_t prefix_len; + uint8_t prefix_bytes; + + ldp_msg_init(session, LDP_MESSAGE_TYPE_ADDRESS); + ldp_tlv_init(session, LDP_TLV_TYPE_ADDRESS_LIST); + push_be_uint(buffer, 2, 1); /* IPv4 */ + push_data(buffer, (uint8_t*)&lsr_id, 4); + if(lsr_id != local_ipv4) { + push_data(buffer, (uint8_t*)&local_ipv4, 4); + } + while(adjacency) { + ipv4 = adjacency->interface->ip.address; + if(ipv4 && ipv4 != lsr_id && ipv4 != local_ipv4) { + push_data(buffer, (uint8_t*)&adjacency->interface->ip.address, 4); + } + adjacency = adjacency->next; + } + ldp_tlv_close(session); + ldp_msg_close(session); + + ldp_msg_init(session, LDP_MESSAGE_TYPE_LABEL_MAPPING); + ldp_tlv_init(session, LDP_TLV_TYPE_FEC); + push_be_uint(buffer, 1, 2); /* Prefix FEC */ + push_be_uint(buffer, 2, 1); /* IPv4 */ + push_be_uint(buffer, 1, 32); + push_data(buffer, (uint8_t*)&lsr_id, 4); + adjacency = session->instance->adjacencies; + while(adjacency) { + ipv4 = adjacency->interface->ip.address; + prefix_len = adjacency->interface->ip.len; + prefix_bytes = BITS_TO_BYTES(prefix_len); + push_be_uint(buffer, 1, 2); /* Prefix FEC */ + push_be_uint(buffer, 2, 1); /* IPv4 */ + push_be_uint(buffer, 1, prefix_len); + push_data(buffer, (uint8_t*)&adjacency->interface->ip.address, prefix_bytes); + adjacency = adjacency->next; + } + ldp_tlv_close(session); + ldp_tlv_init(session, LDP_TLV_TYPE_GENERIC_LABEL); + push_be_uint(buffer, 4, 3); /* Implicit NULL Label */ + ldp_tlv_close(session); + ldp_msg_close(session); } \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_message.h b/code/bngblaster/src/ldp/ldp_message.h index 825f08c7..d5b3424f 100644 --- a/code/bngblaster/src/ldp/ldp_message.h +++ b/code/bngblaster/src/ldp/ldp_message.h @@ -10,7 +10,13 @@ #define __BBL_LDP_MESSAGE_H__ void -ldp_push_init_message(ldp_session_s *session, bool keepalive); +ldp_pdu_close(ldp_session_s *session); + +bool +ldp_pdu_init(ldp_session_s *session); + +void +ldp_push_init_message(ldp_session_s *session); void ldp_push_keepalive_message(ldp_session_s *session); @@ -18,4 +24,10 @@ ldp_push_keepalive_message(ldp_session_s *session); void ldp_push_notification_message(ldp_session_s *session); +void +ldp_push_label_mapping_message(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label); + +void +ldp_push_self_message(ldp_session_s *session); + #endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index 743d2023..932e700e 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -149,12 +149,10 @@ ldp_session_keepalive_job(timer_s *timer) if(session->state == LDP_OPERATIONAL) { if(session->tcpc && session->tcpc->state == BBL_TCP_STATE_IDLE) { ldp_session_reset_write_buffer(session); + ldp_pdu_init(session); ldp_push_keepalive_message(session); - if(ldp_session_send(session)) { - session->stats.pdu_tx++; - session->stats.message_tx++; - session->stats.keepalive_tx++; - } + ldp_pdu_close(session); + ldp_session_send(session); } } } @@ -197,7 +195,7 @@ ldp_session_operational(ldp_session_s *session) session->max_pdu_len = session->local.max_pdu_len; } - /* Start LDP keepalive */ + /* Start LDP keepalive. */ if(session->peer.keepalive_time > 0 && session->peer.keepalive_time < session->local.keepalive_time) { session->keepalive_time = session->peer.keepalive_time; @@ -213,7 +211,7 @@ ldp_session_operational(ldp_session_s *session) "LDP KEEPALIVE", keepalive_interval, 0, session, &ldp_session_keepalive_job); - /* Start LDP updates */ + /* Start LDP updates. */ timer_add(&g_ctx->timer_root, &session->update_timer, "LDP UPDATE", 0, 0, session, &ldp_session_update_job); @@ -227,33 +225,29 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) ldp_session_state_change(session, LDP_INITIALIZED); if(session->active) { ldp_session_reset_write_buffer(session); - ldp_push_init_message(session, false); - if(ldp_session_send(session)) { - session->stats.pdu_tx++; - session->stats.message_tx++; - ldp_session_state_change(session, LDP_OPENSENT); - } + ldp_pdu_init(session); + ldp_push_init_message(session); + ldp_pdu_close(session); + ldp_session_send(session); + ldp_session_state_change(session, LDP_OPENSENT); } break; case LDP_EVENT_RX_INITIALIZED: if(session->state == LDP_INITIALIZED) { ldp_session_reset_write_buffer(session); - ldp_push_init_message(session, true); - if(ldp_session_send(session)) { - session->stats.pdu_tx++; - session->stats.message_tx += 2; - session->stats.keepalive_tx++; - ldp_session_state_change(session, LDP_OPENREC); - } + ldp_pdu_init(session); + ldp_push_init_message(session); + ldp_push_keepalive_message(session); + ldp_pdu_close(session); + ldp_session_send(session); + ldp_session_state_change(session, LDP_OPENREC); } else if(session->state == LDP_OPENSENT) { ldp_session_reset_write_buffer(session); + ldp_pdu_init(session); ldp_push_keepalive_message(session); - if(ldp_session_send(session)) { - session->stats.pdu_tx++; - session->stats.message_tx++; - session->stats.keepalive_tx++; - ldp_session_state_change(session, LDP_OPENREC); - } + ldp_pdu_close(session); + ldp_session_send(session); + ldp_session_state_change(session, LDP_OPENREC); } else { if(!session->error_code) { session->error_code = LDP_STATUS_INTERNAL_ERROR; @@ -264,6 +258,11 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) case LDP_EVENT_RX_KEEPALIVE: if(session->state == LDP_OPENREC) { ldp_session_operational(session); + ldp_session_reset_write_buffer(session); + ldp_pdu_init(session); + ldp_push_self_message(session); + ldp_pdu_close(session); + ldp_session_send(session); } break; default: @@ -543,7 +542,9 @@ ldp_session_close(ldp_session_s *session) format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); ldp_session_reset_write_buffer(session); + ldp_pdu_init(session); ldp_push_notification_message(session); + ldp_pdu_close(session); ldp_session_send(session); session->stats.pdu_tx++; session->stats.message_tx++; @@ -554,6 +555,4 @@ ldp_session_close(ldp_session_s *session) timer_add(&g_ctx->timer_root, &session->close_timer, "LDP CLOSE", delay, 0, session, &ldp_session_close_job); -} - - +} \ No newline at end of file From 1957704b6df8fd7d2faed02577b1b00304457711 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Tue, 13 Dec 2022 12:18:03 +0000 Subject: [PATCH 11/27] LDP fix hello PDU --- code/bngblaster/src/ldp/ldp_hello.c | 1 - 1 file changed, 1 deletion(-) diff --git a/code/bngblaster/src/ldp/ldp_hello.c b/code/bngblaster/src/ldp/ldp_hello.c index 38ac2bc5..ead76564 100644 --- a/code/bngblaster/src/ldp/ldp_hello.c +++ b/code/bngblaster/src/ldp/ldp_hello.c @@ -40,7 +40,6 @@ ldp_hello_encode(bbl_network_interface_s *interface, ipv4.src = interface->ip.address; ipv4.ttl = 1; ipv4.protocol = PROTOCOL_IPV4_UDP; - ipv4.router_alert_option = true; ipv4.next = &udp; udp.src = LDP_PORT; udp.dst = LDP_PORT; From e0ecf1c8ed43013d90009ac4fa20a36f26e80ed2 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 14 Dec 2022 15:16:38 +0000 Subject: [PATCH 12/27] LDP database --- code/bngblaster/src/bbl_ctrl.c | 1 + code/bngblaster/src/bbl_def.h | 7 +- code/bngblaster/src/ldp/ldp.c | 27 ++++++- code/bngblaster/src/ldp/ldp.h | 4 + code/bngblaster/src/ldp/ldp_ctrl.c | 109 ++++++++++++++++++++++++-- code/bngblaster/src/ldp/ldp_ctrl.h | 3 + code/bngblaster/src/ldp/ldp_db.c | 66 ++++++++++++++++ code/bngblaster/src/ldp/ldp_db.h | 18 +++++ code/bngblaster/src/ldp/ldp_def.h | 23 +++++- code/bngblaster/src/ldp/ldp_message.c | 8 +- code/bngblaster/src/ldp/ldp_receive.c | 105 +++++++++++++++++++++---- code/bngblaster/src/ldp/ldp_session.c | 60 +++++++------- 12 files changed, 374 insertions(+), 57 deletions(-) create mode 100644 code/bngblaster/src/ldp/ldp_db.c create mode 100644 code/bngblaster/src/ldp/ldp_db.h diff --git a/code/bngblaster/src/bbl_ctrl.c b/code/bngblaster/src/bbl_ctrl.c index 17ae1b4a..52f71115 100644 --- a/code/bngblaster/src/bbl_ctrl.c +++ b/code/bngblaster/src/bbl_ctrl.c @@ -158,6 +158,7 @@ struct action actions[] = { {"bgp-raw-update", bgp_ctrl_raw_update, false}, {"ldp-adjacencies", ldp_ctrl_adjacencies, true}, {"ldp-sessions", ldp_ctrl_sessions, true}, + {"ldp-database", ldb_ctrl_database, true}, {"ldp-disconnect", ldp_ctrl_disconnect, false}, {"ldp-teardown", ldp_ctrl_teardown, true}, {"ldp-raw-update-list", ldp_ctrl_raw_update_list, true}, diff --git a/code/bngblaster/src/bbl_def.h b/code/bngblaster/src/bbl_def.h index 0a4aa792..efef9abf 100644 --- a/code/bngblaster/src/bbl_def.h +++ b/code/bngblaster/src/bbl_def.h @@ -107,6 +107,12 @@ #define ACTIVATE_ENDPOINT(_endpoint) \ if(_endpoint != ENDPOINT_DISABLED) _endpoint = ENDPOINT_ACTIVE +typedef enum { + IANA_AFI_RESERVED = 0, + IANA_AFI_IPV4 = 1, + IANA_AFI_IPV6 = 2, +} __attribute__ ((__packed__)) iana_afi_t; + typedef enum { ACCESS_TYPE_PPPOE = 0, ACCESS_TYPE_IPOE @@ -130,7 +136,6 @@ typedef enum { LAG_MEMBER_INTERFACE, } __attribute__ ((__packed__)) interface_type_t; - typedef enum { IGMP_GROUP_IDLE = 0, IGMP_GROUP_LEAVING, diff --git a/code/bngblaster/src/ldp/ldp.c b/code/bngblaster/src/ldp/ldp.c index a40365cb..56c642ba 100644 --- a/code/bngblaster/src/ldp/ldp.c +++ b/code/bngblaster/src/ldp/ldp.c @@ -8,6 +8,31 @@ */ #include "ldp.h" + +/** + * ldp_id_to_str + * + * @param lsr_id LDP LSR ID + * @param label_space_id LDP label space + + * @return LDP identifier string + */ +char * +ldp_id_to_str(uint32_t lsr_id, uint16_t label_space_id) +{ + static char buffer[4][LDP_IDENTIFIER_STR_LEN]; + static int idx = 0; + char *ret; + ret = buffer[idx]; + idx = (idx+1) & 3; + + snprintf(ret, LDP_IDENTIFIER_STR_LEN, "%s:%u", + format_ipv4_address(&lsr_id), + label_space_id); + + return ret; +} + /** * ldp_init * @@ -29,7 +54,7 @@ ldp_init() g_ctx->ldp_instances = instance; } instance->config = config; - + ldb_db_init(instance); config = config->next; } return true; diff --git a/code/bngblaster/src/ldp/ldp.h b/code/bngblaster/src/ldp/ldp.h index 38dafc7f..d52e390f 100644 --- a/code/bngblaster/src/ldp/ldp.h +++ b/code/bngblaster/src/ldp/ldp.h @@ -15,10 +15,14 @@ #include "ldp_interface.h" #include "ldp_session.h" #include "ldp_message.h" +#include "ldp_db.h" #include "ldp_receive.h" #include "ldp_raw_update.h" #include "ldp_ctrl.h" +char * +ldp_id_to_str(uint32_t lsr_id, uint16_t label_space_id); + bool ldp_init(); diff --git a/code/bngblaster/src/ldp/ldp_ctrl.c b/code/bngblaster/src/ldp/ldp_ctrl.c index ce2ee2c8..5cd21d73 100644 --- a/code/bngblaster/src/ldp/ldp_ctrl.c +++ b/code/bngblaster/src/ldp/ldp_ctrl.c @@ -103,20 +103,17 @@ ldp_ctrl_session_json(ldp_session_s *session) return NULL; } - root = json_pack("{si ss ss ss si ss ss si ss ss* ss* so*}", + root = json_pack("{si ss ss ss ss ss ss ss* ss* so*}", "ldp-instance-id", session->instance->config->id, "interface", session->interface->name, "local-address", format_ipv4_address(&session->local.ipv4_address), - "local-lsr-id", format_ipv4_address(&session->local.lsr_id), - "local-label-space-id", session->local.label_space_id, + "local-identifier", ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), "peer-address", format_ipv4_address(&session->peer.ipv4_address), - "peer-lsr-id", format_ipv4_address(&session->peer.lsr_id), - "peer-label-space-id", session->peer.label_space_id, + "peer-identifier", ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), "state", ldp_session_state_string(session->state), "raw-update-state", raw_update_state(session), "raw-update-file", raw_update_file, "stats", stats); - if(!root) { if(stats) json_decref(stats); } @@ -404,4 +401,104 @@ ldp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t result = bbl_ctrl_status(fd, "error", 500, "internal error"); } return result; +} + +static json_t * +ldb_ctrl_database_entries(ldp_instance_s *instance) +{ + json_t *json_database, *json_entry; + ldp_db_entry_s *entry; + + hb_tree *db; + hb_itor *itor; + bool next; + + json_database = json_array(); + + /* Add IPv4 prefixes. */ + db = instance->db.ipv4; + itor = hb_itor_new(db); + next = hb_itor_first(itor); + while(next) { + entry = *hb_itor_datum(itor); + json_entry = json_pack("{ss ss* si ss*}", + "direction", "ipv4", + "prefix", format_ipv4_prefix(&entry->prefix.ipv4), + "label", entry->label, + "source-identifier", ldp_id_to_str(entry->source->peer.lsr_id, entry->source->peer.label_space_id)); + + if(json_entry) { + json_array_append(json_database, json_entry); + } + next = hb_itor_next(itor); + } + hb_itor_free(itor); + + /* Add IPv6 prefixes. */ + db = instance->db.ipv6; + itor = hb_itor_new(db); + next = hb_itor_first(itor); + while(next) { + entry = *hb_itor_datum(itor); + json_entry = json_pack("{ss ss* si ss*}", + "direction", "ipv6", + "prefix", format_ipv6_prefix(&entry->prefix.ipv6), + "label", entry->label, + "source-identifier", ldp_id_to_str(entry->source->peer.lsr_id, entry->source->peer.label_space_id)); + + if(json_entry) { + json_array_append(json_database, json_entry); + } + next = hb_itor_next(itor); + } + hb_itor_free(itor); + + return json_database; +} + +int +ldb_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments) +{ + int result = 0; + json_t *root = NULL; + json_t *database = NULL; + ldp_instance_s *instance = NULL; + + int instance_id = 0; + + /* Unpack further arguments */ + if(json_unpack(arguments, "{s:i}", "instance", &instance_id) != 0) { + return bbl_ctrl_status(fd, "error", 400, "LDP instance missing"); + } + + /* Search for matching instance */ + instance = g_ctx->ldp_instances; + while(instance) { + if(instance->config->id == instance_id) { + break; + } + instance = instance->next; + } + + if(!instance) { + return bbl_ctrl_status(fd, "error", 400, "LDP instance not found"); + } + + database = ldb_ctrl_database_entries(instance); + if(database) { + root = json_pack("{ss si so}", + "status", "ok", + "code", 200, + "ldp-database", database); + if(root) { + result = json_dumpfd(root, fd, 0); + json_decref(root); + } else { + result = bbl_ctrl_status(fd, "error", 500, "internal error"); + json_decref(database); + } + return result; + } else { + return bbl_ctrl_status(fd, "error", 500, "internal error"); + } } \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_ctrl.h b/code/bngblaster/src/ldp/ldp_ctrl.h index 96e0a43a..6bf0bc04 100644 --- a/code/bngblaster/src/ldp/ldp_ctrl.h +++ b/code/bngblaster/src/ldp/ldp_ctrl.h @@ -27,4 +27,7 @@ ldp_ctrl_raw_update_list(int fd, uint32_t session_id __attribute__((unused)), js int ldp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); +int +ldb_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *arguments); + #endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_db.c b/code/bngblaster/src/ldp/ldp_db.c new file mode 100644 index 00000000..fa5ff4fc --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_db.c @@ -0,0 +1,66 @@ +/* + * BNG Blaster (BBL) - LDP Database + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "ldp.h" + +int +ldb_db_ipv4_compare(void *id1, void *id2) +{ + const uint32_t a = *(const uint32_t*)id1; + const uint32_t b = *(const uint32_t*)id2; + return (a > b) - (a < b); +} + +int +ldb_db_ipv6_compare(void *id1, void *id2) +{ + const uint64_t a = *(const uint64_t*)id1; + const uint64_t b = *(const uint64_t*)id2; + return (a > b) - (a < b); +} + +bool +ldb_db_init(ldp_instance_s *instance) +{ + instance->db.ipv4 = hb_tree_new((dict_compare_func)ldb_db_ipv4_compare); + instance->db.ipv6 = hb_tree_new((dict_compare_func)ldb_db_ipv6_compare); + return true; +} + +bool +ldb_db_add_ipv4(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label) +{ + void **search = NULL; + ldp_instance_s *instance = session->instance; + ldp_db_entry_s *entry; + dict_insert_result result; + + search = hb_tree_search(instance->db.ipv4, &prefix->address); + if(search) { + entry = *search; + entry->version++; + } else { + entry = calloc(1, sizeof(ldp_db_entry_s)); + entry->afi = IANA_AFI_IPV4; + entry->prefix.ipv4.address = prefix->address; + result = hb_tree_insert(instance->db.ipv4, &entry->prefix.ipv4.address); + if(result.inserted) { + *result.datum_ptr = entry; + } else { + LOG(ERROR, "LDP (%s - %s) failed to add IPv4 entry to database\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); + return false; + } + } + entry->active = true; + entry->prefix.ipv4.len = prefix->len; + entry->label = label; + entry->source = session; + return true; +} \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_db.h b/code/bngblaster/src/ldp/ldp_db.h new file mode 100644 index 00000000..7574a7f8 --- /dev/null +++ b/code/bngblaster/src/ldp/ldp_db.h @@ -0,0 +1,18 @@ +/* + * BNG Blaster (BBL) - LDP Database + * + * Christian Giese, November 2022 + * + * Copyright (C) 2020-2022, RtBrick, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __BBL_LDP_DB_H__ +#define __BBL_LDP_DB_H__ + +bool +ldb_db_init(ldp_instance_s *instance); + +bool +ldb_db_add_ipv4(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label); + +#endif \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index e1406109..154b9e34 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -13,6 +13,7 @@ #define LDP_PORT 646 #define LDP_IDENTIFIER_LEN 6U +#define LDP_IDENTIFIER_STR_LEN sizeof("255.255.255.255:6500") #define LDP_MAX_PDU_LEN_INIT 4096U #define LDP_MIN_PDU_LEN 10 #define LDP_MIN_MSG_LEN 8 @@ -49,6 +50,8 @@ #define LDP_TLV_TYPE_LABEL_REQUEST_ID 0x0600 #define LDP_TLV_LEN_MIN 4 +#define LDP_FEC_LEN_MIN 4 +#define LDP_FEC_ELEMENT_TYPE_PREFIX 2 #define LDP_STATUS_SUCCESS 0x00000000 #define LDP_STATUS_BAD_IDENTIFIER 0x00000001 @@ -94,6 +97,21 @@ typedef struct ldp_instance_ ldp_instance_s; typedef struct ldp_session_ ldp_session_s; typedef struct ldp_adjacency_ ldp_adjacency_s; +/* + * LDP database entry + */ +typedef struct ldp_db_entry_ { + iana_afi_t afi; + bool active; + union { + ipv4_prefix ipv4; + ipv6_prefix ipv6; + } prefix; + uint32_t label; + uint32_t version; + ldp_session_s *source; +} ldp_db_entry_s; + /* * LDP RAW Update File */ @@ -234,7 +252,10 @@ typedef struct ldp_instance_ { ldp_adjacency_s *adjacencies; ldp_session_s *sessions; - hb_tree *ldb; /* Label database. */ + struct { + hb_tree *ipv4; + hb_tree *ipv6; + } db; /* Label database. */ /* Pointer to next instance. */ struct ldp_instance_ *next; diff --git a/code/bngblaster/src/ldp/ldp_message.c b/code/bngblaster/src/ldp/ldp_message.c index 4fcf4d61..5b3bcf10 100644 --- a/code/bngblaster/src/ldp/ldp_message.c +++ b/code/bngblaster/src/ldp/ldp_message.c @@ -199,8 +199,8 @@ ldp_push_self_message(ldp_session_s *session) ldp_msg_init(session, LDP_MESSAGE_TYPE_LABEL_MAPPING); ldp_tlv_init(session, LDP_TLV_TYPE_FEC); - push_be_uint(buffer, 1, 2); /* Prefix FEC */ - push_be_uint(buffer, 2, 1); /* IPv4 */ + push_be_uint(buffer, 1, LDP_FEC_ELEMENT_TYPE_PREFIX); + push_be_uint(buffer, 2, IANA_AFI_IPV4); push_be_uint(buffer, 1, 32); push_data(buffer, (uint8_t*)&lsr_id, 4); adjacency = session->instance->adjacencies; @@ -208,8 +208,8 @@ ldp_push_self_message(ldp_session_s *session) ipv4 = adjacency->interface->ip.address; prefix_len = adjacency->interface->ip.len; prefix_bytes = BITS_TO_BYTES(prefix_len); - push_be_uint(buffer, 1, 2); /* Prefix FEC */ - push_be_uint(buffer, 2, 1); /* IPv4 */ + push_be_uint(buffer, 1, LDP_FEC_ELEMENT_TYPE_PREFIX); + push_be_uint(buffer, 2, IANA_AFI_IPV4); push_be_uint(buffer, 1, prefix_len); push_data(buffer, (uint8_t*)&adjacency->interface->ip.address, prefix_bytes); adjacency = adjacency->next; diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index 8b96ba10..11162d3d 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -27,9 +27,9 @@ struct keyval_ ldp_msg_names[] = { static void ldp_decode_error(ldp_session_s *session) { - LOG(LDP, "LDP (%s:%u - %s:%u) invalid PDU received\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) invalid PDU received\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); session->decode_error = true; if(!session->error_code) { @@ -47,6 +47,79 @@ ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) return true; } +static bool +ldp_label_mapping(ldp_session_s *session, uint8_t *start, uint16_t length) +{ + uint8_t *tlv_start = start; + uint16_t tlv_type; + uint16_t tlv_length; + + uint8_t prefix_length; + uint8_t prefix_bytes; + + uint8_t *fec_element; + uint16_t fec_length; + uint16_t fec_afi; + uint32_t label; + + ipv4_prefix ipv4prefix; + + /* Read all TLV's. */ + while(length >= LDP_TLV_LEN_MIN) { + tlv_type = read_be_uint(tlv_start, 2) & 0x3FFF; + tlv_length = read_be_uint(tlv_start+2, 2); + if(tlv_length+LDP_TLV_LEN_MIN > length) { + return false; + } + switch(tlv_type) { + case LDP_TLV_TYPE_FEC: + if(tlv_length < LDP_FEC_LEN_MIN) { + return false; + } + fec_element = tlv_start+LDP_TLV_LEN_MIN; + fec_length = tlv_length; + if(*fec_element != LDP_FEC_ELEMENT_TYPE_PREFIX) { + return false; + } + break; + case LDP_TLV_TYPE_GENERIC_LABEL: + if(tlv_length < sizeof(label)) { + return false; + } + label = read_be_uint(tlv_start+LDP_TLV_LEN_MIN, sizeof(label)); + break; + default: + break; + } + length -= (tlv_length+LDP_TLV_LEN_MIN); + tlv_start += (tlv_length+LDP_TLV_LEN_MIN); + } + + /* Read all FEC elements. */ + while(fec_length >= LDP_FEC_LEN_MIN) { + fec_afi = read_be_uint(fec_element+1, 2); + prefix_length = *(fec_element+3); + prefix_bytes = BITS_TO_BYTES(prefix_length); + if(prefix_bytes+LDP_FEC_LEN_MIN > fec_length) { + return false; + } + if(fec_afi == IANA_AFI_IPV4) { + ipv4prefix.len = prefix_length; + ipv4prefix.address = 0; + memcpy((uint8_t*)&ipv4prefix.address, fec_element+LDP_FEC_LEN_MIN, prefix_bytes); + LOG(DEBUG, "LDP (%s - %s) add %s via label %u\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), + format_ipv4_prefix(&ipv4prefix), label); + + ldb_db_add_ipv4(session, &ipv4prefix, label); + } + fec_length -= (prefix_bytes+LDP_FEC_LEN_MIN); + fec_element += (prefix_bytes+LDP_FEC_LEN_MIN); + } + return true; +} + static bool ldp_initialization(ldp_session_s *session, uint8_t *start, uint16_t length) { @@ -57,10 +130,9 @@ ldp_initialization(ldp_session_s *session, uint8_t *start, uint16_t length) while(length > LDP_TLV_LEN_MIN) { tlv_type = read_be_uint(tlv_start, 2) & 0x3FFF; tlv_length = read_be_uint(tlv_start+2, 2); - if(tlv_length+2 > length) { + if(tlv_length+LDP_TLV_LEN_MIN > length) { return false; } - switch(tlv_type) { case LDP_TLV_TYPE_COMMON_SESSION_PARAMETERS: if(tlv_length < 14) { @@ -72,8 +144,8 @@ ldp_initialization(ldp_session_s *session, uint8_t *start, uint16_t length) default: break; } - length -= (tlv_length+2); - tlv_start += (tlv_length+2); + length -= (tlv_length+LDP_TLV_LEN_MIN); + tlv_start += (tlv_length+LDP_TLV_LEN_MIN); } ldp_session_fsm(session, LDP_EVENT_RX_INITIALIZED); return true; @@ -172,9 +244,9 @@ ldp_read(ldp_session_s *session) return; } - LOG(DEBUG, "LDP (%s:%u - %s:%u) read %s message (%u)\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + LOG(DEBUG, "LDP (%s - %s) read %s message (%u)\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), keyval_get_key(ldp_msg_names, msg_type), msg_id); ldp_session_restart_keepalive_timeout(session); @@ -196,9 +268,14 @@ ldp_read(ldp_session_s *session) session->stats.keepalive_rx++; ldp_session_fsm(session, LDP_EVENT_RX_KEEPALIVE); break; + case LDP_MESSAGE_TYPE_LABEL_MAPPING: + if(!ldp_label_mapping(session, msg_start+8, msg_length-4)) { + ldp_decode_error(session); + return; + } + break; case LDP_MESSAGE_TYPE_ADDRESS: case LDP_MESSAGE_TYPE_ADDRESS_WITHDRAW: - case LDP_MESSAGE_TYPE_LABEL_MAPPING: case LDP_MESSAGE_TYPE_LABEL_REQUEST: case LDP_MESSAGE_TYPE_LABEL_WITHDRAW: case LDP_MESSAGE_TYPE_LABEL_RELEASE: @@ -225,9 +302,9 @@ ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) if(buf) { if(buffer->idx+len > buffer->size) { - LOG(ERROR, "LDP (%s:%u - %s:%u) receive error (read buffer exhausted)\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(ERROR, "LDP (%s - %s) receive error (read buffer exhausted)\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); if(!session->error_code) { session->error_code = LDP_STATUS_INTERNAL_ERROR; } diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index 932e700e..56e288e0 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -32,9 +32,9 @@ static void ldp_session_state_change(ldp_session_s *session, ldp_state_t new_state) { if(session->state != new_state) { - LOG(LDP, "LDP (%s:%u - %s:%u) state changed from %s -> %s\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + LOG(LDP, "LDP (%s - %s) state changed from %s -> %s\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), ldp_session_state_string(session->state), ldp_session_state_string(new_state)); session->state = new_state; @@ -103,9 +103,9 @@ ldp_raw_update_stop_cb(void *arg) session->stats.pdu_tx += session->raw_update->pdu; session->stats.message_tx += session->raw_update->messages; - LOG(LDP, "LDP (%s:%u - %s:%u) raw update stop after %lds\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + LOG(LDP, "LDP (%s - %s) raw update stop after %lds\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), time_diff.tv_sec); } @@ -119,9 +119,9 @@ ldp_session_update_job(timer_s *timer) if(bbl_tcp_send(session->tcpc, session->raw_update->buf, session->raw_update->len)) { session->raw_update_sending = true; - LOG(LDP, "LDP (%s:%u - %s:%u) raw update start\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) raw update start\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); clock_gettime(CLOCK_MONOTONIC, &session->update_start_timestamp); session->tcpc->idle_cb = ldp_raw_update_stop_cb; @@ -162,9 +162,9 @@ ldp_session_keepalive_timeout_job(timer_s *timer) { ldp_session_s *session = timer->data; - LOG(LDP, "LDP (%s:%u - %s:%u) keepalive timer expired\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) keepalive timer expired\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); if(!session->error_code) { session->error_code = LDP_STATUS_KEEPALIVE_TIMER_EXPIRED; @@ -294,9 +294,9 @@ void ldp_error_cb(void *arg, err_t err) { ldp_session_s *session = (ldp_session_s*)arg; - LOG(LDP, "LDP (%s:%u - %s:%u) TCP error %d (%s)\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id, + LOG(LDP, "LDP (%s - %s) TCP error %d (%s)\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), err, tcp_err_string(err)); ldp_session_state_change(session, LDP_ERROR); @@ -329,17 +329,17 @@ ldp_session_connect_job(timer_s *timer) /* Close session if not established within 60 seconds */ timeout = 60; } else { - LOG(LDP, "LDP (%s:%u - %s:%u) TCP connect failed\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) TCP connect failed\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); } } else if(session->state == LDP_OPERATIONAL) { timer->periodic = false; return; } else { - LOG(LDP, "LDP (%s:%u - %s:%u) connect timeout\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) connect timeout\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); ldp_session_close(session); timer->periodic = false; @@ -371,9 +371,9 @@ ldp_session_listen(ldp_session_s *session) "LDP CONNECT", 60, 0, session, &ldp_session_connect_job); } else { - LOG(LDP, "LDP (%s:%u - %s:%u) TCP listen failed\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) TCP listen failed\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); ldp_session_close(session); } } @@ -522,9 +522,9 @@ ldp_session_close(ldp_session_s *session) { time_t delay = 0; - LOG(LDP, "LDP (%s:%u - %s:%u) close session\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) close session\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); /* Stop all timers */ timer_del(session->connect_timer); @@ -537,9 +537,9 @@ ldp_session_close(ldp_session_s *session) } if(session->state > LDP_CONNECT && session->state < LDP_CLOSING) { - LOG(LDP, "LDP (%s:%u - %s:%u) send notification message\n", - format_ipv4_address(&session->local.lsr_id), session->local.label_space_id, - format_ipv4_address(&session->peer.lsr_id), session->peer.label_space_id); + LOG(LDP, "LDP (%s - %s) send notification message\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); ldp_session_reset_write_buffer(session); ldp_pdu_init(session); From 6b90bff3890edb0b5c8d0c82a8223b9bf423d438 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 14 Dec 2022 21:29:14 +0000 Subject: [PATCH 13/27] LDP stream traffic support --- code/bngblaster/src/bbl_config.c | 7 ++++ code/bngblaster/src/bbl_stream.c | 47 ++++++++++++++++++++++-- code/bngblaster/src/bbl_stream.h | 4 ++ code/bngblaster/src/ldp/ldp_db.c | 14 +++++++ code/bngblaster/src/ldp/ldp_db.h | 3 ++ docsrc/sources/configuration/streams.rst | 7 +++- 6 files changed, 77 insertions(+), 5 deletions(-) diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index 3ce0ae62..45c4eac9 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1577,6 +1577,13 @@ json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config) stream_config->start_delay = json_number_value(value); } + if(json_unpack(stream, "{s:s}", "ldp-ipv4-lookup-address", &s) == 0) { + if(!inet_pton(AF_INET, s, &stream_config->ipv4_ldp_lookup_address)) { + fprintf(stderr, "JSON config error: Invalid value for stream->ldp-ipv4-lookup-address\n"); + return false; + } + } + if(json_unpack(stream, "{s:s}", "access-ipv4-source-address", &s) == 0) { if(!inet_pton(AF_INET, s, &stream_config->ipv4_access_src_address)) { fprintf(stderr, "JSON config error: Invalid value for stream->access-ipv4-source-address\n"); diff --git a/code/bngblaster/src/bbl_stream.c b/code/bngblaster/src/bbl_stream.c index d3e6b392..27c28725 100644 --- a/code/bngblaster/src/bbl_stream.c +++ b/code/bngblaster/src/bbl_stream.c @@ -580,9 +580,13 @@ bbl_stream_build_network_packet(bbl_stream_s *stream) eth.vlan_inner = 0; /* Add MPLS labels */ - if(config->tx_mpls1) { + if(config->tx_mpls1 || stream->ldp_entry) { eth.mpls = &mpls1; - mpls1.label = config->tx_mpls1_label; + if(stream->ldp_entry) { + mpls1.label = stream->ldp_entry->label; + } else { + mpls1.label = config->tx_mpls1_label; + } mpls1.exp = config->tx_mpls1_exp; mpls1.ttl = config->tx_mpls1_ttl; if(config->tx_mpls2) { @@ -1143,6 +1147,32 @@ bbl_stream_final() dict_itor_free(itor); } +static bool +bbl_stream_ldp_lookup(bbl_stream_s *stream) +{ + if(!stream->ldp_entry) { + if(stream->sub_type == BBL_SUB_TYPE_IPV4) { + stream->ldp_entry = ldb_db_lookup_ipv4( + stream->network_interface->ldp_adjacency->instance, + stream->config->ipv4_ldp_lookup_address); + } + } + + if(!(stream->ldp_entry && stream->ldp_entry->active)) { + return false; + } + if(stream->ldp_entry->version != stream->ldp_entry_version) { + stream->ldp_entry_version = stream->ldp_entry->version; + /* Free packet if LDP entry has changed. */ + if(stream->tx_buf) { + free(stream->tx_buf); + stream->tx_buf = NULL; + stream->tx_len = 0; + } + } + return true; +} + static bool bbl_stream_can_send(bbl_stream_s *stream) { @@ -1155,10 +1185,13 @@ bbl_stream_can_send(bbl_stream_s *stream) stream->stop) { return false; } + if(stream->ldp_lookup) { + return bbl_stream_ldp_lookup(stream); + } return true; } - /* Free packet if not ready to send */ + /* Free packet if not ready to send. */ if(stream->tx_buf) { free(stream->tx_buf); stream->tx_buf = NULL; @@ -1570,6 +1603,11 @@ bbl_stream_session_add(bbl_stream_config_s *config, bbl_session_s *session) switch(stream->sub_type) { case BBL_SUB_TYPE_IPV4: stream->endpoint = &session->endpoint.ipv4; + if(config->ipv4_ldp_lookup_address && + network_interface && + network_interface->ldp_adjacency) { + stream->ldp_lookup = true; + } break; case BBL_SUB_TYPE_IPV6: stream->endpoint = &session->endpoint.ipv6; @@ -1727,6 +1765,9 @@ bbl_stream_init() { stream->endpoint = &(g_ctx->multicast_endpoint); stream->type = BBL_TYPE_MULTICAST; } + if(config->ipv4_ldp_lookup_address && network_interface->ldp_adjacency) { + stream->ldp_lookup = true; + } } stream->direction = BBL_DIRECTION_DOWN; stream->network_interface = network_interface; diff --git a/code/bngblaster/src/bbl_stream.h b/code/bngblaster/src/bbl_stream.h index a4dc758d..bd3a93c3 100644 --- a/code/bngblaster/src/bbl_stream.h +++ b/code/bngblaster/src/bbl_stream.h @@ -30,6 +30,7 @@ typedef struct bbl_stream_config_ uint8_t priority; /* IPv4 TOS or IPv6 TC */ uint8_t vlan_priority; + uint32_t ipv4_ldp_lookup_address; uint32_t ipv4_access_src_address; /* overwrite default IPv4 access address */ ipv6addr_t ipv6_access_src_address; /* overwrite default IPv6 access address */ uint32_t ipv4_network_address; /* overwrite default IPv4 network address */ @@ -105,6 +106,9 @@ typedef struct bbl_stream_ bool stop; bool reset; bool lag; + bool ldp_lookup; + uint32_t ldp_entry_version; + ldp_db_entry_s *ldp_entry; bool send_window_active; uint64_t send_window_start_packets; diff --git a/code/bngblaster/src/ldp/ldp_db.c b/code/bngblaster/src/ldp/ldp_db.c index fa5ff4fc..8890d319 100644 --- a/code/bngblaster/src/ldp/ldp_db.c +++ b/code/bngblaster/src/ldp/ldp_db.c @@ -63,4 +63,18 @@ ldb_db_add_ipv4(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label) entry->label = label; entry->source = session; return true; +} + +ldp_db_entry_s * +ldb_db_lookup_ipv4(ldp_instance_s *instance, uint32_t address) +{ + void **search = NULL; + ldp_db_entry_s *entry; + + search = hb_tree_search(instance->db.ipv4, &address); + if(search) { + entry = *search; + return entry; + } + return NULL; } \ No newline at end of file diff --git a/code/bngblaster/src/ldp/ldp_db.h b/code/bngblaster/src/ldp/ldp_db.h index 7574a7f8..31d84647 100644 --- a/code/bngblaster/src/ldp/ldp_db.h +++ b/code/bngblaster/src/ldp/ldp_db.h @@ -15,4 +15,7 @@ ldb_db_init(ldp_instance_s *instance); bool ldb_db_add_ipv4(ldp_session_s *session, ipv4_prefix *prefix, uint32_t label); +ldp_db_entry_s * +ldb_db_lookup_ipv4(ldp_instance_s *instance, uint32_t address); + #endif \ No newline at end of file diff --git a/docsrc/sources/configuration/streams.rst b/docsrc/sources/configuration/streams.rst index 0986e88e..04e0fbdc 100644 --- a/docsrc/sources/configuration/streams.rst +++ b/docsrc/sources/configuration/streams.rst @@ -95,10 +95,10 @@ - MPLS send (TX) label (inner label) - * - `tx-label2-exp` - - EXP bits of the first label (inner label) + - EXP bits of the second label (inner label) - 0 * - `tx-label2-ttl` - - TTL of the first label (inner label) + - TTL of the second label (inner label) - 255 * - `rx-label1` - Expected receive MPLS label (outer label) @@ -106,6 +106,9 @@ * - `rx-label2` - Expected receive MPLS label (inner label) - + * - `ldp-ipv4-lookup-address` + - Dynamically resolve outer label + - For L2TP downstream traffic, the IPv4 TOS is applied to the outer IPv4 and inner IPv4 header. From cc38610fa69b54716dcf74784168babc6fb50c3e Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 14 Dec 2022 22:32:55 +0000 Subject: [PATCH 14/27] LDP fix MPLS TTL and EXP --- code/bngblaster/src/bbl_config.c | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index 45c4eac9..df0d1a52 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1641,32 +1641,33 @@ json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config) if(value) { stream_config->tx_mpls1 = true; stream_config->tx_mpls1_label = json_number_value(value); - value = json_object_get(stream, "tx-label1-exp"); - if(value) { - stream_config->tx_mpls1_exp = json_number_value(value); - } - value = json_object_get(stream, "tx-label1-ttl"); - if(value) { - stream_config->tx_mpls1_ttl = json_number_value(value); - } else { - stream_config->tx_mpls1_ttl = 255; - } + } + value = json_object_get(stream, "tx-label1-exp"); + if(value) { + stream_config->tx_mpls1_exp = json_number_value(value); + } + value = json_object_get(stream, "tx-label1-ttl"); + if(value) { + stream_config->tx_mpls1_ttl = json_number_value(value); + } else { + stream_config->tx_mpls1_ttl = 255; } value = json_object_get(stream, "tx-label2"); if(value) { stream_config->tx_mpls2 = true; stream_config->tx_mpls2_label = json_number_value(value); - value = json_object_get(stream, "tx-label2-exp"); - if(value) { - stream_config->tx_mpls2_exp = json_number_value(value); - } - value = json_object_get(stream, "tx-label2-ttl"); - if(value) { - stream_config->tx_mpls2_ttl = json_number_value(value); - } else { - stream_config->tx_mpls2_ttl = 255; - } } + value = json_object_get(stream, "tx-label2-exp"); + if(value) { + stream_config->tx_mpls2_exp = json_number_value(value); + } + value = json_object_get(stream, "tx-label2-ttl"); + if(value) { + stream_config->tx_mpls2_ttl = json_number_value(value); + } else { + stream_config->tx_mpls2_ttl = 255; + } + value = json_object_get(stream, "rx-label1"); if(value) { stream_config->rx_mpls1 = true; From 4254e94ccf374bba830026e5dc1f5f1976fc1c2f Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 14 Dec 2022 23:14:25 +0000 Subject: [PATCH 15/27] add ldpupdate script --- code/CMakeLists.txt | 3 +- code/ldpupdate | 156 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 code/ldpupdate diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 19fab514..0c7c3c80 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -6,4 +6,5 @@ add_subdirectory(bngblaster) add_subdirectory(lspgen) install(PROGRAMS bngblaster-cli DESTINATION sbin) -install(PROGRAMS bgpupdate DESTINATION bin) \ No newline at end of file +install(PROGRAMS bgpupdate DESTINATION bin) +install(PROGRAMS ldpupdate DESTINATION bin) \ No newline at end of file diff --git a/code/ldpupdate b/code/ldpupdate new file mode 100644 index 00000000..8125d864 --- /dev/null +++ b/code/ldpupdate @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +""" +LDP RAW Update Generator + +Christian Giese, December 2022 + +Copyright (C) 2020-2022, RtBrick, Inc. +SPDX-License-Identifier: BSD-3-Clause +""" +import argparse +import ipaddress +import json +import logging +import struct +import sys + +try: + from scapy.all import * + log_runtime.setLevel(logging.ERROR) + from scapy.contrib.ldp import * + log_runtime.setLevel(logging.INFO) +except: + print("Failed to load scapy!") + exit(1) + +# ============================================================== +# DEFINITIONS +# ============================================================== + +DESCRIPTION = """ +The LDP RAW update generator is a simple +tool to generate LDP RAW update streams +for use with the BNG Blaster. +""" + +LOG_LEVELS = { + 'warning': logging.WARNING, + 'info': logging.INFO, + 'debug': logging.DEBUG +} + +MPLS_LABEL_MIN = 1 +MPLS_LABEL_MAX = 1048575 + +# ============================================================== +# FUNCTIONS +# ============================================================== + +def init_logging(log_level: int) -> logging.Logger: + """Init logging.""" + level = LOG_LEVELS[log_level] + log = logging.getLogger() + log.setLevel(level) + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(level) + formatter = logging.Formatter('[%(asctime)s][%(levelname)-7s] %(message)s') + formatter.datefmt = '%Y-%m-%d %H:%M:%S' + handler.setFormatter(formatter) + log.addHandler(handler) + return log + + +def label_type(label: int) -> int: + """Argument parser type for MPLS labels.""" + label = int(label) + if label < MPLS_LABEL_MIN or label > MPLS_LABEL_MAX: + raise argparse.ArgumentTypeError("MPLS label out of range %s - %s" % (MPLS_LABEL_MIN, MPLS_LABEL_MAX)) + return label + + +# ============================================================== +# MAIN +# ============================================================== + +def main(): + # parse arguments + parser = argparse.ArgumentParser(description=DESCRIPTION) + parser.add_argument('-l', '--lsr-id', metavar='ADDRESS', type=ipaddress.ip_address, required=True, help='LSR identifier') + parser.add_argument('-i', '--message-id-base', metavar='N', type=int, default=1000, help='message identifier base') + parser.add_argument('-p', '--prefix-base', metavar='PREFIX', type=ipaddress.ip_network, required=True, help='prefix base network') + parser.add_argument('-P', '--prefix-num', metavar='N', type=int, default=1, help='prefix count') + parser.add_argument('-m', '--label-base', metavar='LABEL', type=label_type, default=10000, help='label base') + parser.add_argument('-M', '--label-num', metavar='N', type=int, default=1, help='label count') + parser.add_argument('-f', '--file', type=str, default="out.ldp", help='output file') + parser.add_argument('--append', action="store_true", help="append to file if exist") + parser.add_argument('--pcap', metavar='FILE', type=str, help="write LDP updates to PCAP file") + parser.add_argument('--log-level', type=str, default='info', choices=LOG_LEVELS.keys(), help='logging Level') + args = parser.parse_args() + + # init logging + log = init_logging(args.log_level) + if args.prefix_base.version != 4: + log.error("prefix must be IPv4") + exit(1) + + log.info("init %s labeled IPv4 prefixes" % (args.prefix_num)) + + # Here we will store packets for optional PCAP output + pcap_packets = [] + def pcap(message): + if args.pcap: + pcap_packets.append(Ether()/IP()/TCP(sport=len(pcap_packets)+10000, dport=646, seq=1, flags='PA')/message) + + prefixes = [] + + label_index = 0 + prefix = args.prefix_base + label = args.label_base + for _ in range(args.prefix_num): + log.debug("add prefix %s via label %s" % (prefix, label)) + prefixes.append((prefix, label)) + + label_index += 1 + if label_index < args.label_num: + label = args.label_base + label_index + if label > MPLS_LABEL_MAX: + label_index = 0 + label = args.label_base + else: + label_index = 0 + label = args.label_base + + prefix = ipaddress.ip_network("%s/%s" % (prefix.broadcast_address+1, prefix.prefixlen)) + + if args.append: + log.info("open file %s (append)" % args.file) + file_flags = "ab" + else: + log.info("open file %s (replace)" % args.file) + file_flags = "wb" + + with open(args.file, file_flags) as f: + + mid = args.message_id_base + + for prefix, label in prefixes: + pdu = LDP(id=args.lsr_id)/LDPLabelMM(id=mid, fec=[(str(prefix.network_address),int(prefix.prefixlen))],label=label) + mid+=1 + + pdu_bin = bytearray(pdu.build()) + pcap(pdu) + f.write(pdu_bin) + + if args.pcap: + log.info("create PCAP file %s" % args.pcap) + try: + wrpcap(args.pcap, pcap_packets) + except Exception as e: + log.error("failed to create PCAP file") + log.debug(e) + + log.info("finished") + + +if __name__ == "__main__": + main() \ No newline at end of file From 16c58bb64a189a208084db0441877bb0cbc8053f Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 14 Dec 2022 23:15:45 +0000 Subject: [PATCH 16/27] LDP docu update --- code/README.md | 5 ++ docsrc/sources/quickstart.rst | 65 +++++++++++++++ docsrc/sources/routing/ldp.rst | 141 ++++++++++++++++++++++++++++++--- 3 files changed, 202 insertions(+), 9 deletions(-) diff --git a/code/README.md b/code/README.md index 240d9b39..ca21e73e 100644 --- a/code/README.md +++ b/code/README.md @@ -33,3 +33,8 @@ control socket JSON RPC API. Simple python script to generate BGP RAW update streams for use with the BNG Blaster. + +### ldpupdate + +Simple python script to generate LDP RAW update +streams for use with the BNG Blaster. diff --git a/docsrc/sources/quickstart.rst b/docsrc/sources/quickstart.rst index bac45f87..d0cbc358 100644 --- a/docsrc/sources/quickstart.rst +++ b/docsrc/sources/quickstart.rst @@ -646,3 +646,68 @@ Finally, you can withdraw them again. bgpupdate -a 65001 -n 192.168.92.2 -p 22.0.0.0/28 -P 100000 -f withdraw.bgp --withdraw sudo bngblaster-cli run.sock bgp-raw-update file withdraw.bgp +LDP +--- + +In the following example, we create two connected :ref:`LDP ` instances. + +**ldp.json:** + +.. code-block:: json + + { + "interfaces": { + "capture-include-streams": true, + "network": [ + { + "interface": "veth1.1", + "address": "10.0.0.1/24", + "gateway": "10.0.0.2", + "ldp-instance-id": 1 + }, + { + "interface": "veth1.2", + "address": "10.0.0.2/24", + "gateway": "10.0.0.1", + "ldp-instance-id": 2 + } + ] + }, + "ldp": [ + { + "instance-id": 1, + "lsr-id": "10.2.3.1", + "raw-update-file": "out.ldp" + }, + { + "instance-id": 2, + "lsr-id": "10.2.3.2" + } + ], + "streams": [ + { + "name": "S1", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "network-interface": "veth1.2", + "destination-ipv4-address": "100.0.0.1", + "ldp-ipv4-lookup-address": "13.37.0.1", + "pps": 1 + } + ] + } + +Use the included tool ``ldpupdate`` to generate an LDP update file +with 10 labeled IPv4 prefixes. + +.. code-block:: none + + ldpupdate -l 10.2.3.1 -p 13.37.0.0/32 -P 10 -M 10000 + +Now you can start the BNG Blaster with this configuration. + +.. code-block:: none + + sudo bngblaster -C ldp.json -l ldp -S run.sock -P ldp.pcap + diff --git a/docsrc/sources/routing/ldp.rst b/docsrc/sources/routing/ldp.rst index 7867180c..33019609 100644 --- a/docsrc/sources/routing/ldp.rst +++ b/docsrc/sources/routing/ldp.rst @@ -21,16 +21,12 @@ attached to two network interfaces. "interface": "eth1", "address": "10.0.1.2/24", "gateway": "10.0.1.1", - "address-ipv6": "fc66:1337:7331:1::2/64", - "gateway-ipv6": "fc66:1337:7331:1::1", "ldp-instance-id": 1, }, { "interface": "eth2", "address": "10.0.2.2/24", "gateway": "10.0.2.1", - "address-ipv6": "fc66:1337:7331:2::2/64", - "gateway-ipv6": "fc66:1337:7331:2::1", "ldp-instance-id": 2 } ] @@ -38,13 +34,11 @@ attached to two network interfaces. "ldp": [ { "instance-id": 1, - "lsr-id": "10.10.10.11", - "hostname": "R1", + "lsr-id": "10.10.10.11" }, { "instance-id": 1, - "lsr-id": "10.10.10.12", - "hostname": "R2", + "lsr-id": "10.10.10.12" } ] } @@ -54,8 +48,77 @@ attached to two network interfaces. Limitations ~~~~~~~~~~~ +LDP sessions between IPv6 addresses and IPv6 label mappings +are currently not supported. + LDP authentication is currently not supported but already -planned as an enhancement in one of the next releases. +planned as an enhancement in one of the next releases. + +LDP Traffic Streams +~~~~~~~~~~~~~~~~~~~ + +Traffic streams send from network interface functions (downstream) +can be configured to dynamically resolve the outer MPLS +label using the learned label mappings. + +The traffic stream configuration option `ldp-ipv4-lookup-address` +specifies the lookup IPv4 address. This means that traffic +will not start until this address is found in the corresponding +label database of the sending network interface function. + +.. code-block:: json + + { + "streams": [ + { + "name": "S1", + "type": "ipv4", + "direction": "downstream", + "priority": 128, + "network-interface": "eth1", + "destination-ipv4-address": "10.0.0.1", + "ldp-ipv4-lookup-address": "13.37.0.1", + "pps": 1 + } + ] + } + +``$ sudo bngblaster-cli run.sock ldp-database instance 1`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "ldp-database": [ + { + "direction": "ipv4", + "prefix": "10.0.0.0/24", + "label": 3, + "source-identifier": "10.2.3.1:0" + }, + { + "direction": "ipv4", + "prefix": "13.37.0.0/32", + "label": 10000, + "source-identifier": "10.2.3.1:0" + }, + { + "direction": "ipv4", + "prefix": "13.37.0.1/32", + "label": 10001, + "source-identifier": "10.2.3.1:0" + } + ] + } + +The `ldp-ipv4-lookup-address` must exactly match the prefix address +as shown in the LDP database. + +.. note:: + + There is currently no longest prefix match supported, + meaning that the actual prefix length is ignored! RAW Update Files ~~~~~~~~~~~~~~~~ @@ -87,3 +150,63 @@ more than a pre-compiled binary stream of LDP PDU. . LDP Messages . +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Those files can be created using the included LDP RAW update generator +script ``ldpupdate`` or manually using libraries like scapy. + +The configured ``raw-update-file`` under the LDP instance is loaded +during BNG Blaster startup phase and send it as soon as the session is +established. + +The ``ldp-raw-update`` :ref:`command ` allows to send further updates during +the session lifetime. + +``$ sudo bngblaster-cli run.sock ldp-raw-update file update1.ldp`` + +This allows loading label mappings after the LDP session has +started and manually trigger a series of changes using incremental +updates files. + +All LDP RAW update files are loaded once and can then be used for +multiple sessions. Meaning if two or more sessions reference the +same file identified by file name, this file is loaded once into +memory and used by multiple sessions. + +LDP RAW Update Generator +~~~~~~~~~~~~~~~~~~~~~~~~ + +The LDP RAW update generator is a simple tool to generate LDP RAW update +streams for use with the BNG Blaster. + +.. code-block:: none + + $ ldpupdate --help + usage: ldpupdate [-h] -l ADDRESS [-i N] -p PREFIX [-P N] [-m LABEL] [-M N] + [-f FILE] [--append] [--pcap FILE] + [--log-level {warning,info,debug}] + + The LDP RAW update generator is a simple tool to generate LDP RAW update + streams for use with the BNG Blaster. + + optional arguments: + -h, --help show this help message and exit + -l ADDRESS, --lsr-id ADDRESS + LSR identifier + -i N, --message-id-base N + message identifier base + -p PREFIX, --prefix-base PREFIX + prefix base network + -P N, --prefix-num N prefix count + -m LABEL, --label-base LABEL + label base + -M N, --label-num N label count + -f FILE, --file FILE output file + --append append to file if exist + --pcap FILE write LDP updates to PCAP file + --log-level {warning,info,debug} + logging Level + +The python LDP RAW update generator is a python script that uses +scapy to build LDP PDU. Therefore this tool can be easily +modified, extend or used as a blueprint for your own tools to generate +valid LDP update streams. \ No newline at end of file From 347af5d6999756789c0b4fe6e9204855956ecc63 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 15 Dec 2022 09:34:27 +0000 Subject: [PATCH 17/27] LDP docu update --- docsrc/sources/index.rst | 7 ++- docsrc/sources/install.rst | 6 +- docsrc/sources/routing/ldp.rst | 104 +++++++++++++++++++++++++++------ 3 files changed, 93 insertions(+), 24 deletions(-) diff --git a/docsrc/sources/index.rst b/docsrc/sources/index.rst index bcf0bfed..e0c3ccd1 100644 --- a/docsrc/sources/index.rst +++ b/docsrc/sources/index.rst @@ -2,7 +2,7 @@ BNG Blaster =========== The **BNG Blaster** is an open-source network tester -for access and routing protocols. It can emulate massive +for access and routing protocols. It can emulate a huge amount of PPPoE and IPoE (DHCP) subscribers including IPTV, and L2TP (LNS). There are various routing protocols supported like ISIS and BGP. So you can use it for end-to-end BNG and non-BNG router testing. @@ -41,10 +41,11 @@ RtBrick and many more. .. tab:: Routing Protocols - * Emulate ISIS topologies with thousands of nodes - * Support for ISIS Segment Routing * Setup thousands of BGP sessions with millions of prefixes * Verify MPLS labels for millions of flows + * Emulate ISIS topologies with thousands of nodes + * Support for ISIS Segment Routing + * Support for LDP and traffic streams with dynamically resolved labels * Support all routing protocols with link aggregation (LAG) * ... diff --git a/docsrc/sources/install.rst b/docsrc/sources/install.rst index 888f2716..e64e44a6 100644 --- a/docsrc/sources/install.rst +++ b/docsrc/sources/install.rst @@ -159,7 +159,7 @@ It is recommended to install the DPDK development package if possible: sudo apt install dpdk libdpdk-dev This package does not support all NIC types (e.g. Mellanox, ...), -which requires to download and installing DPDK manually: +which requires downloading and installing DPDK manually: https://doc.dpdk.org/guides/linux_gsg/build_dpdk.html .. code-block:: none @@ -212,8 +212,8 @@ Running BNG Blaster ------------------- The BNG Blaster needs permission to send raw packets and change network interface -settings. The easiest way to run the BNG Blaster is either as the root user or with -sudo: +settings. The easiest way to run the BNG Blaster is either as the root user or +with `sudo`: .. code-block:: none diff --git a/docsrc/sources/routing/ldp.rst b/docsrc/sources/routing/ldp.rst index 33019609..adfe927e 100644 --- a/docsrc/sources/routing/ldp.rst +++ b/docsrc/sources/routing/ldp.rst @@ -3,14 +3,23 @@ LDP --- -The Label Distribution Protocol (LDP) is a protocol defined for -distributing labels. +Label Distribution Protocol (LDP) is a protocol in which routers capable +of Multiprotocol Label Switching (MPLS) exchange label mapping information. +Two routers with an established session are called LDP peers and the exchange +of information is bi-directional. LDP is used to build and maintain LSP databases +that are used to forward traffic through MPLS networks. + +LDP discovery runs on UDP port 646 and the session is built on TCP port 646. During +the discovery phase hello packets are sent on UDP port 646 to the 'all routers on this subnet' +group multicast address (224.0.0.2). + +LDP is defined by the IETF (RFC 5036). Configuration ~~~~~~~~~~~~~ -Following an example LDP configuration with one instance -attached to two network interfaces. +Following an example LDP configuration with one instance +attached to a network interface function. .. code-block:: json @@ -22,12 +31,6 @@ attached to two network interfaces. "address": "10.0.1.2/24", "gateway": "10.0.1.1", "ldp-instance-id": 1, - }, - { - "interface": "eth2", - "address": "10.0.2.2/24", - "gateway": "10.0.2.1", - "ldp-instance-id": 2 } ] }, @@ -35,10 +38,6 @@ attached to two network interfaces. { "instance-id": 1, "lsr-id": "10.10.10.11" - }, - { - "instance-id": 1, - "lsr-id": "10.10.10.12" } ] } @@ -48,11 +47,80 @@ attached to two network interfaces. Limitations ~~~~~~~~~~~ -LDP sessions between IPv6 addresses and IPv6 label mappings -are currently not supported. +The following LDP functionalities are currently +not supported: -LDP authentication is currently not supported but already -planned as an enhancement in one of the next releases. ++ Targeted LDP ++ LDP TCP authentication ++ LDP sessions between IPv6 addresses ++ Learn IPv6 label mappings ++ Multiple links between LDP instance and DUT (ECMP) + +LDP Adjacencies +~~~~~~~~~~~~~~~~ + +When the BNG Blaster receives an LDP discovery hello message, +an LDP adjacency is set up between the two peers. + +``$ sudo bngblaster-cli run.sock ldp-adjacencies`` + +.. code-block:: json + { + "status": "ok", + "code": 200, + "ldp-adjacencies": [ + { + "ldp-instance-id": 1, + "interface": "eth0", + "state": "up" + } + ] + } + +LDP Sessions +~~~~~~~~~~~~ + +LDP peers exchange messages over a TCP session which is initiated by +the peer with the larger transport IP address (active peer). + +The LDP transport IP address can be explicitly configured for the +LDP instance using the option `ipv4-transport-address`. The `lsr-id` +is used as a transport IP address if not explicitly configured. + +.. note:: + + It is currently not supported to setup multiple links between + a single LDP instance and the device under test (ECMP). + +``$ sudo bngblaster-cli run.sock ldp-sessions`` + +.. code-block:: json + + { + "status": "ok", + "code": 200, + "ldp-sessions": [ + { + "ldp-instance-id": 1, + "interface": "eth0", + "local-address": "10.2.3.1", + "local-identifier": "10.2.3.1:0", + "peer-address": "10.2.3.2", + "peer-identifier": "10.2.3.2:0", + "state": "operational", + "raw-update-state": "done", + "raw-update-file": "out.ldp", + "stats": { + "pdu-rx": 23, + "pdu-tx": 32, + "messages-rx": 24, + "messages-tx": 34, + "keepalive-rx": 21, + "keepalive-tx": 21 + } + } + ] + } LDP Traffic Streams ~~~~~~~~~~~~~~~~~~~ From 458349ea72f6ca55ea5a9253cc34ec97dd47bd29 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 15 Dec 2022 13:01:38 +0000 Subject: [PATCH 18/27] LDP minor enhancements --- code/bngblaster/src/ldp/ldp_ctrl.c | 11 ++++-- code/bngblaster/src/ldp/ldp_def.h | 6 ++++ code/bngblaster/src/ldp/ldp_hello.c | 8 +++-- code/bngblaster/src/ldp/ldp_receive.c | 51 +++++++++++++++++++++++++-- code/bngblaster/src/ldp/ldp_session.c | 3 ++ code/common/src/utils.h | 2 +- 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/code/bngblaster/src/ldp/ldp_ctrl.c b/code/bngblaster/src/ldp/ldp_ctrl.c index 5cd21d73..b43cee65 100644 --- a/code/bngblaster/src/ldp/ldp_ctrl.c +++ b/code/bngblaster/src/ldp/ldp_ctrl.c @@ -49,10 +49,14 @@ ldp_ctrl_adjacencies(int fd, uint32_t session_id __attribute__((unused)), json_t } ldp_adjacency = ldp_instance->adjacencies; while(ldp_adjacency) { - adjacency = json_pack("{si ss ss}", + adjacency = json_pack("{si ss ss si si si si}", "ldp-instance-id", ldp_adjacency->instance->config->id, "interface", ldp_adjacency->interface->name, - "state", ldp_adjacency->state == LDP_ADJACENCY_STATE_UP ? "up" : "down"); + "state", ldp_adjacency->state == LDP_ADJACENCY_STATE_UP ? "up" : "down", + "state-transitions", ldp_adjacency->state_transitions, + "rx-discovery", ldp_adjacency->interface->stats.ldp_udp_rx, + "rx-discovery-error", ldp_adjacency->interface->stats.ldp_udp_rx_error, + "tx-discovery", ldp_adjacency->interface->stats.ldp_udp_tx); if(adjacency) { json_array_append(adjacencies, adjacency); } @@ -103,7 +107,7 @@ ldp_ctrl_session_json(ldp_session_s *session) return NULL; } - root = json_pack("{si ss ss ss ss ss ss ss* ss* so*}", + root = json_pack("{si ss ss ss ss ss ss si ss* ss* so*}", "ldp-instance-id", session->instance->config->id, "interface", session->interface->name, "local-address", format_ipv4_address(&session->local.ipv4_address), @@ -111,6 +115,7 @@ ldp_ctrl_session_json(ldp_session_s *session) "peer-address", format_ipv4_address(&session->peer.ipv4_address), "peer-identifier", ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), "state", ldp_session_state_string(session->state), + "state-transitions", session->state_transitions, "raw-update-state", raw_update_state(session), "raw-update-file", raw_update_file, "stats", stats); diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index 154b9e34..e563bef0 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -52,11 +52,15 @@ #define LDP_TLV_LEN_MIN 4 #define LDP_FEC_LEN_MIN 4 #define LDP_FEC_ELEMENT_TYPE_PREFIX 2 +#define LDP_STATUS_LEN_MIN 10 #define LDP_STATUS_SUCCESS 0x00000000 #define LDP_STATUS_BAD_IDENTIFIER 0x00000001 #define LDP_STATUS_BAD_VERSION 0x00000002 +#define LDP_STATUS_BAD_PDU_LEN 0x00000003 +#define LDP_STATUS_UNKNOWN_MSG_TYPE 0x00000004 #define LDP_STATUS_BAD_MSG_LEN 0x00000005 +#define LDP_STATUS_UNKNOWN_TLV_TYPE 0x00000006 #define LDP_STATUS_BAD_TLV_LEN 0x00000007 #define LDP_STATUS_BAD_TLV_VALUE 0x00000008 #define LDP_STATUS_HOLD_TIMER_EXPIRED 0x00000009 @@ -177,6 +181,7 @@ typedef struct ldp_session_ { bool decode_error; bool active; ldp_state_t state; + uint32_t state_transitions; uint16_t max_pdu_len; uint16_t keepalive_time; @@ -233,6 +238,7 @@ typedef struct ldp_adjacency_ { uint16_t hold_time; ldp_adjacency_state state; + uint32_t state_transitions; /* Pointer to next adjacency of * corresponding instance with. */ diff --git a/code/bngblaster/src/ldp/ldp_hello.c b/code/bngblaster/src/ldp/ldp_hello.c index ead76564..efac5d6f 100644 --- a/code/bngblaster/src/ldp/ldp_hello.c +++ b/code/bngblaster/src/ldp/ldp_hello.c @@ -90,7 +90,7 @@ ldp_hello_hold_timeout_job(timer_s *timer) if(adjacency->state == LDP_ADJACENCY_STATE_DOWN) { return; } - + adjacency->state_transitions++; adjacency->state = LDP_ADJACENCY_STATE_DOWN; LOG(LDP, "LDP hold timeout on interface %s\n", adjacency->interface->name); } @@ -98,7 +98,11 @@ ldp_hello_hold_timeout_job(timer_s *timer) static void ldp_hello_restart_hold_timeout(ldp_adjacency_s *adjacency) { - adjacency->state = LDP_ADJACENCY_STATE_UP; + if(adjacency->state == LDP_ADJACENCY_STATE_DOWN) { + adjacency->state_transitions++; + adjacency->state = LDP_ADJACENCY_STATE_UP; + LOG(LDP, "LDP adjacency on interface %s\n", adjacency->interface->name); + } timer_add(&g_ctx->timer_root, &adjacency->hold_timer, "LDP HOLD TIMEOUT", adjacency->hold_time, 0, adjacency, &ldp_hello_hold_timeout_job); } diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index 11162d3d..e873c6d7 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -24,6 +24,23 @@ struct keyval_ ldp_msg_names[] = { { 0, NULL} }; +struct keyval_ ldp_status_names[] = { + { LDP_STATUS_SUCCESS, "success" }, + { LDP_STATUS_BAD_IDENTIFIER, "bad LDP identifier" }, + { LDP_STATUS_BAD_VERSION, "bad protocol version" }, + { LDP_STATUS_BAD_PDU_LEN, "bad PDU length" }, + { LDP_STATUS_UNKNOWN_MSG_TYPE, "unknown message type" }, + { LDP_STATUS_BAD_MSG_LEN, "bad message length" }, + { LDP_STATUS_UNKNOWN_TLV_TYPE, "unknown TLV type" }, + { LDP_STATUS_BAD_TLV_LEN, "bad TLV length" }, + { LDP_STATUS_BAD_TLV_VALUE, "bad TLV value" }, + { LDP_STATUS_HOLD_TIMER_EXPIRED, "hold timer expired" }, + { LDP_STATUS_KEEPALIVE_TIMER_EXPIRED, "keepalive timer expired" }, + { LDP_STATUS_SHUTDOWN, "shutdown" }, + { LDP_STATUS_INTERNAL_ERROR, "internal error" }, + { 0, NULL} +}; + static void ldp_decode_error(ldp_session_s *session) { @@ -41,9 +58,37 @@ ldp_decode_error(ldp_session_s *session) static bool ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) { - UNUSED(session); - UNUSED(start); - UNUSED(length); + uint8_t *tlv_start = start; + uint16_t tlv_type; + uint16_t tlv_length; + uint32_t status_code = UINT32_MAX; + + /* Read all TLV's. */ + while(length >= LDP_TLV_LEN_MIN) { + tlv_type = read_be_uint(tlv_start, 2) & 0x3FFF; + tlv_length = read_be_uint(tlv_start+2, 2); + if(tlv_length+LDP_TLV_LEN_MIN > length) { + return false; + } + switch(tlv_type) { + case LDP_TLV_TYPE_STATUS: + if(tlv_length < LDP_STATUS_LEN_MIN) { + return false; + } + status_code = read_be_uint(tlv_start+LDP_TLV_LEN_MIN, 4); + break; + default: + break; + } + length -= (tlv_length+LDP_TLV_LEN_MIN); + tlv_start += (tlv_length+LDP_TLV_LEN_MIN); + } + + LOG(LDP, "LDP (%s - %s) received notification with status code %u (%s)\n", + ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), + ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), + status_code, keyval_get_key(ldp_status_names, status_code)); + return true; } diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index 56e288e0..bdb2df35 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -32,6 +32,9 @@ static void ldp_session_state_change(ldp_session_s *session, ldp_state_t new_state) { if(session->state != new_state) { + if(session->state == LDP_OPERATIONAL || new_state == LDP_OPERATIONAL) { + session->state_transitions++; + } LOG(LDP, "LDP (%s - %s) state changed from %s -> %s\n", ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), diff --git a/code/common/src/utils.h b/code/common/src/utils.h index 926cfa2e..3ae13ccf 100644 --- a/code/common/src/utils.h +++ b/code/common/src/utils.h @@ -23,7 +23,7 @@ bool push_le_uint(struct io_buffer_ *buffer, uint32_t length, uint64_t value); const char *val2key(struct keyval_ *keyval, uint32_t val); uint32_t key2val(struct keyval_ *ptr, const char *key); -const char *keyval_get_key (struct keyval_ *keyval, uint32_t val); +const char *keyval_get_key(struct keyval_ *keyval, uint32_t val); char *format_mac_address(uint8_t *mac); char *format_ipv4_address(uint32_t *addr4); From ab320f58b8a23c7808ab30b3be5b99c67cd4effc Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Fri, 16 Dec 2022 08:16:52 +0000 Subject: [PATCH 19/27] support IPv6 stream LDP lookup via IPv4 address --- code/bngblaster/src/bbl_stream.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/code/bngblaster/src/bbl_stream.c b/code/bngblaster/src/bbl_stream.c index 27c28725..d8ea262d 100644 --- a/code/bngblaster/src/bbl_stream.c +++ b/code/bngblaster/src/bbl_stream.c @@ -1151,7 +1151,7 @@ static bool bbl_stream_ldp_lookup(bbl_stream_s *stream) { if(!stream->ldp_entry) { - if(stream->sub_type == BBL_SUB_TYPE_IPV4) { + if(stream->config->ipv4_ldp_lookup_address) { stream->ldp_entry = ldb_db_lookup_ipv4( stream->network_interface->ldp_adjacency->instance, stream->config->ipv4_ldp_lookup_address); @@ -1603,11 +1603,6 @@ bbl_stream_session_add(bbl_stream_config_s *config, bbl_session_s *session) switch(stream->sub_type) { case BBL_SUB_TYPE_IPV4: stream->endpoint = &session->endpoint.ipv4; - if(config->ipv4_ldp_lookup_address && - network_interface && - network_interface->ldp_adjacency) { - stream->ldp_lookup = true; - } break; case BBL_SUB_TYPE_IPV6: stream->endpoint = &session->endpoint.ipv6; @@ -1632,6 +1627,9 @@ bbl_stream_session_add(bbl_stream_config_s *config, bbl_session_s *session) if(network_interface) { stream->network_interface = network_interface; stream->tx_interface = network_interface->interface; + if(config->ipv4_ldp_lookup_address && network_interface->ldp_adjacency) { + stream->ldp_lookup = true; + } bbl_stream_add(stream); if(stream->session_traffic) { g_ctx->stats.session_traffic_flows++; @@ -1765,14 +1763,14 @@ bbl_stream_init() { stream->endpoint = &(g_ctx->multicast_endpoint); stream->type = BBL_TYPE_MULTICAST; } - if(config->ipv4_ldp_lookup_address && network_interface->ldp_adjacency) { - stream->ldp_lookup = true; - } } stream->direction = BBL_DIRECTION_DOWN; stream->network_interface = network_interface; stream->tx_interface = network_interface->interface; stream->tx_interval = tx_interval; + if(config->ipv4_ldp_lookup_address && network_interface->ldp_adjacency) { + stream->ldp_lookup = true; + } result = dict_insert(g_ctx->stream_flow_dict, &stream->flow_id); if(!result.inserted) { LOG(ERROR, "Failed to insert RAW stream %s\n", config->name); From 056f29ccc62e6a121943012c89d8626834cbf814 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Mon, 19 Dec 2022 18:41:38 +0000 Subject: [PATCH 20/27] fix LDP notification E-bit --- code/bngblaster/src/ldp/ldp_ctrl.c | 2 +- code/bngblaster/src/ldp/ldp_def.h | 3 +++ code/bngblaster/src/ldp/ldp_receive.c | 15 +++++++++++---- code/bngblaster/src/ldp/ldp_session.c | 6 +++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/code/bngblaster/src/ldp/ldp_ctrl.c b/code/bngblaster/src/ldp/ldp_ctrl.c index b43cee65..7894d8d3 100644 --- a/code/bngblaster/src/ldp/ldp_ctrl.c +++ b/code/bngblaster/src/ldp/ldp_ctrl.c @@ -382,7 +382,7 @@ ldp_ctrl_disconnect(int fd, uint32_t session_id __attribute__((unused)), json_t continue; } if(!ldp_session->error_code) { - ldp_session->error_code = LDP_STATUS_SHUTDOWN; + ldp_session->error_code = LDP_STATUS_SHUTDOWN|LDP_STATUS_FATAL_ERROR; } ldp_session_close(ldp_session); disconnected++; diff --git a/code/bngblaster/src/ldp/ldp_def.h b/code/bngblaster/src/ldp/ldp_def.h index e563bef0..af2e3622 100644 --- a/code/bngblaster/src/ldp/ldp_def.h +++ b/code/bngblaster/src/ldp/ldp_def.h @@ -69,6 +69,9 @@ #define LDP_STATUS_SHUTDOWN 0x0000000A #define LDP_STATUS_INTERNAL_ERROR 0x00000019 +#define LDP_STATUS_FATAL_ERROR 0x80000000 +#define LDP_STATUS_FORWARD 0x40000000 + #define LDP_DEFAULT_KEEPALIVE_TIME 15 #define LDP_DEFAULT_HOLD_TIME 15 #define LDP_DEFAULT_TEARDOWN_TIME 5 diff --git a/code/bngblaster/src/ldp/ldp_receive.c b/code/bngblaster/src/ldp/ldp_receive.c index e873c6d7..f1d573b1 100644 --- a/code/bngblaster/src/ldp/ldp_receive.c +++ b/code/bngblaster/src/ldp/ldp_receive.c @@ -50,7 +50,7 @@ ldp_decode_error(ldp_session_s *session) session->decode_error = true; if(!session->error_code) { - session->error_code = LDP_STATUS_INTERNAL_ERROR; + session->error_code = LDP_STATUS_INTERNAL_ERROR|LDP_STATUS_FATAL_ERROR; } ldp_session_close(session); } @@ -62,6 +62,8 @@ ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) uint16_t tlv_type; uint16_t tlv_length; uint32_t status_code = UINT32_MAX; + bool e_bit = false; + bool f_bit = false; /* Read all TLV's. */ while(length >= LDP_TLV_LEN_MIN) { @@ -76,6 +78,9 @@ ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) return false; } status_code = read_be_uint(tlv_start+LDP_TLV_LEN_MIN, 4); + e_bit = status_code & LDP_STATUS_FATAL_ERROR; + f_bit = status_code & LDP_STATUS_FORWARD; + status_code &= 0x3FFFFFFF; break; default: break; @@ -84,10 +89,12 @@ ldp_notification(ldp_session_s *session, uint8_t *start, uint16_t length) tlv_start += (tlv_length+LDP_TLV_LEN_MIN); } - LOG(LDP, "LDP (%s - %s) received notification with status code %u (%s)\n", + LOG(LDP, "LDP (%s - %s) received %s notification with status code %u (%s)%s\n", ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id), - status_code, keyval_get_key(ldp_status_names, status_code)); + (e_bit ? "fatal error" : "advisory"), + status_code, keyval_get_key(ldp_status_names, status_code), + (f_bit ? " wit forwarding bit set" : "")); return true; } @@ -351,7 +358,7 @@ ldp_receive_cb(void *arg, uint8_t *buf, uint16_t len) ldp_id_to_str(session->local.lsr_id, session->local.label_space_id), ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); if(!session->error_code) { - session->error_code = LDP_STATUS_INTERNAL_ERROR; + session->error_code = LDP_STATUS_INTERNAL_ERROR|LDP_STATUS_FATAL_ERROR; } ldp_session_close(session); return; diff --git a/code/bngblaster/src/ldp/ldp_session.c b/code/bngblaster/src/ldp/ldp_session.c index bdb2df35..a3a5e367 100644 --- a/code/bngblaster/src/ldp/ldp_session.c +++ b/code/bngblaster/src/ldp/ldp_session.c @@ -170,7 +170,7 @@ ldp_session_keepalive_timeout_job(timer_s *timer) ldp_id_to_str(session->peer.lsr_id, session->peer.label_space_id)); if(!session->error_code) { - session->error_code = LDP_STATUS_KEEPALIVE_TIMER_EXPIRED; + session->error_code = LDP_STATUS_KEEPALIVE_TIMER_EXPIRED|LDP_STATUS_FATAL_ERROR; } ldp_session_close(session); } @@ -253,7 +253,7 @@ ldp_session_fsm(ldp_session_s *session, ldp_event_t event) ldp_session_state_change(session, LDP_OPENREC); } else { if(!session->error_code) { - session->error_code = LDP_STATUS_INTERNAL_ERROR; + session->error_code = LDP_STATUS_INTERNAL_ERROR|LDP_STATUS_FATAL_ERROR; } ldp_session_close(session); } @@ -536,7 +536,7 @@ ldp_session_close(ldp_session_s *session) timer_del(session->update_timer); if(!session->error_code) { - session->error_code = LDP_STATUS_SHUTDOWN; + session->error_code = LDP_STATUS_SHUTDOWN|LDP_STATUS_FATAL_ERROR; } if(session->state > LDP_CONNECT && session->state < LDP_CLOSING) { From 96e9fc6287f8a0a650c210f24a94489a861b14e4 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Tue, 3 Jan 2023 12:28:06 +0000 Subject: [PATCH 21/27] fix stream config merge Streams from main config (-C) and dedicated stream config (-T) are not properly merged. --- code/bngblaster/src/bbl_config.c | 94 ++++++++++++++------------------ 1 file changed, 42 insertions(+), 52 deletions(-) diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index df0d1a52..b431786e 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1706,6 +1706,46 @@ json_parse_stream(json_t *stream, bbl_stream_config_s *stream_config) return true; } +static bool +json_parse_config_streams(json_t *root) +{ + + json_t *section = NULL; + int i, size; + + bbl_stream_config_s *stream_config = g_ctx->config.stream_config; + + if(json_typeof(root) != JSON_OBJECT) { + fprintf(stderr, "JSON config error: Configuration root element must object\n"); + return false; + } + + section = json_object_get(root, "streams"); + if(json_is_array(section)) { + /* Get tail end of stream-config list. */ + if(stream_config) { + while(stream_config->next) { + stream_config = stream_config->next; + } + } + /* Config is provided as array (multiple streams) */ + size = json_array_size(section); + for(i = 0; i < size; i++) { + if(!stream_config) { + g_ctx->config.stream_config = calloc(1, sizeof(bbl_stream_config_s)); + stream_config = g_ctx->config.stream_config; + } else { + stream_config->next = calloc(1, sizeof(bbl_stream_config_s)); + stream_config = stream_config->next; + } + if(!json_parse_stream(json_array_get(section, i), stream_config)) { + return false; + } + } + } + return true; +} + static bool json_parse_config(json_t *root) { @@ -1716,7 +1756,6 @@ json_parse_config(json_t *root) double number; bbl_access_line_profile_s *access_line_profile = NULL; - bbl_stream_config_s *stream_config = NULL; bbl_l2tp_server_s *l2tp_server = NULL; bbl_lag_config_s *lag_config = NULL; @@ -2690,24 +2729,9 @@ json_parse_config(json_t *root) } /* Traffic Streams Configuration */ - section = json_object_get(root, "streams"); - if(json_is_array(section)) { - /* Config is provided as array (multiple streams) */ - size = json_array_size(section); - for(i = 0; i < size; i++) { - if(!stream_config) { - g_ctx->config.stream_config = calloc(1, sizeof(bbl_stream_config_s)); - stream_config = g_ctx->config.stream_config; - } else { - stream_config->next = calloc(1, sizeof(bbl_stream_config_s)); - stream_config = stream_config->next; - } - if(!json_parse_stream(json_array_get(section, i), stream_config)) { - return false; - } - } + if(!json_parse_config_streams(root)) { + return false; } - return true; } @@ -2738,40 +2762,6 @@ bbl_config_load_json(const char *filename) return result; } -static bool -json_parse_config_streams(json_t *root) -{ - - json_t *section = NULL; - int i, size; - - bbl_stream_config_s *stream_config = g_ctx->config.stream_config; - - if(json_typeof(root) != JSON_OBJECT) { - fprintf(stderr, "JSON config error: Configuration root element must object\n"); - return false; - } - - section = json_object_get(root, "streams"); - if(json_is_array(section)) { - /* Config is provided as array (multiple streams) */ - size = json_array_size(section); - for(i = 0; i < size; i++) { - if(!stream_config) { - g_ctx->config.stream_config = calloc(1, sizeof(bbl_stream_config_s)); - stream_config = g_ctx->config.stream_config; - } else { - stream_config->next = calloc(1, sizeof(bbl_stream_config_s)); - stream_config = stream_config->next; - } - if(!json_parse_stream(json_array_get(section, i), stream_config)) { - return false; - } - } - } - return true; -} - /** * bbl_config_streams_load_json * From 451114770ff694d57e1545ee7fc4fb20c7135360 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 5 Jan 2023 09:12:11 +0000 Subject: [PATCH 22/27] fix #138 lspgen option to disable SR --- code/lspgen/src/lspgen.c | 133 ++++++++++++++++++---------------- code/lspgen/src/lspgen_lsdb.h | 1 + 2 files changed, 71 insertions(+), 63 deletions(-) diff --git a/code/lspgen/src/lspgen.c b/code/lspgen/src/lspgen.c index 3555e3b7..71bbde62 100644 --- a/code/lspgen/src/lspgen.c +++ b/code/lspgen/src/lspgen.c @@ -54,6 +54,7 @@ static struct option long_options[] = { {"lsp-lifetime", required_argument, NULL, 'M'}, {"no-ipv4", no_argument, NULL, 'z'}, {"no-ipv6", no_argument, NULL, 'Z'}, + {"no-sr", no_argument, NULL, 'y'}, {"external-count", required_argument, NULL, 'e'}, {"graphviz-file", required_argument, NULL, 'g'}, {"help", no_argument, NULL, 'h'}, @@ -431,26 +432,28 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) ext_addr6 += ext_incr6; } - /* SR capability */ - lsdb_reset_attr_template(&attr_template); - addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)); - addr += node->node_index; - lspgen_store_addr(addr, attr_template.key.cap.router_id, sizeof(ipv4addr_t)); - attr_template.key.cap.srgb_base = ctx->srgb_base; - attr_template.key.cap.srgb_range = ctx->srgb_range; - if (!ctx->no_ipv4) { - attr_template.key.cap.mpls_ipv4_flag = true; /* mpls ipv4 */ + if (!ctx->no_sr) { + /* SR capability */ + lsdb_reset_attr_template(&attr_template); + addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)); + addr += node->node_index; + lspgen_store_addr(addr, attr_template.key.cap.router_id, sizeof(ipv4addr_t)); + attr_template.key.cap.srgb_base = ctx->srgb_base; + attr_template.key.cap.srgb_range = ctx->srgb_range; + if (!ctx->no_ipv4) { + attr_template.key.cap.mpls_ipv4_flag = true; /* mpls ipv4 */ + } + if (!ctx->no_ipv6) { + attr_template.key.cap.mpls_ipv6_flag = true; /* mpls ipv6 */ + } + attr_template.key.attr_type = ISIS_TLV_CAP; + attr_template.key.ordinal = 1; + lsdb_add_node_attr(node, &attr_template); } - if (!ctx->no_ipv6) { - attr_template.key.cap.mpls_ipv6_flag = true; /* mpls ipv6 */ - } - attr_template.key.attr_type = ISIS_TLV_CAP; - attr_template.key.ordinal = 1; - lsdb_add_node_attr(node, &attr_template); /* - * Walk all of our neighbors. - */ + * Walk all of our neighbors. + */ CIRCLEQ_FOREACH(link, &node->link_qhead, link_qnode) { /* Generate an IS reach for each link */ @@ -549,7 +552,7 @@ lspgen_compute_end_prefix4(struct ipv4_prefix_ *start_prefix, unsigned int num_p end_prefix = *start_prefix; if (!num_prefixes) { - return &end_prefix; + return &end_prefix; } prefix_inc = lspgen_get_prefix_inc(AF_INET, start_prefix->len); @@ -569,7 +572,7 @@ lspgen_compute_end_prefix6(struct ipv6_prefix_ *start_prefix, unsigned int num_p end_prefix = *start_prefix; if (!num_prefixes) { - return &end_prefix; + return &end_prefix; } prefix_inc = lspgen_get_prefix_inc(AF_INET6, start_prefix->len); @@ -605,36 +608,36 @@ lspgen_log_ctx(struct lsdb_ctx_ *ctx) ctx->authentication_key, val2key(isis_auth_names, ctx->authentication_type)); } if (!ctx->no_ipv4) { - end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_node_prefix, ctx->num_nodes); - LOG(NORMAL, " IPv4 Node Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv4_prefix(&ctx->ipv4_node_prefix), - format_ipv4_prefix(end_prefix4), ctx->num_nodes); + end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_node_prefix, ctx->num_nodes); + LOG(NORMAL, " IPv4 Node Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv4_prefix(&ctx->ipv4_node_prefix), + format_ipv4_prefix(end_prefix4), ctx->num_nodes); - end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_link_prefix, ctx->num_nodes*2); - LOG(NORMAL, " IPv4 Link Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv4_prefix(&ctx->ipv4_link_prefix), - format_ipv4_prefix(end_prefix4), ctx->num_nodes*2); + end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_link_prefix, ctx->num_nodes*2); + LOG(NORMAL, " IPv4 Link Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv4_prefix(&ctx->ipv4_link_prefix), + format_ipv4_prefix(end_prefix4), ctx->num_nodes*2); - end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_ext_prefix, ctx->num_ext); - LOG(NORMAL, " IPv4 External Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv4_prefix(&ctx->ipv4_ext_prefix), - format_ipv4_prefix(end_prefix4), ctx->num_ext); + end_prefix4 = lspgen_compute_end_prefix4(&ctx->ipv4_ext_prefix, ctx->num_ext); + LOG(NORMAL, " IPv4 External Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv4_prefix(&ctx->ipv4_ext_prefix), + format_ipv4_prefix(end_prefix4), ctx->num_ext); } if (!ctx->no_ipv6) { - end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_node_prefix, ctx->num_nodes); - LOG(NORMAL, " IPv6 Node Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv6_prefix(&ctx->ipv6_node_prefix), - format_ipv6_prefix(end_prefix6), ctx->num_nodes); + end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_node_prefix, ctx->num_nodes); + LOG(NORMAL, " IPv6 Node Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv6_prefix(&ctx->ipv6_node_prefix), + format_ipv6_prefix(end_prefix6), ctx->num_nodes); - end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_link_prefix, ctx->num_nodes*2); - LOG(NORMAL, " IPv6 Link Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv6_prefix(&ctx->ipv6_link_prefix), - format_ipv6_prefix(end_prefix6), ctx->num_nodes); + end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_link_prefix, ctx->num_nodes*2); + LOG(NORMAL, " IPv6 Link Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv6_prefix(&ctx->ipv6_link_prefix), + format_ipv6_prefix(end_prefix6), ctx->num_nodes); - end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_ext_prefix, ctx->num_ext); - LOG(NORMAL, " IPv6 External Base Prefix %s, End Prefix %s, %u prefixes\n", - format_ipv6_prefix(&ctx->ipv6_ext_prefix), - format_ipv6_prefix(end_prefix6), ctx->num_ext); + end_prefix6 = lspgen_compute_end_prefix6(&ctx->ipv6_ext_prefix, ctx->num_ext); + LOG(NORMAL, " IPv6 External Base Prefix %s, End Prefix %s, %u prefixes\n", + format_ipv6_prefix(&ctx->ipv6_ext_prefix), + format_ipv6_prefix(end_prefix6), ctx->num_ext); } LOG(NORMAL, " SRGB base %u, range %u\n", ctx->srgb_base, ctx->srgb_range); } @@ -648,16 +651,16 @@ lspgen_compute_srgb_range (struct lsdb_ctx_ *ctx) unsigned int range; if (ctx->no_ipv4 && ctx->no_ipv6) { - ctx->srgb_range = 0; - return; + ctx->srgb_range = 0; + return; } range = ctx->num_nodes * 2; if (ctx->no_ipv4) { - range = ctx->num_nodes; + range = ctx->num_nodes; } if (ctx->no_ipv6) { - range = ctx->num_nodes; + range = ctx->num_nodes; } ctx->srgb_range = range; @@ -756,7 +759,7 @@ main(int argc, char *argv[]) * Parse options. */ idx = 0; - while ((opt = getopt_long(argc, argv, "vha:c:C:e:f:g:l:L:m:M:n:K:N:p:q:Qr:s:S:t:T:V:w:x:X:zZ", + while ((opt = getopt_long(argc, argv, "vha:c:C:e:f:g:l:L:m:M:n:K:N:p:q:Qr:s:S:t:T:V:w:x:X:yzZ", long_options, &idx)) != -1) { switch (opt) { case 'v': @@ -790,6 +793,10 @@ main(int argc, char *argv[]) LOG(ERROR, "Set lsp-lifetime to min %us\n", ctx->lsp_lifetime); } break; + case 'y': + /* no-sr */ + ctx->no_sr = true; + break; case 'z': /* no-ipv4 */ ctx->no_ipv4 = true; @@ -812,7 +819,7 @@ main(int argc, char *argv[]) ctx->num_nodes = 5; LOG(ERROR, "Set node count to minimal %u\n", ctx->num_nodes); } - lspgen_compute_srgb_range(ctx); + lspgen_compute_srgb_range(ctx); break; case 'C': /* connector */ @@ -923,7 +930,7 @@ main(int argc, char *argv[]) } /* - * Bump the seqeunce numbers if there is a cache file. + * Bump the sequence numbers if there is a cache file. */ lspgen_read_seq_cache(ctx); @@ -986,16 +993,16 @@ main(int argc, char *argv[]) ctx->ctrl_io_buf.size = CTRL_SOCKET_BUFSIZE; ctx->ctrl_io_buf.data = malloc(ctx->ctrl_io_buf.size); if (!ctx->ctrl_io_buf.data) { - goto flush_and_close; + goto EXIT; } timer_add_periodic(&ctx->timer_root, &ctx->ctrl_socket_connect_timer, "connect", 1, 0, ctx, &lspgen_ctrl_connect_cb); - /* - * Wakup at least once a second doing nothing, - * such that we do not sleep while user tries to quit the timer loop. - */ + /* + * Wakeup at least once a second doing nothing, + * such that we do not sleep while user tries to quit the timer loop. + */ timer_add_periodic(&ctx->timer_root, &ctx->ctrl_socket_wakeup_timer, "wakeup", 1, 0, ctx, &lspgen_ctrl_wakeup_cb); @@ -1005,14 +1012,14 @@ main(int argc, char *argv[]) */ signal(SIGPIPE, SIG_IGN); - /* - * Keep running until Ctrl-C is hit. - */ - signal(SIGINT, lspgen_sig_handler); + /* + * Keep running until Ctrl-C is hit. + */ + signal(SIGINT, lspgen_sig_handler); - while (loop_running) { - timer_walk(&ctx->timer_root); - } + while (loop_running) { + timer_walk(&ctx->timer_root); + } } /* @@ -1023,7 +1030,7 @@ main(int argc, char *argv[]) /* * Flush and close all we have. */ - flush_and_close: +EXIT: lsdb_delete_ctx(ctx); return 0; } diff --git a/code/lspgen/src/lspgen_lsdb.h b/code/lspgen/src/lspgen_lsdb.h index 5e7f4d18..e42ff6b8 100644 --- a/code/lspgen/src/lspgen_lsdb.h +++ b/code/lspgen/src/lspgen_lsdb.h @@ -72,6 +72,7 @@ typedef struct lsdb_ctx_ struct lsdb_node_id_ connector[3]; uint32_t num_connector; uint32_t num_ext; /* number of external prefixes */ + bool no_sr; bool no_ipv4; bool no_ipv6; uint16_t lsp_lifetime; From 9702925824da055603a9a5206c0fed15d41d9874 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 5 Jan 2023 21:28:22 +0000 Subject: [PATCH 23/27] fix/extend ldpupdate --- code/ldpupdate | 103 +++++++++++++++++++++++++-------- docsrc/sources/routing/ldp.rst | 9 ++- 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/code/ldpupdate b/code/ldpupdate index 8125d864..9150bc94 100644 --- a/code/ldpupdate +++ b/code/ldpupdate @@ -9,7 +9,6 @@ SPDX-License-Identifier: BSD-3-Clause """ import argparse import ipaddress -import json import logging import struct import sys @@ -23,6 +22,35 @@ except: print("Failed to load scapy!") exit(1) +# ============================================================== +# PATCHES +# ============================================================== + +# Monkey patch scapy LDP FecTLVField + +def _monkey_i2m(self, pkt, x): + if not x: + return b"" + if isinstance(x, bytes): + return x + s = b"\x01\x00" + tmp_len = 0 + fec = b"" + for o in x: + fec += b"\x02\x00\x01" + # mask length + fec += struct.pack("!B", o[1]) + # Prefix + l = o[1]+7>>3 + p = inet_aton(o[0]) + fec += p[:l] + tmp_len += 4+l + s += struct.pack("!H", tmp_len) + s += fec + return s + +scapy.contrib.ldp.FecTLVField.i2m = _monkey_i2m + # ============================================================== # DEFINITIONS # ============================================================== @@ -77,8 +105,11 @@ def main(): parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-l', '--lsr-id', metavar='ADDRESS', type=ipaddress.ip_address, required=True, help='LSR identifier') parser.add_argument('-i', '--message-id-base', metavar='N', type=int, default=1000, help='message identifier base') - parser.add_argument('-p', '--prefix-base', metavar='PREFIX', type=ipaddress.ip_network, required=True, help='prefix base network') - parser.add_argument('-P', '--prefix-num', metavar='N', type=int, default=1, help='prefix count') + parser.add_argument('-w', '--withdraw', action="store_true", help='withdraw') + parser.add_argument('-a', '--address-base', metavar='ADDRESS', type=ipaddress.ip_address, help='address message base') + parser.add_argument('-A', '--address-num', metavar='N', type=int, default=0, help='address message count') + parser.add_argument('-p', '--prefix-base', metavar='PREFIX', type=ipaddress.ip_network, help='label mapping base prefix') + parser.add_argument('-P', '--prefix-num', metavar='N', type=int, default=0, help='label mapping prefix count') parser.add_argument('-m', '--label-base', metavar='LABEL', type=label_type, default=10000, help='label base') parser.add_argument('-M', '--label-num', metavar='N', type=int, default=1, help='label count') parser.add_argument('-f', '--file', type=str, default="out.ldp", help='output file') @@ -89,11 +120,6 @@ def main(): # init logging log = init_logging(args.log_level) - if args.prefix_base.version != 4: - log.error("prefix must be IPv4") - exit(1) - - log.info("init %s labeled IPv4 prefixes" % (args.prefix_num)) # Here we will store packets for optional PCAP output pcap_packets = [] @@ -101,26 +127,43 @@ def main(): if args.pcap: pcap_packets.append(Ether()/IP()/TCP(sport=len(pcap_packets)+10000, dport=646, seq=1, flags='PA')/message) + addresses = [] + if args.address_base and args.address_num > 0: + log.info("init %s addresses" % (args.address_num)) + + address = args.address_base + for _ in range(args.address_num): + addresses.append(address) + address += 1 + prefixes = [] + if args.prefix_base and args.prefix_num > 0: + if args.prefix_base.version != 4: + log.error("prefix must be IPv4") + exit(1) + log.info("init %s labeled IPv4 prefixes" % (args.prefix_num)) - label_index = 0 - prefix = args.prefix_base - label = args.label_base - for _ in range(args.prefix_num): - log.debug("add prefix %s via label %s" % (prefix, label)) - prefixes.append((prefix, label)) + prefix = args.prefix_base + label_index = 0 + label = args.label_base + for _ in range(args.prefix_num): + log.debug("add prefix %s via label %s" % (prefix, label)) + prefixes.append((prefix, label)) - label_index += 1 - if label_index < args.label_num: - label = args.label_base + label_index - if label > MPLS_LABEL_MAX: + label_index += 1 + if label_index < args.label_num: + label = args.label_base + label_index + if label > MPLS_LABEL_MAX: + label_index = 0 + label = args.label_base + else: label_index = 0 label = args.label_base - else: - label_index = 0 - label = args.label_base - prefix = ipaddress.ip_network("%s/%s" % (prefix.broadcast_address+1, prefix.prefixlen)) + prefix = ipaddress.ip_network("%s/%s" % (prefix.broadcast_address+1, prefix.prefixlen)) + + if len(addresses) + len(prefixes) == 0: + exit(0) if args.append: log.info("open file %s (append)" % args.file) @@ -133,8 +176,22 @@ def main(): mid = args.message_id_base + for address in addresses: + if args.withdraw: + pdu = LDP(id=args.lsr_id)/LDPAddressWM(id=mid, address=[str(address)]) + else: + pdu = LDP(id=args.lsr_id)/LDPAddress(id=mid, address=[str(address)]) + mid+=1 + + pdu_bin = bytearray(pdu.build()) + pcap(pdu) + f.write(pdu_bin) + for prefix, label in prefixes: - pdu = LDP(id=args.lsr_id)/LDPLabelMM(id=mid, fec=[(str(prefix.network_address),int(prefix.prefixlen))],label=label) + if args.withdraw: + pdu = LDP(id=args.lsr_id)/LDPLabelWM(id=mid, fec=[(str(prefix.network_address),int(prefix.prefixlen))],label=label) + else: + pdu = LDP(id=args.lsr_id)/LDPLabelMM(id=mid, fec=[(str(prefix.network_address),int(prefix.prefixlen))],label=label) mid+=1 pdu_bin = bytearray(pdu.build()) diff --git a/docsrc/sources/routing/ldp.rst b/docsrc/sources/routing/ldp.rst index adfe927e..e4711636 100644 --- a/docsrc/sources/routing/ldp.rst +++ b/docsrc/sources/routing/ldp.rst @@ -262,9 +262,14 @@ streams for use with the BNG Blaster. LSR identifier -i N, --message-id-base N message identifier base + -w, --withdraw withdraw + -a ADDRESS, --address-base ADDRESS + address message base + -A N, --address-num N + address message count -p PREFIX, --prefix-base PREFIX - prefix base network - -P N, --prefix-num N prefix count + label mapping base prefix + -P N, --prefix-num N label mapping prefix count -m LABEL, --label-base LABEL label base -M N, --label-num N label count From bc7a2cb332ff2a8a175032218b49585b8e06e3a6 Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Thu, 5 Jan 2023 22:13:01 +0000 Subject: [PATCH 24/27] fix LDP crtl command and docs --- code/bngblaster/src/ldp/ldp_ctrl.c | 6 +++--- docsrc/sources/api/ldp.rst | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/code/bngblaster/src/ldp/ldp_ctrl.c b/code/bngblaster/src/ldp/ldp_ctrl.c index 7894d8d3..6c3e32d3 100644 --- a/code/bngblaster/src/ldp/ldp_ctrl.c +++ b/code/bngblaster/src/ldp/ldp_ctrl.c @@ -427,7 +427,7 @@ ldb_ctrl_database_entries(ldp_instance_s *instance) while(next) { entry = *hb_itor_datum(itor); json_entry = json_pack("{ss ss* si ss*}", - "direction", "ipv4", + "afi", "ipv4", "prefix", format_ipv4_prefix(&entry->prefix.ipv4), "label", entry->label, "source-identifier", ldp_id_to_str(entry->source->peer.lsr_id, entry->source->peer.label_space_id)); @@ -446,7 +446,7 @@ ldb_ctrl_database_entries(ldp_instance_s *instance) while(next) { entry = *hb_itor_datum(itor); json_entry = json_pack("{ss ss* si ss*}", - "direction", "ipv6", + "afi", "ipv6", "prefix", format_ipv6_prefix(&entry->prefix.ipv6), "label", entry->label, "source-identifier", ldp_id_to_str(entry->source->peer.lsr_id, entry->source->peer.label_space_id)); @@ -472,7 +472,7 @@ ldb_ctrl_database(int fd, uint32_t session_id __attribute__((unused)), json_t *a int instance_id = 0; /* Unpack further arguments */ - if(json_unpack(arguments, "{s:i}", "instance", &instance_id) != 0) { + if(json_unpack(arguments, "{s:i}", "ldp-instance-id", &instance_id) != 0) { return bbl_ctrl_status(fd, "error", 400, "LDP instance missing"); } diff --git a/docsrc/sources/api/ldp.rst b/docsrc/sources/api/ldp.rst index c3e5236d..9ddef527 100644 --- a/docsrc/sources/api/ldp.rst +++ b/docsrc/sources/api/ldp.rst @@ -5,10 +5,18 @@ - Description - Mandatory Arguments - Optional Arguments + * - `ldp-adjacencies` + - Display all LDP adjacencies + - + - `ldp-instance-id` * - `ldp-sessions` - Display all matching LDP sessions - - `ldp-instance-id`, `local-ipv4-address`, `peer-ipv4-address` + * - `ldp-database` + - Display LDP database + - `ldp-instance-id` + - * - `ldp-disconnect` - Disconnect all matching LDP sessions - From c80e5011bdc794ab3286319028d7c13c7c4fd04c Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 11 Jan 2023 22:10:09 +0000 Subject: [PATCH 25/27] IPoE reconnect support Add support to reconnect IPoE sessions via control socket commands. --- code/bngblaster/src/bbl_config.c | 6 +++++ code/bngblaster/src/bbl_ctx.h | 1 + code/bngblaster/src/bbl_session.c | 27 ++++++++++------------- docsrc/sources/configuration/sessions.rst | 3 +++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/code/bngblaster/src/bbl_config.c b/code/bngblaster/src/bbl_config.c index b431786e..cb63e57c 100644 --- a/code/bngblaster/src/bbl_config.c +++ b/code/bngblaster/src/bbl_config.c @@ -1804,6 +1804,10 @@ json_parse_config(json_t *root) if(json_is_boolean(value)) { g_ctx->config.sessions_autostart = json_boolean_value(value); } + value = json_object_get(section, "reconnect"); + if(json_is_boolean(value)) { + g_ctx->config.sessions_reconnect = json_boolean_value(value); + } value = json_object_get(section, "monkey-autostart"); if(json_is_boolean(value)) { g_ctx->config.monkey_autostart = json_boolean_value(value); @@ -1865,6 +1869,8 @@ json_parse_config(json_t *root) value = json_object_get(section, "reconnect"); if(json_is_boolean(value)) { g_ctx->config.pppoe_reconnect = json_boolean_value(value); + } else { + g_ctx->config.pppoe_reconnect = g_ctx->config.sessions_reconnect; } value = json_object_get(section, "discovery-timeout"); if(json_is_number(value)) { diff --git a/code/bngblaster/src/bbl_ctx.h b/code/bngblaster/src/bbl_ctx.h index a9d16ca8..f84e8a1e 100644 --- a/code/bngblaster/src/bbl_ctx.h +++ b/code/bngblaster/src/bbl_ctx.h @@ -202,6 +202,7 @@ typedef struct bbl_ctx_ uint16_t sessions_start_rate; uint16_t sessions_stop_rate; uint16_t sessions_start_delay; + bool sessions_reconnect; bool sessions_autostart; bool monkey_autostart; bool iterate_outer_vlan; diff --git a/code/bngblaster/src/bbl_session.c b/code/bngblaster/src/bbl_session.c index 9d087524..b2f27ad5 100644 --- a/code/bngblaster/src/bbl_session.c +++ b/code/bngblaster/src/bbl_session.c @@ -322,6 +322,7 @@ bbl_session_reset(bbl_session_s *session) { session->dns2 = 0; session->ipv6_prefix.len = 0; session->delegated_ipv6_prefix.len = 0; + session->arp_resolved = false; session->icmpv6_ra_received = false; if(session->dhcpv6_state > BBL_DHCP_DISABLED) { session->dhcpv6_state = BBL_DHCP_INIT; @@ -503,24 +504,20 @@ bbl_session_update_state(bbl_session_s *session, session_state_t state) if(g_teardown) { g_ctx->sessions_terminated++; } else { - if(session->access_type == ACCESS_TYPE_PPPOE) { - if(g_ctx->config.pppoe_reconnect) { - /* Increment flap counter */ - session->stats.flapped++; - g_ctx->sessions_flapped++; - if(session->reconnect_delay) { - timer_add(&g_ctx->timer_root, &session->timer_reconnect, "RECONNECT", - session->reconnect_delay, 0, session, &bbl_session_reconnect_job); - } else { - state = BBL_IDLE; - bbl_session_reset(session); - CIRCLEQ_INSERT_TAIL(&g_ctx->sessions_idle_qhead, session, session_idle_qnode); - } + if((session->access_type == ACCESS_TYPE_PPPOE && g_ctx->config.pppoe_reconnect) || + (session->access_type == ACCESS_TYPE_IPOE && g_ctx->config.sessions_reconnect)) { + /* Increment flap counter */ + session->stats.flapped++; + g_ctx->sessions_flapped++; + if(session->reconnect_delay) { + timer_add(&g_ctx->timer_root, &session->timer_reconnect, "RECONNECT", + session->reconnect_delay, 0, session, &bbl_session_reconnect_job); } else { - g_ctx->sessions_terminated++; + state = BBL_IDLE; + bbl_session_reset(session); + CIRCLEQ_INSERT_TAIL(&g_ctx->sessions_idle_qhead, session, session_idle_qnode); } } else { - /* IPoE */ g_ctx->sessions_terminated++; } } diff --git a/docsrc/sources/configuration/sessions.rst b/docsrc/sources/configuration/sessions.rst index fb5397a6..feb8f97f 100644 --- a/docsrc/sources/configuration/sessions.rst +++ b/docsrc/sources/configuration/sessions.rst @@ -28,6 +28,9 @@ * - `start-delay` - Wait N seconds after all interfaces are resolved before starting sessions - 0 + * - `reconnect` + - Automatically reconnect sessions (PPPoE and IPoE) if terminated + - false * - `autostart` - Start sessions automatically - true From 90b6534a5be95c5e64603039dee2c87a3a2112cf Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Wed, 11 Jan 2023 22:28:42 +0000 Subject: [PATCH 26/27] add support for IPoE monkey testing --- code/bngblaster/src/bbl_session.c | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/code/bngblaster/src/bbl_session.c b/code/bngblaster/src/bbl_session.c index b2f27ad5..f872f851 100644 --- a/code/bngblaster/src/bbl_session.c +++ b/code/bngblaster/src/bbl_session.c @@ -10,6 +10,7 @@ #include "bbl_session.h" #include "bbl_stream.h" #include "bbl_stats.h" +#include "bbl_dhcp.h" #include "bbl_dhcpv6.h" extern volatile bool g_teardown; @@ -200,6 +201,50 @@ bbl_session_monkey_pppoe(bbl_session_s *session) { } } +static void +bbl_session_monkey_ipoe(bbl_session_s *session) { + switch(rand() % 256) { + case 10: + /* Clear session. */ + bbl_session_clear(session); + break; + case 20: + /* Release DHCP */ + if(session->dhcp_state != BBL_DHCP_RELEASE) { + session->dhcp_state = BBL_DHCP_RELEASE; + session->dhcp_xid = rand(); + session->dhcp_request_timestamp.tv_sec = 0; + session->dhcp_request_timestamp.tv_nsec = 0; + session->dhcp_retry = 0; + session->send_requests |= BBL_SEND_DHCP_REQUEST; + bbl_session_tx_qnode_insert(session); + } + break; + case 30: + /* Release DHCPv6 */ + if(session->dhcpv6_state != BBL_DHCP_RELEASE) { + session->dhcpv6_state = BBL_DHCP_RELEASE; + session->dhcpv6_xid = rand() & 0xffffff; + session->dhcpv6_request_timestamp.tv_sec = 0; + session->dhcpv6_request_timestamp.tv_nsec = 0; + session->dhcpv6_retry = 0; + session->send_requests |= BBL_SEND_DHCPV6_REQUEST; + bbl_session_tx_qnode_insert(session); + } + break; + case 40: + /* Restart DHCPv4 */ + bbl_dhcp_restart(session); + break; + case 50: + /* Restart DHCPv6 */ + bbl_dhcpv6_restart(session); + break; + default: + break; + } +} + void bbl_session_monkey_job(timer_s *timer) { bbl_session_s *session = timer->data; @@ -218,6 +263,8 @@ bbl_session_monkey_job(timer_s *timer) { if(session->access_type == ACCESS_TYPE_PPPOE) { bbl_session_monkey_pppoe(session); + } else if(session->access_type == ACCESS_TYPE_IPOE) { + bbl_session_monkey_ipoe(session); } } From 4fd51e2bd2d9b297da9105d0713e7a93b15c407e Mon Sep 17 00:00:00 2001 From: Christian Giese Date: Fri, 13 Jan 2023 15:48:53 +0000 Subject: [PATCH 27/27] fix #138 lspgen option to disable SR Remove prefix-sid if no-sr is set! --- code/lspgen/src/lspgen.c | 24 +++++++----- code/lspgen/src/lspgen_packet.c | 65 ++++++++++++++++----------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/code/lspgen/src/lspgen.c b/code/lspgen/src/lspgen.c index 71bbde62..cf3ef37a 100644 --- a/code/lspgen/src/lspgen.c +++ b/code/lspgen/src/lspgen.c @@ -370,7 +370,7 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) lsdb_add_node_attr(node, &attr_template); } - /* ipv4 loopback address */ + /* IPv4 loopback address */ lsdb_reset_attr_template(&attr_template); addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_node_prefix.address, sizeof(ipv4addr_t)); addr += node->node_index; @@ -379,18 +379,20 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) attr_template.key.attr_type = ISIS_TLV_IPV4_ADDR; lsdb_add_node_attr(node, &attr_template); - /* ipv4 loopback prefix */ + /* IPv4 loopback prefix */ lsdb_reset_attr_template(&attr_template); lspgen_store_addr(addr, (uint8_t*)&attr_template.key.prefix.ipv4_prefix.address, sizeof(ipv4addr_t)); attr_template.key.prefix.ipv4_prefix.len = ctx->ipv4_node_prefix.len; - attr_template.key.prefix.sid = node->node_index; - attr_template.key.prefix.adv_sid = true; + if (!ctx->no_sr) { + attr_template.key.prefix.sid = node->node_index; + attr_template.key.prefix.adv_sid = true; + } attr_template.key.prefix.node_flag = true; attr_template.key.ordinal = 1; attr_template.key.attr_type = ISIS_TLV_EXTD_IPV4_REACH; lsdb_add_node_attr(node, &attr_template); - /* ipv6 loopback address */ + /* IPv6 loopback address */ lsdb_reset_attr_template(&attr_template); addr = lspgen_load_addr(ctx->ipv6_node_prefix.address, IPV6_ADDR_LEN); addr += node->node_index; @@ -399,12 +401,14 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) attr_template.key.attr_type = ISIS_TLV_IPV6_ADDR; lsdb_add_node_attr(node, &attr_template); - /* ipv6 loopback prefix */ + /* IPv6 loopback prefix */ lsdb_reset_attr_template(&attr_template); lspgen_store_addr(addr, attr_template.key.prefix.ipv6_prefix.address, IPV6_ADDR_LEN); attr_template.key.prefix.ipv6_prefix.len = ctx->ipv6_node_prefix.len; - attr_template.key.prefix.sid = ctx->srgb_range/2 + node->node_index; - attr_template.key.prefix.adv_sid = true; + if (!ctx->no_sr) { + attr_template.key.prefix.sid = ctx->srgb_range/2 + node->node_index; + attr_template.key.prefix.adv_sid = true; + } attr_template.key.prefix.node_flag = true; attr_template.key.ordinal = 1; attr_template.key.attr_type = ISIS_TLV_EXTD_IPV6_REACH; @@ -463,7 +467,7 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) attr_template.key.link.metric = link->link_metric; lsdb_add_node_attr(node, &attr_template); - /* Generate an ipv4 prefix for each link */ + /* Generate an IPv4 prefix for each link */ lsdb_reset_attr_template(&attr_template); addr = lspgen_load_addr((uint8_t*)&ctx->ipv4_link_prefix.address, sizeof(ipv4addr_t)); inc = lspgen_get_prefix_inc(AF_INET, ctx->ipv4_link_prefix.len); @@ -474,7 +478,7 @@ lspgen_gen_attr(struct lsdb_ctx_ *ctx) attr_template.key.attr_type = ISIS_TLV_EXTD_IPV4_REACH; lsdb_add_node_attr(node, &attr_template); - /* Generate an ipv6 prefix for each link */ + /* Generate an IPv6 prefix for each link */ lsdb_reset_attr_template(&attr_template); addr = lspgen_load_addr(ctx->ipv6_link_prefix.address, IPV6_ADDR_LEN); inc = lspgen_get_prefix_inc(AF_INET6, ctx->ipv6_link_prefix.len); diff --git a/code/lspgen/src/lspgen_packet.c b/code/lspgen/src/lspgen_packet.c index a06574b7..c0ef8db8 100644 --- a/code/lspgen/src/lspgen_packet.c +++ b/code/lspgen/src/lspgen_packet.c @@ -346,16 +346,16 @@ lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf) break; case ISIS_TLV_IS_REACH: push_be_uint(buf, 1, 0); /* virtual */ - metric = attr->key.link.metric; - if (metric > 63) { - metric = 63; /* limit metric to 6 bits */ - } + metric = attr->key.link.metric; + if (metric > 63) { + metric = 63; /* limit metric to 6 bits */ + } push_be_uint(buf, 1, metric); /* default metric */ push_be_uint(buf, 1, 0x80); /* delay metric */ push_be_uint(buf, 1, 0x80); /* expense metric */ push_be_uint(buf, 1, 0x80); /* error metric */ push_data(buf, attr->key.link.remote_node_id, 7); - break; + break; case ISIS_TLV_EXTD_IS_REACH: push_data(buf, attr->key.link.remote_node_id, 7); push_be_uint(buf, 3, attr->key.link.metric); /* Metric */ @@ -373,11 +373,11 @@ lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf) break; case ISIS_TLV_INT_IPV4_REACH: /* fall through */ case ISIS_TLV_EXT_IPV4_REACH: - metric = attr->key.prefix.metric; - if (metric > 63) { - metric = 63; /* limit metric to 6 bits */ - } - flags = metric; + metric = attr->key.prefix.metric; + if (metric > 63) { + metric = 63; /* limit metric to 6 bits */ + } + flags = metric; if (attr->key.prefix.updown_flag) { flags |= 0x80; } @@ -386,11 +386,11 @@ lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf) push_be_uint(buf, 1, 0x80); /* expense metric */ push_be_uint(buf, 1, 0x80); /* error metric */ push_data(buf, (uint8_t*)&attr->key.prefix.ipv4_prefix.address, 4); - mask = 0xffffffff; - /* convert prefix length to mask */ - mask &= ~((1 << ((32 - attr->key.prefix.ipv4_prefix.len)))-1); - push_be_uint(buf, 4, mask); - break; + mask = 0xffffffff; + /* convert prefix length to mask */ + mask &= ~((1 << ((32 - attr->key.prefix.ipv4_prefix.len)))-1); + push_be_uint(buf, 4, mask); + break; case ISIS_TLV_EXTD_IPV4_REACH: push_be_uint(buf, 4, attr->key.prefix.metric); /* Metric */ flags = attr->key.prefix.ipv4_prefix.len & 0x3f; @@ -398,12 +398,11 @@ lspgen_serialize_attr(lsdb_attr_t *attr, io_buffer_t *buf) flags |= 0x80; } if (subtlv_present) { - flags |= 0x40; /* subTLVs present */ + flags |= 0x40; /* Sub-TLVs present */ } push_be_uint(buf, 1, flags); /* Flags */ attr_len = (attr->key.prefix.ipv4_prefix.len+7)/8; push_data(buf, (uint8_t*)&attr->key.prefix.ipv4_prefix.address, attr_len); - /* Generate subTLVs */ if (subtlv_present) { lspgen_serialize_prefix_subtlv(attr, buf, true); @@ -549,7 +548,7 @@ lspgen_add_packet(lsdb_ctx_t *ctx, lsdb_node_t *node, uint32_t id) */ CIRCLEQ_INSERT_TAIL(&ctx->packet_change_qhead, packet, packet_change_qnode); packet->on_change_list = true; - ctx->ctrl_stats.packets_queued++; + ctx->ctrl_stats.packets_queued++; /* * Parent @@ -589,10 +588,10 @@ lspgen_refresh_cb (timer_s *timer) */ if (ctx->ctrl_socket_path) { - if (!ctx->ctrl_socket_connect_timer) { - timer_add_periodic(&ctx->timer_root, &ctx->ctrl_socket_connect_timer, - "connect", 1, 0, ctx, &lspgen_ctrl_connect_cb); - } + if (!ctx->ctrl_socket_connect_timer) { + timer_add_periodic(&ctx->timer_root, &ctx->ctrl_socket_connect_timer, + "connect", 1, 0, ctx, &lspgen_ctrl_connect_cb); + } } } @@ -607,7 +606,7 @@ lspgen_refresh_interval (lsdb_ctx_t *ctx) refresh = ctx->lsp_lifetime - 300; if (refresh < 60) { - refresh = 60; + refresh = 60; } return refresh; @@ -667,8 +666,8 @@ lspgen_gen_packet_node(lsdb_node_t *node) * Start refresh timer. */ if (ctx->ctrl_socket_path) { - timer_add_periodic(&ctx->timer_root, &node->refresh_timer, "refresh", - lspgen_refresh_interval(ctx), 0, node, &lspgen_refresh_cb); + timer_add_periodic(&ctx->timer_root, &node->refresh_timer, "refresh", + lspgen_refresh_interval(ctx), 0, node, &lspgen_refresh_cb); } do { @@ -712,7 +711,7 @@ lspgen_gen_packet_node(lsdb_node_t *node) */ if ((last_attr != attr->key.attr_type) || (lspgen_calculate_tlv_space(&packet->buf, tlv_start_idx) < attr->size) || - attr->key.start_tlv) { + attr->key.start_tlv) { tlv_start_idx = packet->buf.idx; push_be_uint(&packet->buf, 1, attr->key.attr_type); /* Type */ push_be_uint(&packet->buf, 1, 0); /* Length */ @@ -758,14 +757,14 @@ lspgen_gen_packet(lsdb_ctx_t *ctx) do { node = *dict_itor_datum(itor); - /* - * Init per-packet tree for this node. - */ - if (!node->packet_dict) { - node->packet_dict = hb_dict_new((dict_compare_func)lsdb_compare_packet); - } + /* + * Init per-packet tree for this node. + */ + if (!node->packet_dict) { + node->packet_dict = hb_dict_new((dict_compare_func)lsdb_compare_packet); + } - /* + /* * Generate the link-state packets for this node. */ lspgen_gen_packet_node(node);