mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-23 02:01:55 +00:00
Integrate MRT Table Dump (RFC 6396) into BIRD
Asynchronous periodic mrt table dumps of routes configuration in bird.conf: mrtdump routes { [ filename "<format>"; ] [ table <name>|"<wildcard name>"; ] [ period <num>; ] [ filter <filter>|where <condition>; ] } Synchronous mrt table dumps of routes in BIRD client: mrtdump routes [table <name>|"<wildcard name>"] [to "<filename format>"] [filter <filter>|where <condition>]
This commit is contained in:
parent
33b4f40acc
commit
6702b7ad74
@ -96,7 +96,7 @@ config_alloc(byte *name)
|
|||||||
char *ndup = lp_allocu(l, nlen);
|
char *ndup = lp_allocu(l, nlen);
|
||||||
memcpy(ndup, name, nlen);
|
memcpy(ndup, name, nlen);
|
||||||
|
|
||||||
c->mrtdump_file = -1; /* Hack, this should be sysdep-specific */
|
c->mrt_proto_file = -1; /* Indication that the file descriptor should not be used */
|
||||||
c->pool = p;
|
c->pool = p;
|
||||||
c->mem = l;
|
c->mem = l;
|
||||||
c->file_name = ndup;
|
c->file_name = ndup;
|
||||||
|
35
conf/conf.h
35
conf/conf.h
@ -12,8 +12,36 @@
|
|||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/timer.h"
|
#include "lib/timer.h"
|
||||||
|
|
||||||
|
/* Configuration structures */
|
||||||
|
|
||||||
/* Configuration structure */
|
#define MRT_TABLE_NOT_CONFIGURED -1
|
||||||
|
#define MRT_TABLE_DEFAULT_PERIOD 60
|
||||||
|
#define MRT_TABLE_DEFAULT_FILENAME_FMT "%f_%F_%T.mrt"
|
||||||
|
#define MRT_TABLE_DEFAULT_TABLENAME_PATTERN "*"
|
||||||
|
|
||||||
|
struct mrt_table_common_config {
|
||||||
|
u32 period; /* Time in seconds between Table Dump */
|
||||||
|
char *filename_fmt;
|
||||||
|
struct filter *filter;
|
||||||
|
struct cli *cli; /* Client console or NULL */
|
||||||
|
struct config *config; /* Configuration or NULL */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Template of configuration that can be apply at any table */
|
||||||
|
struct mrt_table_config {
|
||||||
|
node n; /* Node in config->mrt_table_dumps */
|
||||||
|
struct mrt_table_common_config c;
|
||||||
|
char *rtable_wildcard_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Configuration that is specific per table */
|
||||||
|
struct mrt_table_individual_config {
|
||||||
|
node n; /* Node in rtable_config->mrt_table_dumps */
|
||||||
|
struct mrt_table_common_config c;
|
||||||
|
timer *timer; /* Timer for periodic dumps */
|
||||||
|
struct rtable_config *table_cf;
|
||||||
|
bird_clock_t next_dump;
|
||||||
|
};
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
pool *pool; /* Pool the configuration is stored in */
|
pool *pool; /* Pool the configuration is stored in */
|
||||||
@ -21,9 +49,10 @@ struct config {
|
|||||||
list protos; /* Configured protocol instances (struct proto_config) */
|
list protos; /* Configured protocol instances (struct proto_config) */
|
||||||
list tables; /* Configured routing tables (struct rtable_config) */
|
list tables; /* Configured routing tables (struct rtable_config) */
|
||||||
list roa_tables; /* Configured ROA tables (struct roa_table_config) */
|
list roa_tables; /* Configured ROA tables (struct roa_table_config) */
|
||||||
list logfiles; /* Configured log fils (sysdep) */
|
list logfiles; /* Configured log files (sysdep) */
|
||||||
|
list mrt_table_dumps; /* Configured MRT table dumps (struct mrt_table_config) */
|
||||||
|
|
||||||
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
|
int mrt_proto_file; /* Configured MRTDump file (sysdep, fd in unix) for Protocols*/
|
||||||
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
|
char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
|
||||||
struct rtable_config *master_rtc; /* Configuration of master routing table */
|
struct rtable_config *master_rtc; /* Configuration of master routing table */
|
||||||
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
|
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
source=rt-table.c rt-fib.c rt-attr.c rt-roa.c proto.c iface.c rt-dev.c password.c cli.c locks.c cmds.c neighbor.c \
|
source=rt-table.c rt-fib.c rt-attr.c rt-roa.c proto.c iface.c rt-dev.c password.c cli.c locks.c cmds.c neighbor.c \
|
||||||
a-path.c a-set.c
|
a-path.c a-set.c mrtdump.c
|
||||||
root-rel=../
|
root-rel=../
|
||||||
dir-name=nest
|
dir-name=nest
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ static struct roa_table_config *this_roa_table;
|
|||||||
static list *this_p_list;
|
static list *this_p_list;
|
||||||
static struct password_item *this_p_item;
|
static struct password_item *this_p_item;
|
||||||
static int password_id;
|
static int password_id;
|
||||||
|
static struct mrt_table_config *this_mrt_table_config;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iface_patt_check(void)
|
iface_patt_check(void)
|
||||||
@ -60,7 +61,7 @@ CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFA
|
|||||||
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE, ROA)
|
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE, ROA)
|
||||||
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
|
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
|
||||||
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
|
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
|
||||||
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
|
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS, PERIOD, FILENAME)
|
||||||
|
|
||||||
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
||||||
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
|
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
|
||||||
@ -80,6 +81,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
|
|||||||
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode roa_mode limit_action tab_sorted tos
|
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode roa_mode limit_action tab_sorted tos
|
||||||
%type <ps> proto_patt proto_patt2
|
%type <ps> proto_patt proto_patt2
|
||||||
%type <g> limit_spec
|
%type <g> limit_spec
|
||||||
|
%type <t> mrtdump_table_config_table_option
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
@ -371,7 +373,7 @@ debug_flag:
|
|||||||
| PACKETS { $$ = D_PACKETS; }
|
| PACKETS { $$ = D_PACKETS; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* MRTDump flags */
|
/* MRTDump Protocol flags */
|
||||||
|
|
||||||
mrtdump_mask:
|
mrtdump_mask:
|
||||||
ALL { $$ = ~0; }
|
ALL { $$ = ~0; }
|
||||||
@ -389,6 +391,50 @@ mrtdump_flag:
|
|||||||
| MESSAGES { $$ = MD_MESSAGES; }
|
| MESSAGES { $$ = MD_MESSAGES; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* MRT Table Dump */
|
||||||
|
|
||||||
|
mrtdump_table_config_init:
|
||||||
|
{
|
||||||
|
this_mrt_table_config = mrt_table_new_config();
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_config:
|
||||||
|
'{' mrtdump_table_config_init mrtdump_table_config_list '}'
|
||||||
|
| mrtdump_table_config_init ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_filter_option:
|
||||||
|
where_filter {
|
||||||
|
if (this_mrt_table_config->c.filter != FILTER_ACCEPT)
|
||||||
|
cf_error("Filter specified twice");
|
||||||
|
this_mrt_table_config->c.filter = $1;
|
||||||
|
}
|
||||||
|
| FILTER filter {
|
||||||
|
if (this_mrt_table_config->c.filter != FILTER_ACCEPT)
|
||||||
|
cf_error("Filter specified twice");
|
||||||
|
this_mrt_table_config->c.filter = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_config_list:
|
||||||
|
/* empty */
|
||||||
|
| mrtdump_table_config_option ';'
|
||||||
|
| mrtdump_table_config_list mrtdump_table_config_option ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_config_table_option:
|
||||||
|
rtable { $$ = $1->name; }
|
||||||
|
| TEXT { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_config_option:
|
||||||
|
PERIOD expr { this_mrt_table_config->c.period = $2; }
|
||||||
|
| FILENAME text { this_mrt_table_config->c.filename_fmt = $2; }
|
||||||
|
| TABLE mrtdump_table_config_table_option { this_mrt_table_config->rtable_wildcard_name = $2; }
|
||||||
|
| mrtdump_table_filter_option
|
||||||
|
;
|
||||||
|
|
||||||
/* Password lists */
|
/* Password lists */
|
||||||
|
|
||||||
password_list:
|
password_list:
|
||||||
@ -697,6 +743,30 @@ CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
|
|||||||
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
|
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
|
||||||
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
|
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
|
||||||
|
|
||||||
|
CF_CLI_HELP(MRTDUMP ROUTES, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>] , [[Save MRT Table Dump into a file]])
|
||||||
|
CF_CLI(MRTDUMP ROUTES, mrtdump_table_cli_config, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>], [[Save mrt table dump v2 of table name <t> right now]])
|
||||||
|
{
|
||||||
|
this_mrt_table_config->c.cli = this_cli;
|
||||||
|
this_mrt_table_config->c.config = NULL;
|
||||||
|
mrt_table_cli_cmd(this_mrt_table_config);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
mrtdump_table_cli_config:
|
||||||
|
mrtdump_table_config_init mrtdump_table_cli_config_list
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_cli_config_list:
|
||||||
|
/* empty */
|
||||||
|
| mrtdump_table_cli_config_option
|
||||||
|
| mrtdump_table_cli_config_list mrtdump_table_cli_config_option
|
||||||
|
;
|
||||||
|
|
||||||
|
mrtdump_table_cli_config_option:
|
||||||
|
TABLE mrtdump_table_config_table_option { this_mrt_table_config->rtable_wildcard_name = $2; }
|
||||||
|
| TO text { this_mrt_table_config->c.filename_fmt = $2; }
|
||||||
|
| mrtdump_table_filter_option
|
||||||
|
;
|
||||||
|
|
||||||
CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
|
CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
|
||||||
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
|
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
|
||||||
|
|
||||||
|
265
nest/mrtdump.c
Normal file
265
nest/mrtdump.c
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
mrt_rib_table_reset(state);
|
||||||
|
|
||||||
|
#ifdef IPV6
|
||||||
|
state->subtype = MRT_RIB_IPV6_UNICAST;
|
||||||
|
#else
|
||||||
|
state->subtype = 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);
|
||||||
|
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");
|
||||||
|
}
|
115
nest/mrtdump.h
115
nest/mrtdump.h
@ -1,31 +1,106 @@
|
|||||||
/*
|
/*
|
||||||
* BIRD -- MRTdump handling
|
* 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.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MRTDUMP_H
|
#ifndef _BIRD_MRTDUMP_H_
|
||||||
#define MRTDUMP_H
|
#define _BIRD_MRTDUMP_H_
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
|
#include "lib/lists.h"
|
||||||
|
#include "nest/route.h"
|
||||||
|
#include "lib/event.h"
|
||||||
|
|
||||||
/* MRTDump values */
|
#define MRT_HDR_LENGTH 12 /* MRT Timestamp + MRT Type + MRT Subtype + MRT Load Length */
|
||||||
|
#define MRT_PEER_TYPE_32BIT_ASN 2 /* MRT Table Dump: Peer Index Table: Peer Type: Use 32bit ASN */
|
||||||
#define MRTDUMP_HDR_LENGTH 12
|
#define MRT_PEER_TYPE_IPV6 1 /* MRT Table Dump: Peer Index Table: Peer Type: Use IPv6 IP Address */
|
||||||
|
|
||||||
/* MRTdump types */
|
|
||||||
|
|
||||||
#define BGP4MP 16
|
|
||||||
|
|
||||||
/* MRTdump subtypes */
|
|
||||||
|
|
||||||
#define BGP4MP_MESSAGE 1
|
|
||||||
#define BGP4MP_MESSAGE_AS4 4
|
|
||||||
#define BGP4MP_STATE_CHANGE_AS4 5
|
|
||||||
|
|
||||||
|
|
||||||
/* implemented in sysdep */
|
|
||||||
void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
|
|
||||||
|
|
||||||
|
#ifdef PATH_MAX
|
||||||
|
#define BIRD_PATH_MAX PATH_MAX
|
||||||
|
#else
|
||||||
|
#define BIRD_PATH_MAX 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* MRT Types */
|
||||||
|
#define MRT_TABLE_DUMP_V2 13
|
||||||
|
#define MRT_BGP4MP 16
|
||||||
|
|
||||||
|
/* MRT Table Dump v2 Subtypes */
|
||||||
|
#define MRT_PEER_INDEX_TABLE 1
|
||||||
|
#define MRT_RIB_IPV4_UNICAST 2
|
||||||
|
#define MRT_RIB_IPV4_MULTICAST 3
|
||||||
|
#define MRT_RIB_IPV6_UNICAST 4
|
||||||
|
#define MRT_RIB_IPV6_MULTICAST 5
|
||||||
|
#define MRT_RIB_GENERIC 6
|
||||||
|
|
||||||
|
/* MRT BGP4MP Subtypes */
|
||||||
|
#define MRT_BGP4MP_MESSAGE 1
|
||||||
|
#define MRT_BGP4MP_MESSAGE_AS4 4
|
||||||
|
#define MRT_BGP4MP_STATE_CHANGE_AS4 5
|
||||||
|
|
||||||
|
struct mrt_buffer
|
||||||
|
{
|
||||||
|
byte *msg; /* Buffer with final formatted data */
|
||||||
|
size_t msg_length; /* Size of used buffer */
|
||||||
|
size_t msg_capacity; /* Number of allocated bytes in msg */
|
||||||
|
#define MRT_BUFFER_DEFAULT_CAPACITY 64 /* Size in bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mrt_peer_index_table
|
||||||
|
{
|
||||||
|
struct mrt_buffer msg;
|
||||||
|
u16 peer_count; /* Datatype u16 should fit with the size 16bit in MRT packet */
|
||||||
|
u32 peer_count_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mrt_rib_table
|
||||||
|
{
|
||||||
|
struct mrt_buffer msg;
|
||||||
|
int subtype; /* RIB_IPV4_UNICAST or RIB_IPV6_UNICAST */
|
||||||
|
u16 entry_count; /* Number of RIB Entries */
|
||||||
|
u32 entry_count_offset; /* Offset in msg->msg[?] to position where start the entries count */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mrt_rib_entry
|
||||||
|
{
|
||||||
|
u16 peer_index;
|
||||||
|
u32 originated_time;
|
||||||
|
u16 attributes_length;
|
||||||
|
byte *attributes; /* encoded BGP attributes */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mrt_table_dump_ctx {
|
||||||
|
struct rtable *rtable;
|
||||||
|
struct fib_iterator fit;
|
||||||
|
struct mrt_rib_table rib_table;
|
||||||
|
u32 rib_sequence_number;
|
||||||
|
struct rfile *rfile; /* tracking for mrt table dump file */
|
||||||
|
char *file_path; /* full path for mrt table dump file */
|
||||||
|
byte state;
|
||||||
|
#define MRT_STATE_RUNNING 0
|
||||||
|
#define MRT_STATE_COMPLETED 1
|
||||||
|
event *step;
|
||||||
|
struct mrt_table_individual_config config; /* Own special configuration of MRT */
|
||||||
|
};
|
||||||
|
|
||||||
|
void mrt_buffer_alloc(struct mrt_buffer *buf);
|
||||||
|
void mrt_buffer_free(struct mrt_buffer *buf);
|
||||||
|
|
||||||
|
void mrt_peer_index_table_header(struct mrt_peer_index_table *state, u32 collector_bgp_id, const char *name);
|
||||||
|
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);
|
||||||
|
void mrt_peer_index_table_dump(struct mrt_peer_index_table *state, int file_descriptor);
|
||||||
|
|
||||||
|
void mrt_rib_table_alloc(struct mrt_rib_table *state);
|
||||||
|
void mrt_rib_table_header(struct mrt_rib_table *state, u32 sequence_number, u8 prefix_length, ip_addr prefix);
|
||||||
|
void mrt_rib_table_add_entry(struct mrt_rib_table *state, const struct mrt_rib_entry *entry);
|
||||||
|
|
||||||
|
/* implemented in sysdep */
|
||||||
|
void mrt_dump_message_proto(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
|
||||||
|
void mrt_dump_message(int file_descriptor, u16 type, u16 subtype, byte *buf, u32 len);
|
||||||
|
|
||||||
|
#endif /* _BIRD_MRTDUMP_H_ */
|
||||||
|
@ -129,6 +129,7 @@ struct rtable_config {
|
|||||||
int gc_max_ops; /* Maximum number of operations before GC is run */
|
int gc_max_ops; /* Maximum number of operations before GC is run */
|
||||||
int gc_min_time; /* Minimum time between two consecutive GC runs */
|
int gc_min_time; /* Minimum time between two consecutive GC runs */
|
||||||
byte sorted; /* Routes of network are sorted according to rte_better() */
|
byte sorted; /* Routes of network are sorted according to rte_better() */
|
||||||
|
list mrt_table_dumps; /* Configured MRT tables dumps (struct mrt_table_individual_config) */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rtable {
|
typedef struct rtable {
|
||||||
@ -631,5 +632,13 @@ void roa_preconfig(struct config *c);
|
|||||||
void roa_commit(struct config *new, struct config *old);
|
void roa_commit(struct config *new, struct config *old);
|
||||||
void roa_show(struct roa_show_data *d);
|
void roa_show(struct roa_show_data *d);
|
||||||
|
|
||||||
|
void mrt_table_dump_init_periodic(struct rtable *tab, list *mrt_table_dumps);
|
||||||
|
struct mrt_table_dump_ctx *mrt_table_dump_cmd(struct mrt_table_individual_config *mrt_cfg);
|
||||||
|
void mrt_table_cli_cmd(struct mrt_table_config *mrt_config);
|
||||||
|
struct mrt_table_config *mrt_table_new_config(void);
|
||||||
|
|
||||||
|
struct mrt_table_dump_ctx;
|
||||||
|
int is_route_good_for_table_dump(struct mrt_table_dump_ctx *state, rte *e);
|
||||||
|
void mrt_table_dump_init_file_descriptor(struct mrt_table_dump_ctx *state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
359
nest/rt-table.c
359
nest/rt-table.c
@ -28,6 +28,10 @@
|
|||||||
* routes in order to conserve memory.
|
* routes in order to conserve memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#undef LOCAL_DEBUG
|
#undef LOCAL_DEBUG
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
@ -35,6 +39,7 @@
|
|||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
#include "nest/cli.h"
|
#include "nest/cli.h"
|
||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
|
#include "nest/mrtdump.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/event.h"
|
#include "lib/event.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
@ -42,6 +47,9 @@
|
|||||||
#include "filter/filter.h"
|
#include "filter/filter.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
#include "lib/alloca.h"
|
#include "lib/alloca.h"
|
||||||
|
#include "lib/unix.h"
|
||||||
|
|
||||||
|
#include "proto/bgp/mrt.h"
|
||||||
|
|
||||||
pool *rt_table_pool;
|
pool *rt_table_pool;
|
||||||
|
|
||||||
@ -58,7 +66,8 @@ static void rt_next_hop_update(rtable *tab);
|
|||||||
static inline int rt_prune_table(rtable *tab);
|
static inline int rt_prune_table(rtable *tab);
|
||||||
static inline void rt_schedule_gc(rtable *tab);
|
static inline void rt_schedule_gc(rtable *tab);
|
||||||
static inline void rt_schedule_prune(rtable *tab);
|
static inline void rt_schedule_prune(rtable *tab);
|
||||||
|
static void mrt_table_dump_stop_periodic(struct rtable *tab);
|
||||||
|
static int mrt_table_dump_cmd_step(void *mrt_table_dump_ctx);
|
||||||
|
|
||||||
static inline struct ea_list *
|
static inline struct ea_list *
|
||||||
make_tmp_attrs(struct rte *rt, struct linpool *pool)
|
make_tmp_attrs(struct rte *rt, struct linpool *pool)
|
||||||
@ -1661,6 +1670,8 @@ rt_preconfig(struct config *c)
|
|||||||
|
|
||||||
init_list(&c->tables);
|
init_list(&c->tables);
|
||||||
c->master_rtc = rt_new_table(s);
|
c->master_rtc = rt_new_table(s);
|
||||||
|
|
||||||
|
init_list(&c->mrt_table_dumps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1830,6 +1841,9 @@ rt_new_table(struct symbol *s)
|
|||||||
add_tail(&new_config->tables, &c->n);
|
add_tail(&new_config->tables, &c->n);
|
||||||
c->gc_max_ops = 1000;
|
c->gc_max_ops = 1000;
|
||||||
c->gc_min_time = 5;
|
c->gc_min_time = 5;
|
||||||
|
|
||||||
|
init_list(&c->mrt_table_dumps);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1896,6 +1910,7 @@ rt_commit(struct config *new, struct config *old)
|
|||||||
WALK_LIST(o, old->tables)
|
WALK_LIST(o, old->tables)
|
||||||
{
|
{
|
||||||
rtable *ot = o->table;
|
rtable *ot = o->table;
|
||||||
|
mrt_table_dump_stop_periodic(ot);
|
||||||
if (!ot->deleted)
|
if (!ot->deleted)
|
||||||
{
|
{
|
||||||
struct symbol *sym = cf_find_symbol(new, o->name);
|
struct symbol *sym = cf_find_symbol(new, o->name);
|
||||||
@ -1922,6 +1937,7 @@ rt_commit(struct config *new, struct config *old)
|
|||||||
}
|
}
|
||||||
|
|
||||||
WALK_LIST(r, new->tables)
|
WALK_LIST(r, new->tables)
|
||||||
|
{
|
||||||
if (!r->table)
|
if (!r->table)
|
||||||
{
|
{
|
||||||
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
|
||||||
@ -1930,6 +1946,8 @@ rt_commit(struct config *new, struct config *old)
|
|||||||
add_tail(&routing_tables, &t->n);
|
add_tail(&routing_tables, &t->n);
|
||||||
r->table = t;
|
r->table = t;
|
||||||
}
|
}
|
||||||
|
mrt_table_dump_init_periodic(r->table, &new->mrt_table_dumps);
|
||||||
|
}
|
||||||
DBG("\tdone\n");
|
DBG("\tdone\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2605,6 +2623,345 @@ rt_show(struct rt_show_data *d)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MRTDump Table Commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct mrt_table_config *
|
||||||
|
mrt_table_new_config(void)
|
||||||
|
{
|
||||||
|
struct mrt_table_config *mrt_cfg = cfg_allocz(sizeof(struct mrt_table_config));
|
||||||
|
mrt_cfg->c.period = MRT_TABLE_NOT_CONFIGURED;
|
||||||
|
mrt_cfg->c.filter = FILTER_ACCEPT;
|
||||||
|
mrt_cfg->c.config = new_config;
|
||||||
|
return mrt_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct filter *
|
||||||
|
mrt_table_dump_config_get_filter(struct mrt_table_dump_ctx *state)
|
||||||
|
{
|
||||||
|
if (state->config.c.filter != FILTER_ACCEPT)
|
||||||
|
return state->config.c.filter;
|
||||||
|
|
||||||
|
return FILTER_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
mrt_table_dump_config_get_period(struct mrt_table_individual_config *mrt_cfg)
|
||||||
|
{
|
||||||
|
if (mrt_cfg->c.period && mrt_cfg->c.period != (u32)MRT_TABLE_NOT_CONFIGURED)
|
||||||
|
return mrt_cfg->c.period;
|
||||||
|
|
||||||
|
return MRT_TABLE_DEFAULT_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writing timestamp of the next mrt dump.
|
||||||
|
* Return seconds for wait for next mrt dump from now.
|
||||||
|
*/
|
||||||
|
static uint
|
||||||
|
mrt_table_dump_config_get_next_modular_period(struct mrt_table_individual_config *cfg)
|
||||||
|
{
|
||||||
|
bird_clock_t period = (bird_clock_t)mrt_table_dump_config_get_period(cfg);
|
||||||
|
bird_clock_t timestamp = now;
|
||||||
|
|
||||||
|
if (cfg->next_dump != 0)
|
||||||
|
{
|
||||||
|
cfg->next_dump += period;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bird_clock_t time_to_wait = period - (timestamp % period);
|
||||||
|
cfg->next_dump = timestamp + time_to_wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (uint)(cfg->next_dump - timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mrt_table_dump_config_get_filename_fmt(struct mrt_table_dump_ctx *state)
|
||||||
|
{
|
||||||
|
if (state->config.c.filename_fmt != NULL)
|
||||||
|
return state->config.c.filename_fmt;
|
||||||
|
|
||||||
|
return MRT_TABLE_DEFAULT_FILENAME_FMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mrt_table_dump_config_get_tablename_pattern(const struct mrt_table_config *mrt_config)
|
||||||
|
{
|
||||||
|
const char *table_name_pattern = MRT_TABLE_DEFAULT_TABLENAME_PATTERN;
|
||||||
|
if (mrt_config->rtable_wildcard_name)
|
||||||
|
table_name_pattern = mrt_config->rtable_wildcard_name;
|
||||||
|
return table_name_pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mrt_table_dump_timer_hook(struct timer *timer)
|
||||||
|
{
|
||||||
|
if (timer->expires)
|
||||||
|
{
|
||||||
|
struct mrt_table_individual_config *cfg = (struct mrt_table_individual_config *) timer->data;
|
||||||
|
mrt_table_dump_cmd(cfg);
|
||||||
|
tm_start(timer, mrt_table_dump_config_get_next_modular_period(cfg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mrt_table_individual_config *
|
||||||
|
mrt_table_new_individual_config(struct mrt_table_config *mrt_cfg, struct rtable *tab)
|
||||||
|
{
|
||||||
|
struct mrt_table_individual_config *cfg = mb_allocz(rt_table_pool, sizeof(struct mrt_table_individual_config));
|
||||||
|
cfg->c = mrt_cfg->c;
|
||||||
|
cfg->table_cf = tab->config;
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mrt_table_dump_init_periodic(struct rtable *tab, list *mrt_table_dumps)
|
||||||
|
{
|
||||||
|
struct mrt_table_config *mrt_cfg;
|
||||||
|
|
||||||
|
WALK_LIST(mrt_cfg, *mrt_table_dumps)
|
||||||
|
{
|
||||||
|
if (patmatch(mrt_table_dump_config_get_tablename_pattern(mrt_cfg), tab->name))
|
||||||
|
{
|
||||||
|
struct mrt_table_individual_config *cfg = mrt_table_new_individual_config(mrt_cfg, tab);
|
||||||
|
add_tail(&cfg->table_cf->mrt_table_dumps, &cfg->n);
|
||||||
|
cfg->timer = tm_new_set(rt_table_pool, mrt_table_dump_timer_hook, cfg, 0, (uint)-1);
|
||||||
|
tm_start(cfg->timer, mrt_table_dump_config_get_next_modular_period(cfg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mrt_table_dump_cmd_step(void *mrt_table_dump_ctx)
|
||||||
|
{
|
||||||
|
struct mrt_table_dump_ctx *state = mrt_table_dump_ctx;
|
||||||
|
|
||||||
|
bgp_mrt_table_dump_step(state);
|
||||||
|
if (state->state != MRT_STATE_COMPLETED)
|
||||||
|
ev_schedule(state->step);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rfree(state->step);
|
||||||
|
if (state->config.c.config)
|
||||||
|
config_del_obstacle(state->config.c.config);
|
||||||
|
log(L_INFO "MRT dump of table %s was saved into file \"%s\"", state->rtable->name, state->file_path);
|
||||||
|
if (state->config.c.cli)
|
||||||
|
{
|
||||||
|
cli_printf(state->config.c.cli, 13, "Dump of table %s was saved into file \"%s\"", state->rtable->name, state->file_path);
|
||||||
|
}
|
||||||
|
rt_unlock_table(state->rtable);
|
||||||
|
mb_free(state->file_path);
|
||||||
|
mb_free(state);
|
||||||
|
return 0; /* End of entire mrt dump */
|
||||||
|
}
|
||||||
|
return 1; /* End of part in mrt dump */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mrt_table_dump_cmd_step_void(void *mrt_table_dump_ctx)
|
||||||
|
{
|
||||||
|
mrt_table_dump_cmd_step(mrt_table_dump_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mrt_table_dump_init(struct mrt_table_dump_ctx *state)
|
||||||
|
{
|
||||||
|
struct rtable *tab = state->rtable;
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
fib_check(&tab->fib);
|
||||||
|
#endif
|
||||||
|
FIB_ITERATE_INIT(&state->fit, &tab->fib);
|
||||||
|
|
||||||
|
state->state = MRT_STATE_RUNNING;
|
||||||
|
state->rib_sequence_number = 0;
|
||||||
|
mrt_table_dump_init_file_descriptor(state);
|
||||||
|
mrt_rib_table_alloc(&state->rib_table);
|
||||||
|
|
||||||
|
bgp_mrt_peer_index_table_dump(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mrt_table_dump_ctx *
|
||||||
|
mrt_table_dump_cmd(struct mrt_table_individual_config *mrt_cfg)
|
||||||
|
{
|
||||||
|
struct mrt_table_dump_ctx *state = mb_allocz(rt_table_pool, sizeof(struct mrt_table_dump_ctx));
|
||||||
|
|
||||||
|
event *step_ev = ev_new(rt_table_pool);
|
||||||
|
step_ev->hook = mrt_table_dump_cmd_step_void;
|
||||||
|
step_ev->data = state;
|
||||||
|
state->step = step_ev;
|
||||||
|
state->config = *mrt_cfg;
|
||||||
|
state->rtable = state->config.table_cf->table;
|
||||||
|
rt_lock_table(state->rtable);
|
||||||
|
|
||||||
|
if (state->config.c.config)
|
||||||
|
config_add_obstacle(state->config.c.config);
|
||||||
|
|
||||||
|
mrt_table_dump_init(state);
|
||||||
|
if (mrt_table_dump_cmd_step(state) == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
is_route_good_for_table_dump(struct mrt_table_dump_ctx *state, rte *e)
|
||||||
|
{
|
||||||
|
if (e->attrs->src->proto->proto_state != PS_UP)
|
||||||
|
return 0; /* FAIL */
|
||||||
|
|
||||||
|
struct filter *filter = mrt_table_dump_config_get_filter(state);
|
||||||
|
rte *rte = e;
|
||||||
|
struct ea_list *tmp_attrs = make_tmp_attrs(rte, rte_update_pool);
|
||||||
|
|
||||||
|
int filter_result = f_run(filter, &rte, &tmp_attrs, rte_update_pool, REF_COW);
|
||||||
|
|
||||||
|
if (filter_result >= F_REJECT)
|
||||||
|
return 0; /* FAIL */
|
||||||
|
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* You must free the result if result is non-NULL. */
|
||||||
|
static char *
|
||||||
|
mrt_str_replace(const char *orig, const char *rep, const char *with)
|
||||||
|
{
|
||||||
|
if (!orig || !rep || !with)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char *result;
|
||||||
|
const char *ins_point;
|
||||||
|
char *tmp;
|
||||||
|
int len_rep;
|
||||||
|
int len_with;
|
||||||
|
int len_front;
|
||||||
|
int num_of_replacements;
|
||||||
|
|
||||||
|
len_rep = strlen(rep);
|
||||||
|
len_with = strlen(with);
|
||||||
|
|
||||||
|
ins_point = orig;
|
||||||
|
for (num_of_replacements = 0; tmp = strstr(ins_point, rep); ++num_of_replacements)
|
||||||
|
ins_point = tmp + len_rep;
|
||||||
|
|
||||||
|
/* first time through the loop, all the variable are set correctly
|
||||||
|
* from here on,
|
||||||
|
* tmp points to the end of the result string
|
||||||
|
* ins points to the next occurrence of rep in orig
|
||||||
|
* orig points to the remainder of orig after "end of rep"
|
||||||
|
*/
|
||||||
|
tmp = result = mb_alloc(rt_table_pool, strlen(orig) + (len_with - len_rep) * num_of_replacements + 1);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (num_of_replacements--)
|
||||||
|
{
|
||||||
|
ins_point = strstr(orig, rep);
|
||||||
|
len_front = ins_point - orig;
|
||||||
|
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||||
|
tmp = strcpy(tmp, with) + len_with;
|
||||||
|
orig += len_front + len_rep; /* move to next "end of rep" */
|
||||||
|
}
|
||||||
|
strcpy(tmp, orig);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
mrt_table_dump_get_realpath(const char *filename)
|
||||||
|
{
|
||||||
|
static char path[BIRD_PATH_MAX];
|
||||||
|
if (realpath(filename, path) != path)
|
||||||
|
{
|
||||||
|
DBG("ERR: realpath(\"%s\") errno %d", filename, errno);
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mrt_table_dump_init_file_descriptor(struct mrt_table_dump_ctx *state)
|
||||||
|
{
|
||||||
|
char *tablename = state->config.table_cf->name;
|
||||||
|
char *filename_fmt = mrt_str_replace(mrt_table_dump_config_get_filename_fmt(state), "%f", tablename);
|
||||||
|
|
||||||
|
if (filename_fmt)
|
||||||
|
{
|
||||||
|
struct timeformat timestamp_fmt = {
|
||||||
|
.fmt1 = filename_fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
char filename[TM_DATETIME_BUFFER_SIZE];
|
||||||
|
tm_format_datetime(filename, ×tamp_fmt, now);
|
||||||
|
state->rfile = tracked_fopen(rt_table_pool, filename, "a");
|
||||||
|
|
||||||
|
const char *filename_fullpath = mrt_table_dump_get_realpath(filename);
|
||||||
|
state->file_path = mb_allocz(rt_table_pool, strlen(filename_fullpath)+1);
|
||||||
|
strcpy(state->file_path, filename_fullpath);
|
||||||
|
|
||||||
|
if (!state->rfile)
|
||||||
|
{
|
||||||
|
log(L_WARN "Unable to open file \"%s\" for MRT dump of table %s", state->file_path, tablename);
|
||||||
|
if (state->config.c.cli)
|
||||||
|
{
|
||||||
|
cli_msg(13, "Unable to open file \"%s\" for MRT dump of table %s", state->file_path, tablename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log(L_INFO "MRT dump of table %s is saving into file \"%s\"", tablename, state->file_path);
|
||||||
|
if (state->config.c.cli)
|
||||||
|
{
|
||||||
|
cli_msg(13, "Dump of table %s is saving into file \"%s\"", tablename, state->file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mb_free(filename_fmt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log(L_ERR "Parsing MRT dump filename filename_fmt \"%s\" for table %s failed", mrt_table_dump_config_get_filename_fmt(state), tablename);
|
||||||
|
if (state->config.c.cli)
|
||||||
|
{
|
||||||
|
cli_msg(13, "Parsing filename filename_fmt \"%s\" for table %s failed", mrt_table_dump_config_get_filename_fmt(state), tablename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mrt_table_dump_stop_periodic(struct rtable *tab)
|
||||||
|
{
|
||||||
|
struct mrt_table_individual_config *mrt_cfg, *mrt_cfg_next;
|
||||||
|
WALK_LIST_DELSAFE(mrt_cfg, mrt_cfg_next, tab->config->mrt_table_dumps)
|
||||||
|
{
|
||||||
|
mrt_cfg->timer->recurrent = 0;
|
||||||
|
tm_stop(mrt_cfg->timer);
|
||||||
|
rfree(mrt_cfg->timer);
|
||||||
|
rem_node(&mrt_cfg->n);
|
||||||
|
mb_free(mrt_cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mrt_table_cli_cmd(struct mrt_table_config *mrt_cfg)
|
||||||
|
{
|
||||||
|
struct rtable_config *r;
|
||||||
|
|
||||||
|
WALK_LIST(r, config->tables)
|
||||||
|
{
|
||||||
|
if (patmatch(mrt_table_dump_config_get_tablename_pattern(mrt_cfg), r->table->name))
|
||||||
|
{
|
||||||
|
struct mrt_table_individual_config *cfg = mrt_table_new_individual_config(mrt_cfg, r->table);
|
||||||
|
struct mrt_table_dump_ctx *state = mrt_table_dump_cmd(cfg);
|
||||||
|
if (state && state->state != MRT_STATE_COMPLETED)
|
||||||
|
while (mrt_table_dump_cmd_step(state));
|
||||||
|
mb_free(cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cli_printf(mrt_cfg->c.cli, 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Documentation for functions declared inline in route.h
|
* Documentation for functions declared inline in route.h
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
source=bgp.c attrs.c packets.c
|
source=bgp.c attrs.c packets.c mrt.c
|
||||||
root-rel=../../
|
root-rel=../../
|
||||||
dir-name=proto/bgp
|
dir-name=proto/bgp
|
||||||
|
|
||||||
|
@ -75,8 +75,10 @@
|
|||||||
#include "lib/socket.h"
|
#include "lib/socket.h"
|
||||||
#include "lib/resource.h"
|
#include "lib/resource.h"
|
||||||
#include "lib/string.h"
|
#include "lib/string.h"
|
||||||
|
#include "lib/slists.h"
|
||||||
|
|
||||||
#include "bgp.h"
|
#include "bgp.h"
|
||||||
|
#include "mrt.h"
|
||||||
|
|
||||||
|
|
||||||
struct linpool *bgp_linpool; /* Global temporary pool */
|
struct linpool *bgp_linpool; /* Global temporary pool */
|
||||||
@ -1261,6 +1263,7 @@ bgp_init(struct proto_config *C)
|
|||||||
p->rs_client = c->rs_client;
|
p->rs_client = c->rs_client;
|
||||||
p->rr_client = c->rr_client;
|
p->rr_client = c->rr_client;
|
||||||
p->igp_table = get_igp_table(c);
|
p->igp_table = get_igp_table(c);
|
||||||
|
p->mrt_peer_index = 0;
|
||||||
|
|
||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,7 @@ struct bgp_proto {
|
|||||||
u8 last_error_class; /* Error class of last error */
|
u8 last_error_class; /* Error class of last error */
|
||||||
u32 last_error_code; /* Error code of last error. BGP protocol errors
|
u32 last_error_code; /* Error code of last error. BGP protocol errors
|
||||||
are encoded as (bgp_err_code << 16 | bgp_err_subcode) */
|
are encoded as (bgp_err_code << 16 | bgp_err_subcode) */
|
||||||
|
u16 mrt_peer_index; /* Used for MRT Table Dump */
|
||||||
#ifdef IPV6
|
#ifdef IPV6
|
||||||
byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */
|
byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */
|
||||||
unsigned mp_reach_len, mp_unreach_len;
|
unsigned mp_reach_len, mp_unreach_len;
|
||||||
@ -189,6 +190,7 @@ struct bgp_bucket {
|
|||||||
#define BGP_TX_BUFFER_SIZE 4096
|
#define BGP_TX_BUFFER_SIZE 4096
|
||||||
#define BGP_RX_BUFFER_EXT_SIZE 65535
|
#define BGP_RX_BUFFER_EXT_SIZE 65535
|
||||||
#define BGP_TX_BUFFER_EXT_SIZE 65535
|
#define BGP_TX_BUFFER_EXT_SIZE 65535
|
||||||
|
#define BGP_ATTR_BUFFER_SIZE 2048 /* Default buffer size for encoded bgp attributes */
|
||||||
|
|
||||||
static inline int bgp_max_packet_length(struct bgp_proto *p)
|
static inline int bgp_max_packet_length(struct bgp_proto *p)
|
||||||
{ return p->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; }
|
{ return p->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; }
|
||||||
|
134
proto/bgp/mrt.c
Normal file
134
proto/bgp/mrt.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
u32 original_rib_sequence_number = state->rib_sequence_number;
|
||||||
|
|
||||||
|
FIB_ITERATE_START(&state->rtable->fib, &state->fit, f)
|
||||||
|
{
|
||||||
|
if (!max_work_size--)
|
||||||
|
{
|
||||||
|
FIB_ITERATE_PUT(&state->fit, f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net *n = (net *) f;
|
||||||
|
mrt_rib_table_header(&state->rib_table, state->rib_sequence_number++, n->n.pxlen, n->n.prefix);
|
||||||
|
|
||||||
|
rte *e;
|
||||||
|
for (e = n->routes; e; e = e->next)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes_length = bgp_encode_attrs(p, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mrt_rib_entry entry = {
|
||||||
|
.peer_index = peer_index,
|
||||||
|
.originated_time = (u32) bird_clock_to_unix_timestamp(e->lastmod),
|
||||||
|
.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;
|
||||||
|
} 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;
|
||||||
|
}
|
11
proto/bgp/mrt.h
Normal file
11
proto/bgp/mrt.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _BIRD_BGP_MRT_H_
|
||||||
|
#define _BIRD_BGP_MRT_H_
|
||||||
|
|
||||||
|
#include "nest/route.h"
|
||||||
|
#include "nest/mrtdump.h"
|
||||||
|
#include "bgp.h"
|
||||||
|
|
||||||
|
void bgp_mrt_table_dump_step(struct mrt_table_dump_ctx *state);
|
||||||
|
void bgp_mrt_peer_index_table_dump(struct mrt_table_dump_ctx *state);
|
||||||
|
|
||||||
|
#endif /* _BIRD_BGP_MRT_H_ */
|
@ -85,14 +85,13 @@ static void
|
|||||||
mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
|
mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
|
||||||
{
|
{
|
||||||
byte *buf = alloca(128+len); /* 128 is enough for MRT headers */
|
byte *buf = alloca(128+len); /* 128 is enough for MRT headers */
|
||||||
byte *bp = buf + MRTDUMP_HDR_LENGTH;
|
byte *bp = buf + MRT_HDR_LENGTH;
|
||||||
int as4 = conn->bgp->as4_session;
|
int as4 = conn->bgp->as4_session;
|
||||||
|
|
||||||
bp = mrt_put_bgp4_hdr(bp, conn, as4);
|
bp = mrt_put_bgp4_hdr(bp, conn, as4);
|
||||||
memcpy(bp, pkt, len);
|
memcpy(bp, pkt, len);
|
||||||
bp += len;
|
bp += len;
|
||||||
mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE,
|
mrt_dump_message_proto(&conn->bgp->p, MRT_BGP4MP, as4 ? MRT_BGP4MP_MESSAGE_AS4 : MRT_BGP4MP_MESSAGE, buf, bp-buf);
|
||||||
buf, bp-buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u16
|
static inline u16
|
||||||
@ -106,13 +105,13 @@ void
|
|||||||
mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)
|
mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)
|
||||||
{
|
{
|
||||||
byte buf[128];
|
byte buf[128];
|
||||||
byte *bp = buf + MRTDUMP_HDR_LENGTH;
|
byte *bp = buf + MRT_HDR_LENGTH;
|
||||||
|
|
||||||
bp = mrt_put_bgp4_hdr(bp, conn, 1);
|
bp = mrt_put_bgp4_hdr(bp, conn, 1);
|
||||||
put_u16(bp+0, convert_state(old));
|
put_u16(bp+0, convert_state(old));
|
||||||
put_u16(bp+2, convert_state(new));
|
put_u16(bp+2, convert_state(new));
|
||||||
bp += 4;
|
bp += 4;
|
||||||
mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf);
|
mrt_dump_message_proto(&conn->bgp->p, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4, buf, bp-buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte *
|
static byte *
|
||||||
|
@ -42,9 +42,9 @@ syslog_name:
|
|||||||
|
|
||||||
log_file:
|
log_file:
|
||||||
text {
|
text {
|
||||||
FILE *f = tracked_fopen(new_config->pool, $1, "a");
|
struct rfile *rf = tracked_fopen(new_config->pool, $1, "a");
|
||||||
if (!f) cf_error("Unable to open log file `%s': %m", $1);
|
if (!rf) cf_error("Unable to open log file `%s': %m", $1);
|
||||||
$$ = f;
|
$$ = rf->f;
|
||||||
}
|
}
|
||||||
| SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
|
| SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
|
||||||
| STDERR { $$ = stderr; }
|
| STDERR { $$ = stderr; }
|
||||||
@ -77,14 +77,14 @@ CF_ADDTO(conf, mrtdump_base)
|
|||||||
|
|
||||||
mrtdump_base:
|
mrtdump_base:
|
||||||
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
|
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
|
||||||
|
| MRTDUMP ROUTES mrtdump_table_config { add_tail(&new_config->mrt_table_dumps, &this_mrt_table_config->n); }
|
||||||
| MRTDUMP text ';' {
|
| MRTDUMP text ';' {
|
||||||
FILE *f = tracked_fopen(new_config->pool, $2, "a");
|
struct rfile *rf = tracked_fopen(new_config->pool, $2, "a");
|
||||||
if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
|
if (!rf) cf_error("Unable to open MRTDump file '%s': %m", $2);
|
||||||
new_config->mrtdump_file = fileno(f);
|
new_config->mrt_proto_file = fileno(rf->f);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
CF_ADDTO(conf, timeformat_base)
|
CF_ADDTO(conf, timeformat_base)
|
||||||
|
|
||||||
timeformat_which:
|
timeformat_which:
|
||||||
|
@ -55,11 +55,6 @@
|
|||||||
* Tracked Files
|
* Tracked Files
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct rfile {
|
|
||||||
resource r;
|
|
||||||
FILE *f;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rf_free(resource *r)
|
rf_free(resource *r)
|
||||||
{
|
{
|
||||||
@ -85,17 +80,17 @@ static struct resclass rf_class = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
void *
|
struct rfile *
|
||||||
tracked_fopen(pool *p, char *name, char *mode)
|
tracked_fopen(pool *p, const char *name, const char *mode)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(name, mode);
|
FILE *f = fopen(name, mode);
|
||||||
|
|
||||||
if (f)
|
if (!f)
|
||||||
{
|
return NULL;
|
||||||
|
|
||||||
struct rfile *r = ralloc(p, &rf_class);
|
struct rfile *r = ralloc(p, &rf_class);
|
||||||
r->f = f;
|
r->f = f;
|
||||||
}
|
return r;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,14 +316,20 @@ log_init_debug(char *f)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
|
mrt_dump_message_proto(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
|
||||||
|
{
|
||||||
|
mrt_dump_message(p->cf->global->mrt_proto_file, type, subtype, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mrt_dump_message(int file_descriptor, u16 type, u16 subtype, byte *buf, u32 len)
|
||||||
{
|
{
|
||||||
/* Prepare header */
|
/* Prepare header */
|
||||||
put_u32(buf+0, now_real);
|
put_u32(buf+0, now_real);
|
||||||
put_u16(buf+4, type);
|
put_u16(buf+4, type);
|
||||||
put_u16(buf+6, subtype);
|
put_u16(buf+6, subtype);
|
||||||
put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
|
put_u32(buf+8, len - MRT_HDR_LENGTH);
|
||||||
|
|
||||||
if (p->cf->global->mrtdump_file != -1)
|
if (file_descriptor >= 0)
|
||||||
write(p->cf->global->mrtdump_file, buf, len);
|
write(file_descriptor, buf, len);
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,12 @@ tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, uns
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bird_clock_t
|
||||||
|
bird_clock_to_unix_timestamp(bird_clock_t bird_clock)
|
||||||
|
{
|
||||||
|
bird_clock_t delta = now - bird_clock;
|
||||||
|
return (now_real - delta);
|
||||||
|
}
|
||||||
|
|
||||||
struct timeformat {
|
struct timeformat {
|
||||||
char *fmt1, *fmt2;
|
char *fmt1, *fmt2;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#ifndef _BIRD_UNIX_H_
|
#ifndef _BIRD_UNIX_H_
|
||||||
#define _BIRD_UNIX_H_
|
#define _BIRD_UNIX_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
struct pool;
|
struct pool;
|
||||||
@ -103,9 +104,14 @@ void io_init(void);
|
|||||||
void io_loop(void);
|
void io_loop(void);
|
||||||
void io_log_dump(void);
|
void io_log_dump(void);
|
||||||
int sk_open_unix(struct birdsock *s, char *name);
|
int sk_open_unix(struct birdsock *s, char *name);
|
||||||
void *tracked_fopen(struct pool *, char *name, char *mode);
|
|
||||||
void test_old_bird(char *path);
|
void test_old_bird(char *path);
|
||||||
|
|
||||||
|
/* Tracked Files */
|
||||||
|
struct rfile {
|
||||||
|
resource r;
|
||||||
|
FILE *f;
|
||||||
|
};
|
||||||
|
struct rfile *tracked_fopen(struct pool *, const char *name, const char *mode);
|
||||||
|
|
||||||
/* krt.c bits */
|
/* krt.c bits */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user