From: Pavel TvrdĂ­k Date: Thu, 12 Nov 2015 12:07:04 +0000 (+0100) Subject: Integrate MRT Table Dump (RFC 6396) into BIRD X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6702b7ad7417bf52ab35102061919b1161204076;p=thirdparty%2Fbird.git Integrate MRT Table Dump (RFC 6396) into BIRD Asynchronous periodic mrt table dumps of routes configuration in bird.conf: mrtdump routes { [ filename ""; ] [ table |""; ] [ period ; ] [ filter |where ; ] } Synchronous mrt table dumps of routes in BIRD client: mrtdump routes [table |""] [to ""] [filter |where ] --- diff --git a/conf/conf.c b/conf/conf.c index 825a8e9f1..847360b40 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -96,7 +96,7 @@ config_alloc(byte *name) char *ndup = lp_allocu(l, 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->mem = l; c->file_name = ndup; diff --git a/conf/conf.h b/conf/conf.h index 89a2c5b71..4ca424424 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -12,8 +12,36 @@ #include "lib/resource.h" #include "lib/timer.h" +/* Configuration structures */ + +#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 structure */ +/* 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 { pool *pool; /* Pool the configuration is stored in */ @@ -21,9 +49,10 @@ struct config { list protos; /* Configured protocol instances (struct proto_config) */ list tables; /* Configured routing tables (struct rtable_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) */ struct rtable_config *master_rtc; /* Configuration of master routing table */ struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ diff --git a/nest/Makefile b/nest/Makefile index e69286684..4def57b8f 100644 --- a/nest/Makefile +++ b/nest/Makefile @@ -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 \ - a-path.c a-set.c + a-path.c a-set.c mrtdump.c root-rel=../ dir-name=nest diff --git a/nest/config.Y b/nest/config.Y index 799a09f90..9e214247d 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -23,6 +23,7 @@ static struct roa_table_config *this_roa_table; static list *this_p_list; static struct password_item *this_p_item; static int password_id; +static struct mrt_table_config *this_mrt_table_config; static 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(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) 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, RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) @@ -80,6 +81,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID) %type 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 proto_patt proto_patt2 %type limit_spec +%type mrtdump_table_config_table_option CF_GRAMMAR @@ -371,7 +373,7 @@ debug_flag: | PACKETS { $$ = D_PACKETS; } ; -/* MRTDump flags */ +/* MRTDump Protocol flags */ mrtdump_mask: ALL { $$ = ~0; } @@ -389,6 +391,50 @@ mrtdump_flag: | 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_list: @@ -697,6 +743,30 @@ CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]]) CF_CLI(MRTDUMP, proto_patt mrtdump_mask, ( | | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) { proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ; +CF_CLI_HELP(MRTDUMP ROUTES, [table |\"\"] [to \"\"] [filter |where ] , [[Save MRT Table Dump into a file]]) +CF_CLI(MRTDUMP ROUTES, mrtdump_table_cli_config, [table |\"\"] [to \"\"] [filter |where ], [[Save mrt table dump v2 of table name 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]]) { this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ; diff --git a/nest/mrtdump.c b/nest/mrtdump.c new file mode 100644 index 000000000..515a7c4dc --- /dev/null +++ b/nest/mrtdump.c @@ -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"); +} diff --git a/nest/mrtdump.h b/nest/mrtdump.h index 739325537..d3b134932 100644 --- a/nest/mrtdump.h +++ b/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. */ -#ifndef MRTDUMP_H -#define MRTDUMP_H +#ifndef _BIRD_MRTDUMP_H_ +#define _BIRD_MRTDUMP_H_ + +#include + #include "nest/protocol.h" +#include "lib/lists.h" +#include "nest/route.h" +#include "lib/event.h" + +#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 MRT_PEER_TYPE_IPV6 1 /* MRT Table Dump: Peer Index Table: Peer Type: Use IPv6 IP Address */ -/* MRTDump values */ +#ifdef PATH_MAX +#define BIRD_PATH_MAX PATH_MAX +#else +#define BIRD_PATH_MAX 4096 +#endif -#define MRTDUMP_HDR_LENGTH 12 +/* MRT Types */ +#define MRT_TABLE_DUMP_V2 13 +#define MRT_BGP4MP 16 -/* MRTdump types */ +/* 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 -#define BGP4MP 16 +/* MRT BGP4MP Subtypes */ +#define MRT_BGP4MP_MESSAGE 1 +#define MRT_BGP4MP_MESSAGE_AS4 4 +#define MRT_BGP4MP_STATE_CHANGE_AS4 5 -/* MRTdump subtypes */ +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 */ +}; -#define BGP4MP_MESSAGE 1 -#define BGP4MP_MESSAGE_AS4 4 -#define BGP4MP_STATE_CHANGE_AS4 5 +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 */ +}; -/* implemented in sysdep */ -void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len); +struct mrt_rib_entry +{ + u16 peer_index; + u32 originated_time; + u16 attributes_length; + byte *attributes; /* encoded BGP attributes */ +}; -#endif +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_ */ diff --git a/nest/route.h b/nest/route.h index c435b9e07..c853036c2 100644 --- a/nest/route.h +++ b/nest/route.h @@ -129,6 +129,7 @@ struct rtable_config { int gc_max_ops; /* Maximum number of operations before GC is run */ int gc_min_time; /* Minimum time between two consecutive GC runs */ 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 { @@ -631,5 +632,13 @@ void roa_preconfig(struct config *c); void roa_commit(struct config *new, struct config *old); 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 diff --git a/nest/rt-table.c b/nest/rt-table.c index 57c8b8e08..76d6c13d4 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -28,6 +28,10 @@ * routes in order to conserve memory. */ +#include +#include +#include + #undef LOCAL_DEBUG #include "nest/bird.h" @@ -35,6 +39,7 @@ #include "nest/protocol.h" #include "nest/cli.h" #include "nest/iface.h" +#include "nest/mrtdump.h" #include "lib/resource.h" #include "lib/event.h" #include "lib/string.h" @@ -42,6 +47,9 @@ #include "filter/filter.h" #include "lib/string.h" #include "lib/alloca.h" +#include "lib/unix.h" + +#include "proto/bgp/mrt.h" 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 void rt_schedule_gc(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 * make_tmp_attrs(struct rte *rt, struct linpool *pool) @@ -1661,6 +1670,8 @@ rt_preconfig(struct config *c) init_list(&c->tables); 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); c->gc_max_ops = 1000; c->gc_min_time = 5; + + init_list(&c->mrt_table_dumps); + return c; } @@ -1896,6 +1910,7 @@ rt_commit(struct config *new, struct config *old) WALK_LIST(o, old->tables) { rtable *ot = o->table; + mrt_table_dump_stop_periodic(ot); if (!ot->deleted) { 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) + { if (!r->table) { 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); r->table = t; } + mrt_table_dump_init_periodic(r->table, &new->mrt_table_dumps); + } 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 */ diff --git a/proto/bgp/Makefile b/proto/bgp/Makefile index a634cf0de..30f87c5b9 100644 --- a/proto/bgp/Makefile +++ b/proto/bgp/Makefile @@ -1,4 +1,4 @@ -source=bgp.c attrs.c packets.c +source=bgp.c attrs.c packets.c mrt.c root-rel=../../ dir-name=proto/bgp diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f549b0ed9..5723f8f30 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -75,8 +75,10 @@ #include "lib/socket.h" #include "lib/resource.h" #include "lib/string.h" +#include "lib/slists.h" #include "bgp.h" +#include "mrt.h" struct linpool *bgp_linpool; /* Global temporary pool */ @@ -1261,6 +1263,7 @@ bgp_init(struct proto_config *C) p->rs_client = c->rs_client; p->rr_client = c->rr_client; p->igp_table = get_igp_table(c); + p->mrt_peer_index = 0; return P; } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 274794f13..f64d8a15a 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -155,6 +155,7 @@ struct bgp_proto { u8 last_error_class; /* Error class of last error */ u32 last_error_code; /* Error code of last error. BGP protocol errors are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ + u16 mrt_peer_index; /* Used for MRT Table Dump */ #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; @@ -189,6 +190,7 @@ struct bgp_bucket { #define BGP_TX_BUFFER_SIZE 4096 #define BGP_RX_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) { return p->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; } diff --git a/proto/bgp/mrt.c b/proto/bgp/mrt.c new file mode 100644 index 000000000..d4f8a434f --- /dev/null +++ b/proto/bgp/mrt.c @@ -0,0 +1,134 @@ +#include +#include +#include + +#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; +} diff --git a/proto/bgp/mrt.h b/proto/bgp/mrt.h new file mode 100644 index 000000000..fdaa9e642 --- /dev/null +++ b/proto/bgp/mrt.h @@ -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_ */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ed99f6236..5caa356fe 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -85,14 +85,13 @@ static void mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len) { 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; bp = mrt_put_bgp4_hdr(bp, conn, as4); memcpy(bp, pkt, len); bp += len; - mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE, - buf, bp-buf); + mrt_dump_message_proto(&conn->bgp->p, MRT_BGP4MP, as4 ? MRT_BGP4MP_MESSAGE_AS4 : MRT_BGP4MP_MESSAGE, buf, bp-buf); } static inline u16 @@ -106,13 +105,13 @@ void mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new) { byte buf[128]; - byte *bp = buf + MRTDUMP_HDR_LENGTH; + byte *bp = buf + MRT_HDR_LENGTH; bp = mrt_put_bgp4_hdr(bp, conn, 1); put_u16(bp+0, convert_state(old)); put_u16(bp+2, convert_state(new)); 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 * diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y index d6ab8cab7..4b893e1ba 100644 --- a/sysdep/unix/config.Y +++ b/sysdep/unix/config.Y @@ -42,9 +42,9 @@ syslog_name: log_file: text { - FILE *f = tracked_fopen(new_config->pool, $1, "a"); - if (!f) cf_error("Unable to open log file `%s': %m", $1); - $$ = f; + struct rfile *rf = tracked_fopen(new_config->pool, $1, "a"); + if (!rf) cf_error("Unable to open log file `%s': %m", $1); + $$ = rf->f; } | SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; } | STDERR { $$ = stderr; } @@ -77,14 +77,14 @@ CF_ADDTO(conf, mrtdump_base) mrtdump_base: 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 ';' { - FILE *f = tracked_fopen(new_config->pool, $2, "a"); - if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2); - new_config->mrtdump_file = fileno(f); + struct rfile *rf = tracked_fopen(new_config->pool, $2, "a"); + if (!rf) cf_error("Unable to open MRTDump file '%s': %m", $2); + new_config->mrt_proto_file = fileno(rf->f); } ; - CF_ADDTO(conf, timeformat_base) timeformat_which: diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index b636e7997..da330122d 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -55,11 +55,6 @@ * Tracked Files */ -struct rfile { - resource r; - FILE *f; -}; - static void rf_free(resource *r) { @@ -85,17 +80,17 @@ static struct resclass rf_class = { NULL }; -void * -tracked_fopen(pool *p, char *name, char *mode) +struct rfile * +tracked_fopen(pool *p, const char *name, const char *mode) { FILE *f = fopen(name, mode); - if (f) - { - struct rfile *r = ralloc(p, &rf_class); - r->f = f; - } - return f; + if (!f) + return NULL; + + struct rfile *r = ralloc(p, &rf_class); + r->f = f; + return r; } /** diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 7cb26360a..e04947322 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -316,14 +316,20 @@ log_init_debug(char *f) } 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 */ put_u32(buf+0, now_real); put_u16(buf+4, type); 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) - write(p->cf->global->mrtdump_file, buf, len); + if (file_descriptor >= 0) + write(file_descriptor, buf, len); } diff --git a/sysdep/unix/timer.h b/sysdep/unix/timer.h index 99d439328..8c7dd6cf5 100644 --- a/sysdep/unix/timer.h +++ b/sysdep/unix/timer.h @@ -64,6 +64,12 @@ tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, uns 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 { char *fmt1, *fmt2; diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 4e0ff8411..4e3f78ac8 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -9,6 +9,7 @@ #ifndef _BIRD_UNIX_H_ #define _BIRD_UNIX_H_ +#include #include struct pool; @@ -103,9 +104,14 @@ void io_init(void); void io_loop(void); void io_log_dump(void); int sk_open_unix(struct birdsock *s, char *name); -void *tracked_fopen(struct pool *, char *name, char *mode); 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 */