mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 18:21:54 +00:00
71299a594d
Add support for MRT Table Dump draft-petrie-grow-mrt-add-paths
276 lines
6.8 KiB
C
276 lines
6.8 KiB
C
/*
|
|
* BIRD -- Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format
|
|
*
|
|
* (c) 2015 CZ.NIC z.s.p.o.
|
|
*
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
*/
|
|
|
|
#undef LOCAL_DEBUG
|
|
|
|
#include "nest/mrtdump.h"
|
|
#include "nest/route.h"
|
|
|
|
/*
|
|
* MRTDump: Table Dump: Base
|
|
*/
|
|
|
|
static void
|
|
mrt_buffer_reset(struct mrt_buffer *buf)
|
|
{
|
|
buf->msg_capacity = MRT_BUFFER_DEFAULT_CAPACITY;
|
|
buf->msg_length = MRT_HDR_LENGTH; /* Reserved for the main MRT header */
|
|
}
|
|
|
|
void
|
|
mrt_buffer_alloc(struct mrt_buffer *buf)
|
|
{
|
|
mrt_buffer_reset(buf);
|
|
buf->msg = mb_allocz(&root_pool, buf->msg_capacity);
|
|
}
|
|
|
|
void
|
|
mrt_buffer_free(struct mrt_buffer *buf)
|
|
{
|
|
if (buf->msg != NULL)
|
|
{
|
|
mb_free(buf->msg);
|
|
buf->msg = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mrt_buffer_enlarge(struct mrt_buffer *buf, size_t min_required_capacity)
|
|
{
|
|
if (min_required_capacity > buf->msg_capacity)
|
|
{
|
|
buf->msg_capacity *= 2;
|
|
if (min_required_capacity > buf->msg_capacity)
|
|
buf->msg_capacity = min_required_capacity;
|
|
buf->msg = mb_realloc(buf->msg, buf->msg_capacity);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return pointer to the actual position in the msg buffer
|
|
*/
|
|
static byte *
|
|
mrt_buffer_get_cursor(struct mrt_buffer *buf)
|
|
{
|
|
return &buf->msg[buf->msg_length];
|
|
}
|
|
|
|
static void
|
|
mrt_buffer_write_show_debug(struct mrt_buffer *buf, size_t data_size)
|
|
{
|
|
#if defined(LOCAL_DEBUG) || defined(GLOBAL_DEBUG)
|
|
byte *data = mrt_buffer_get_cursor(buf) - data_size;
|
|
#endif
|
|
DBG("(%d) ", data_size);
|
|
u32 i;
|
|
for (i = 0; i < data_size; i++)
|
|
DBG("%02X ", data[i]);
|
|
DBG("| ");
|
|
}
|
|
|
|
static void
|
|
mrt_buffer_put_raw(struct mrt_buffer *buf, const void *data, size_t data_size)
|
|
{
|
|
if (data_size == 0)
|
|
return;
|
|
|
|
size_t required_size = data_size + buf->msg_length;
|
|
mrt_buffer_enlarge(buf, required_size);
|
|
|
|
memcpy(mrt_buffer_get_cursor(buf), data, data_size);
|
|
buf->msg_length += data_size;
|
|
|
|
mrt_buffer_write_show_debug(buf, data_size);
|
|
}
|
|
|
|
static void
|
|
mrt_buffer_put_ipa(struct mrt_buffer *buf, ip_addr addr, size_t write_size)
|
|
{
|
|
ip_addr addr_network_formatted = ipa_hton(addr);
|
|
mrt_buffer_put_raw(buf, &addr_network_formatted, write_size);
|
|
}
|
|
|
|
/*
|
|
* The data will be transformed (put_u16(), put_u32(), ...) to the network format before writing
|
|
*/
|
|
static void
|
|
mrt_buffer_put_var(struct mrt_buffer *buf, const void *data, size_t data_size)
|
|
{
|
|
if (data_size == 0)
|
|
return;
|
|
|
|
byte *actual_position;
|
|
|
|
size_t required_size = data_size + buf->msg_length;
|
|
mrt_buffer_enlarge(buf, required_size);
|
|
|
|
switch (data_size)
|
|
{
|
|
case 8:
|
|
put_u64(mrt_buffer_get_cursor(buf), *(u64*)data);
|
|
break;
|
|
case 4:
|
|
put_u32(mrt_buffer_get_cursor(buf), *(u32*)data);
|
|
break;
|
|
case 2:
|
|
put_u16(mrt_buffer_get_cursor(buf), *(u16*)data);
|
|
break;
|
|
case 1:
|
|
actual_position = mrt_buffer_get_cursor(buf);
|
|
*actual_position = *(byte*)data;
|
|
break;
|
|
default:
|
|
log(L_WARN "Unexpected size %zu byte(s) of data. Allowed are 1, 2, 4 or 8 bytes.", data_size);
|
|
}
|
|
|
|
buf->msg_length += data_size;
|
|
mrt_buffer_write_show_debug(buf, data_size);
|
|
}
|
|
#define mrt_buffer_put_var_autosize(msg, data) mrt_buffer_put_var(msg, &data, sizeof(data))
|
|
|
|
/*
|
|
* MRTDump: Table Dump: Peer Index Table
|
|
*/
|
|
|
|
void
|
|
mrt_peer_index_table_header(struct mrt_peer_index_table *state, u32 collector_bgp_id, const char *name)
|
|
{
|
|
struct mrt_buffer *buf = &state->msg;
|
|
mrt_buffer_alloc(buf);
|
|
|
|
state->peer_count = 0;
|
|
u16 name_length = 0;
|
|
if (name != NULL)
|
|
name_length = strlen(name);
|
|
|
|
mrt_buffer_put_var_autosize(buf, collector_bgp_id);
|
|
mrt_buffer_put_var_autosize(buf, name_length);
|
|
mrt_buffer_put_raw(buf, name, name_length);
|
|
state->peer_count_offset = state->msg.msg_length;
|
|
mrt_buffer_put_var(buf, &state->peer_count, sizeof(u16));
|
|
DBG("\n");
|
|
}
|
|
|
|
static void
|
|
mrt_peer_index_table_inc_peer_count(struct mrt_peer_index_table *state)
|
|
{
|
|
state->peer_count++;
|
|
byte *peer_count = &state->msg.msg[state->peer_count_offset];
|
|
put_u16(peer_count, state->peer_count);
|
|
}
|
|
|
|
void
|
|
mrt_peer_index_table_add_peer(struct mrt_peer_index_table *state, u32 peer_bgp_id, u32 peer_as, ip_addr peer_ip_addr)
|
|
{
|
|
struct mrt_buffer *msg = &state->msg;
|
|
|
|
u8 peer_type = MRT_PEER_TYPE_32BIT_ASN;
|
|
#ifdef IPV6
|
|
peer_type |= MRT_PEER_TYPE_IPV6;
|
|
#endif
|
|
|
|
mrt_buffer_put_var_autosize(msg, peer_type);
|
|
mrt_buffer_put_var_autosize(msg, peer_bgp_id);
|
|
mrt_buffer_put_ipa(msg, peer_ip_addr, sizeof(ip_addr));
|
|
mrt_buffer_put_var_autosize(msg, peer_as);
|
|
|
|
mrt_peer_index_table_inc_peer_count(state);
|
|
DBG("\n");
|
|
}
|
|
|
|
void
|
|
mrt_peer_index_table_dump(struct mrt_peer_index_table *state, int file_descriptor)
|
|
{
|
|
byte *msg = state->msg.msg;
|
|
u32 msg_length = state->msg.msg_length;
|
|
|
|
mrt_dump_message(file_descriptor, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE, msg, msg_length);
|
|
}
|
|
|
|
void
|
|
bgp_mrt_peer_index_table_free(struct mrt_peer_index_table *state)
|
|
{
|
|
mrt_buffer_free(&state->msg);
|
|
}
|
|
|
|
/*
|
|
* MRTDump: Table Dump: RIB Table
|
|
*/
|
|
|
|
static void
|
|
mrt_rib_table_reset(struct mrt_rib_table *state)
|
|
{
|
|
state->entry_count = 0;
|
|
state->entry_count_offset = 0;
|
|
state->subtype = MRT_RIB_IPV4_UNICAST;
|
|
mrt_buffer_reset(&state->msg);
|
|
}
|
|
|
|
void
|
|
mrt_rib_table_alloc(struct mrt_rib_table *state)
|
|
{
|
|
mrt_buffer_alloc(&state->msg);
|
|
mrt_rib_table_reset(state);
|
|
}
|
|
|
|
void
|
|
mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix, uint is_addpath)
|
|
{
|
|
mrt_rib_table_reset(state);
|
|
|
|
#ifdef IPV6
|
|
state->subtype = (is_addpath == MRT_RIB_ADDPATH) ? MRT_RIB_IPV6_UNICAST_ADDPATH : MRT_RIB_IPV6_UNICAST;
|
|
#else
|
|
state->subtype = (is_addpath == MRT_RIB_ADDPATH) ? MRT_RIB_IPV4_UNICAST_ADDPATH : MRT_RIB_IPV4_UNICAST;
|
|
#endif
|
|
|
|
struct mrt_buffer *msg = &state->msg;
|
|
mrt_buffer_put_var_autosize(msg, sequence_number);
|
|
mrt_buffer_put_var_autosize(msg, prefix_length);
|
|
|
|
#define CEILING(a, b) (((a)+(b)-1) / (b))
|
|
u32 prefix_bytes = CEILING(prefix_length, 8);
|
|
mrt_buffer_put_ipa(msg, prefix, prefix_bytes);
|
|
|
|
state->entry_count_offset = msg->msg_length;
|
|
mrt_buffer_put_var_autosize(msg, state->entry_count);
|
|
DBG("\n");
|
|
}
|
|
|
|
static void
|
|
mrt_rib_table_inc_entry_count(struct mrt_rib_table *state)
|
|
{
|
|
state->entry_count++;
|
|
byte *entry_count = &state->msg.msg[state->entry_count_offset];
|
|
put_u16(entry_count, state->entry_count);
|
|
}
|
|
|
|
void
|
|
mrt_rib_table_add_entry(struct mrt_rib_table *state, const struct mrt_rib_entry *entry)
|
|
{
|
|
struct mrt_buffer *msg = &state->msg;
|
|
|
|
mrt_buffer_put_var_autosize(msg, entry->peer_index);
|
|
mrt_buffer_put_var_autosize(msg, entry->originated_time);
|
|
|
|
switch (state->subtype)
|
|
{
|
|
case MRT_RIB_IPV4_UNICAST_ADDPATH:
|
|
case MRT_RIB_IPV6_UNICAST_ADDPATH:
|
|
case MRT_RIB_IPV4_MULTICAST_ADDPATH:
|
|
case MRT_RIB_IPV6_MULTICAST_ADDPATH:
|
|
mrt_buffer_put_var_autosize(msg, entry->path_id);
|
|
}
|
|
|
|
mrt_buffer_put_var_autosize(msg, entry->attributes_length);
|
|
mrt_buffer_put_raw(msg, entry->attributes, entry->attributes_length);
|
|
|
|
mrt_rib_table_inc_entry_count(state);
|
|
DBG("\n");
|
|
}
|