0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 18:21:54 +00:00
bird/nest/mrtdump.c
Pavel Tvrdík 71299a594d MRT Table Dump: draft-petrie-grow-mrt-add-paths
Add support for MRT Table Dump draft-petrie-grow-mrt-add-paths
2016-01-06 14:41:48 +01:00

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");
}