0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-30 13:41:53 +00:00
bird/proto/bgp/mrt.c

173 lines
4.6 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "nest/route.h"
#include "nest/iface.h"
#include "nest/cli.h"
#include "lib/socket.h"
#include "lib/ip.h"
#include "lib/unix.h"
#include "lib/krt.h"
#include "bgp.h"
#include "mrt.h"
/*
* MRTDump: Table Dump V2: BGP Specific Part
*/
void
bgp_mrt_peer_index_table_dump(struct mrt_table_dump_ctx *state)
{
struct proto *P;
struct mrt_peer_index_table pit;
u32 collector_bgp_id = config->router_id;
mrt_peer_index_table_header(&pit, collector_bgp_id, state->rtable->name);
mrt_peer_index_table_add_peer(&pit, 0, 0, IPA_NONE); /* at index 0 is fake zeroed-peer for all non-BGP routes */
WALK_LIST(P, active_proto_list)
{
if (P->proto_state == PS_UP && P->proto == &proto_bgp)
{
struct bgp_proto *p = (struct bgp_proto *) P;
p->mrt_peer_index = pit.peer_count;
ip_addr peer_ip = p->cf->remote_ip;
mrt_peer_index_table_add_peer(&pit, p->remote_id, p->remote_as, peer_ip);
}
}
mrt_peer_index_table_dump(&pit, fileno(state->rfile->f));
mrt_buffer_free(&pit.msg);
}
static void
bgp_mrt_rib_table_dump(struct mrt_table_dump_ctx *state)
{
byte *msg = state->rib_table.msg.msg;
u32 msg_length = state->rib_table.msg.msg_length;
mrt_dump_message(fileno(state->rfile->f), MRT_TABLE_DUMP_V2, state->rib_table.subtype, msg, msg_length);
}
static void
bgp_mrt_rib_table_entry(struct mrt_table_dump_ctx *state, net *n, uint is_addpath)
{
u32 original_rib_sequence_number = state->rib_sequence_number;
mrt_rib_table_header(&state->rib_table, state->rib_sequence_number++, n->n.pxlen, n->n.prefix, is_addpath);
rte *e;
for (e = n->routes; e; e = e->next)
{
u32 path_id = 0;
if (is_addpath == MRT_RIB_ADDPATH)
if (e->attrs->src->private_id == 0)
continue;
if (is_addpath == MRT_RIB_NO_ADDPATH)
if (e->attrs->src->private_id != 0)
continue;
struct proto *P = e->attrs->src->proto;
if (!is_route_good_for_table_dump(state, e))
continue;
u16 peer_index = 0; /* have to correspond with fake zeroed-peer in peer index table */
uint attributes_length = 0;
static byte attributes_buffer[BGP_ATTR_BUFFER_SIZE]; /* static intends to do better performance */
if (P->proto == &proto_bgp)
{
struct bgp_proto *p = (struct bgp_proto *) P;
if (p->mrt_peer_index == 0)
{
log(L_INFO "%s: MRT Table Dump for %I/%u: Skipping not-indexed BPG RIB (local ASN: %u, remote ASN: %u)", p->p.name, n->n.prefix, n->n.pxlen, p->local_as, p->remote_as);
continue;
}
/* Set as4_session=1 to force build AS_PATH as 32bit AS in bgp_encode_attrs() */
struct bgp_proto bgp_proto_shallow_copy;
memcpy(&bgp_proto_shallow_copy, p, sizeof(bgp_proto_shallow_copy));
bgp_proto_shallow_copy.as4_session = 1;
attributes_length = bgp_encode_attrs(&bgp_proto_shallow_copy, attributes_buffer, e->attrs->eattrs, BGP_ATTR_BUFFER_SIZE);
if (attributes_length == -1)
{
log(L_WARN "%s: MRT Table Dump for %I/%u: Attribute list too long, let it blank", p->p.name, n->n.prefix, n->n.pxlen);
attributes_length = 0;
}
peer_index = p->mrt_peer_index;
if (is_addpath)
path_id = e->attrs->src->private_id;
}
struct mrt_rib_entry entry = {
.peer_index = peer_index,
.originated_time = (u32) bird_clock_to_unix_timestamp(e->lastmod),
.path_id = path_id,
.attributes_length = attributes_length,
.attributes = attributes_buffer
};
mrt_rib_table_add_entry(&state->rib_table, &entry);
}
if (state->rib_table.entry_count)
bgp_mrt_rib_table_dump(state);
else
state->rib_sequence_number = original_rib_sequence_number;
}
static void
mrt_rib_table_without_addpath(struct mrt_table_dump_ctx *state, net *n)
{
bgp_mrt_rib_table_entry(state, n, MRT_RIB_NO_ADDPATH);
}
static void
mrt_rib_table_with_addpath(struct mrt_table_dump_ctx *state, net *n)
{
bgp_mrt_rib_table_entry(state, n, MRT_RIB_ADDPATH);
}
/*
* Usage:
* struct mrt_table_dump_ctx ctx;
* bgp_mrt_table_dump_init(rtable, &ctx);
* while (ctx.state != MRT_STATE_COMPLETED)
* bgp_mrt_table_dump_step(&ctx);
*/
void
bgp_mrt_table_dump_step(struct mrt_table_dump_ctx *state)
{
if (state->state == MRT_STATE_COMPLETED)
return;
uint max_work_size = 1;
FIB_ITERATE_START(&state->rtable->fib, &state->fit, f)
{
if (!max_work_size--)
{
FIB_ITERATE_PUT(&state->fit, f);
return;
}
mrt_rib_table_without_addpath(state, (net *) f);
mrt_rib_table_with_addpath(state, (net *) f);
} FIB_ITERATE_END(f);
fit_get(&state->rtable->fib, &state->fit);
mrt_buffer_free(&state->rib_table.msg);
if (state->rfile)
rfree(state->rfile);
state->state = MRT_STATE_COMPLETED;
}