From: Katerina Kubecova Date: Fri, 27 Sep 2024 11:58:46 +0000 (+0200) Subject: MRT: buildable and running again for BIRD 3 X-Git-Tag: v3.0.0~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc69284f61b400bb263cdbadf6c97b09d0a770b3;p=thirdparty%2Fbird.git MRT: buildable and running again for BIRD 3 Tests for MRT are scarce and not automated for now, so it may behave weirdly in corner cases. --- diff --git a/configure.ac b/configure.ac index ae8c81f79..9c8092014 100644 --- a/configure.ac +++ b/configure.ac @@ -320,8 +320,7 @@ else AC_DEFINE([HAVE_CLOCK_MONOTONIC_COARSE], [1], [Define to 1 if coarse clock is available]) fi -# temporarily removed "mrt" from all_protocols to speed up 3.0-alpha1 release -all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static" +all_protocols="aggregator bfd babel bgp l3vpn ospf pipe radv rip rpki static mrt" all_protocols=`echo $all_protocols | sed 's/ /,/g'` if test "$with_protocols" = all ; then diff --git a/nest/route.h b/nest/route.h index 720899296..ddcb9a851 100644 --- a/nest/route.h +++ b/nest/route.h @@ -125,7 +125,7 @@ struct rt_export_request { /* Table feeding contraption */ struct rt_export_feeder { /* Formal name */ - char *name; + const char *name; /* Enlisting */ struct rt_exporter * _Atomic exporter; diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index d293a71b2..3dba149e5 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1433,7 +1433,10 @@ static inline int bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size) { const union bgp_attr_desc *desc = bgp_find_attr_desc(a); - ASSERT_DIE(desc); + if (s->ignore_non_bgp_attrs == 0) + ASSERT_DIE(desc); + else if (desc == NULL) + return 0; return desc->encode(s, a, buf, size); } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index e6db1114f..2e38a29a6 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -513,6 +513,7 @@ struct bgp_write_state { int as4_session; int add_path; int mpls; + int ignore_non_bgp_attrs; eattr *mp_next_hop; const adata *mpls_labels; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 401e2814f..49d9e71df 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -145,7 +145,7 @@ bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len) d.msg_len = len; d.add_path = bgp_estimate_add_path(conn->bgp, pkt, len); - mrt_dump_bgp_message(&d); + mrt_dump_bgp_message(&d, conn->bgp->p.pool); } void @@ -157,7 +157,7 @@ bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new) d.old_state = old; d.new_state = new; - mrt_dump_bgp_state_change(&d); + mrt_dump_bgp_state_change(&d, conn->bgp->p.pool); } static byte * diff --git a/proto/mrt/config.Y b/proto/mrt/config.Y index d2136ed16..78a14dd97 100644 --- a/proto/mrt/config.Y +++ b/proto/mrt/config.Y @@ -28,6 +28,7 @@ proto: mrt_proto ; mrt_proto_start: proto_start MRT { this_proto = proto_config_new(&proto_mrt, $1); + this_proto->loop_order = DOMAIN_ORDER(proto); }; mrt_proto_item: diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index a1b53adfc..bab2dc301 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -38,6 +38,7 @@ * - RFC 6396 - MRT format standard * - RFC 8050 - ADD_PATH extension */ +#include #include #include @@ -45,10 +46,13 @@ #include "mrt.h" +#include "lib/io-loop.h" #include "nest/cli.h" #include "filter/filter.h" #include "proto/bgp/bgp.h" #include "sysdep/unix/unix.h" +#include "sysdep/unix/io-loop.h" +#include "conf/conf.h" #ifdef PATH_MAX @@ -65,6 +69,7 @@ log(L_ERR "%s: " msg, s->proto->p.name, ## args); \ }) +extern proto_state_table proto_state_table_pub; /* * MRT buffer code @@ -78,6 +83,13 @@ mrt_buffer_init(buffer *b, pool *pool, size_t n) b->end = b->start + n; } +static void +mrt_buffer_free(buffer *b) +{ + mb_free(b->start); + b->start = b->pos = b->end = NULL; +} + static void mrt_buffer_grow(buffer *b, size_t n) { @@ -216,46 +228,6 @@ bstrsub(char *dst, size_t n, const char *src, const char *key, const char *val) return 1; } -static inline rtable * -mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern) -{ - /* Handle explicit table, return it in the first pass */ - if (tab_ptr) - return !tab ? tab_ptr : NULL; - - /* Walk routing_tables list, starting after tab (if non-NULL) */ - for (node *tn = tab ? tab->n.next : HEAD(routing_tables); - NODE_VALID(tn); - tn = tn->next) - { - tab = SKIP_BACK(rtable, n, tn); - if (patmatch(pattern, tab->name) && - ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6))) - return tab; - } - - return NULL; -} - -static rtable * -mrt_next_table(struct mrt_table_dump_state *s) -{ - rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr); - - if (s->table) - RT_LOCKED(s->table, tab) - rt_unlock_table(tab); - - s->table = tab; - s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0; - - if (s->table) - RT_LOCKED(s->table, tab) - rt_lock_table(tab); - - return s->table; -} - static int mrt_open_file(struct mrt_table_dump_state *s) { @@ -263,15 +235,16 @@ mrt_open_file(struct mrt_table_dump_state *s) char name[BIRD_PATH_MAX]; btime now = current_time(); btime now_real = current_real_time(); + rtable *tab = s->table_list[s->table_cur]; - if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) || + if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", tab->name) || !tm_format_real_time(name, sizeof(name), fmt1, now_real)) { mrt_log(s, "Invalid filename '%s'", s->filename); return 0; } - s->file = rf_open(s->pool, name, "a"); + s->file = rf_open(s->pool, name, RF_APPEND, 0); if (!s->file) { mrt_log(s, "Unable to open MRT file '%s': %m", name); @@ -354,19 +327,33 @@ static void mrt_peer_table_dump(struct mrt_table_dump_state *s) { mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE); - mrt_peer_table_header(s, config->router_id, s->table->name); + mrt_peer_table_header(s, OBSREF_GET(config)->router_id, s->table_open->name); /* 0 is fake peer for non-BGP routes */ mrt_peer_table_entry(s, 0, 0, IPA_NONE); #ifdef CONFIG_BGP - struct proto *P; - WALK_LIST(P, proto_list) - if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN)) + PST_LOCKED(ts) + { + for(u32 i = 0; i < ts->length_states; i++) { - struct bgp_proto *p = (void *) P; - mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip); + ea_list *eal = ts->states[i]; + if (eal) + ea_free_later(ea_ref(eal)); + else + continue; + + struct protocol *type = (struct protocol *)ea_get_ptr(eal, &ea_protocol_type, 0); + int state = ea_get_int(eal, &ea_state, 0); + if ((type == &proto_bgp) && (state != PS_DOWN)) + { + int rem_id = ea_get_int(eal, &ea_bgp_rem_id, 0); + int rem_as = ea_get_int(eal, &ea_bgp_rem_as, 0); + ip_addr *rem_ip = (ip_addr *)ea_get_adata(eal, &ea_bgp_rem_ip)->data; + mrt_peer_table_entry(s, rem_id, rem_as, *rem_ip); + } } + } #endif /* Fix Peer Count */ @@ -388,7 +375,7 @@ mrt_peer_table_flush(struct mrt_table_dump_state *s) */ static void -mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n) +mrt_rib_table_header(struct mrt_table_dump_state *s, const net_addr *n) { buffer *b = &s->buf; @@ -432,7 +419,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r) return; /* Attribute list must be normalized for bgp_encode_attrs() */ - if (!rta_is_cached(r->attrs)) + if (!r->attrs->stored) eattrs = ea_normalize(eattrs, 0); mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE); @@ -440,6 +427,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r) s->bws->mp_reach = !s->ipv4; s->bws->mp_next_hop = NULL; + s->bws->ignore_non_bgp_attrs = 1; /* Encode BGP attributes */ int len = bgp_encode_attrs(s->bws, eattrs, pos, b->end); @@ -503,7 +491,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r) } static void -mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) +mrt_rib_table_dump(struct mrt_table_dump_state *s, const struct rt_export_feed *feed, int add_path) { s->add_path = s->bws->add_path = add_path; @@ -512,23 +500,23 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) (!add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH); mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype); - mrt_rib_table_header(s, n->n.addr); + mrt_rib_table_header(s, feed->block[0].net); - for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next) + for (uint i = 0; i < feed->count_routes; i++) { - if (rte_is_filtered(&rt->rte)) + rte *rte = &feed->block[i]; + if (rte_is_filtered(rte)) continue; /* Skip routes that should be reported in the other phase */ - if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path)) + if (!s->always_add_path && (!rte->src->private_id != !s->add_path)) { s->want_add_path = 1; continue; } - rte e = rt->rte; - if (f_run(s->filter, &e, 0) <= F_ACCEPT) - mrt_rib_table_entry(s, &e); + if (f_run(s->filter, rte, 0) <= F_ACCEPT) + mrt_rib_table_entry(s, rte); lp_flush(s->linpool); } @@ -547,25 +535,80 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) mrt_dump_message(&s->buf, s->fd); } +/* + * MRT Table Dump: table lists + */ + +static uint +mrt_get_table_list(pool *p, const char *pattern, rtable ***tl) +{ + ASSERT_DIE(the_bird_locked()); + + rtable *tab; + node *n; + + /* + * CAVEAT directly accessing tab->priv.deleted; this is safe due to + * the_bird_locked(), and this value changes only from the main loop. + * But this is a fragile piece of code which may need some rethinking + * later on. + */ + + uint count = 0; + WALK_LIST2(tab, n, routing_tables, n) + if (!OBSREF_GET(tab->priv.deleted) && + patmatch(pattern, tab->name) && + ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6))) + count++; + + *tl = mb_alloc(p, sizeof **tl * count); + + uint pos = 0; + WALK_LIST2(tab, n, routing_tables, n) + if (!OBSREF_GET(tab->priv.deleted) && + patmatch(pattern, tab->name) && + ((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6))) + { + (*tl)[pos++] = tab; + rt_lock_table(tab); + } + + ASSERT_DIE(pos == count); + return pos; +} + +static void +mrt_free_table_list(rtable **tl, int len) +{ + for (int i=0; idomain, "MRT Table Dump"); + struct mrt_table_dump_state *s = mb_allocz(pool, sizeof *s); s->pool = pool; s->linpool = lp_new(pool); s->peer_lp = lp_new(pool); mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE); + s->feeder = (struct rt_export_feeder) { + .name = name, + }; + /* We lock the current config as we may reference it indirectly by filter */ - s->config = config; - config_add_obstacle(s->config); + + OBSREF_SET(s->config, OBSREF_GET(config)); s->fd = -1; @@ -575,28 +618,20 @@ mrt_table_dump_init(pool *pp) static void mrt_table_dump_free(struct mrt_table_dump_state *s) { - if (s->table) - RT_LOCKED(s->table, tab) - { - if (s->table_open) - FIB_ITERATE_UNLINK(&s->fit, &tab->fib); - - rt_unlock_table(tab); - } - - if (s->table_ptr) - RT_LOCKED(s->table_ptr, tab) - rt_unlock_table(tab); + OBSREF_CLEAR(s->config); - config_del_obstacle(s->config); + if (s->table_open) + RT_LOCKED(s->table_open, tab) + rt_feeder_unsubscribe(&s->feeder); rp_free(s->pool); } -static int -mrt_table_dump_step(struct mrt_table_dump_state *s) +static void +mrt_table_dump_step(void *_s) { + struct mrt_table_dump_state *s = _s; struct bgp_write_state bws = { .as4_session = 1 }; s->max = 2048; @@ -605,49 +640,49 @@ mrt_table_dump_step(struct mrt_table_dump_state *s) if (s->table_open) goto step; - while (mrt_next_table(s)) + while (++s->table_cur < s->table_end) { if (!mrt_open_file(s)) continue; - mrt_peer_table_dump(s); + s->table_open = s->table_list[s->table_cur]; + s->ipv4 = (s->table_open->addr_type == NET_IP4); - RT_LOCKED(s->table, tab) - { + mrt_peer_table_dump(s); - FIB_ITERATE_INIT(&s->fit, &tab->fib); - s->table_open = 1; + RT_LOCKED(s->table_open, tab) + rt_feeder_subscribe(&tab->export_all, &s->feeder); - step: - FIB_ITERATE_START(&tab->fib, &s->fit, net, n) + step: ; + RT_FEED_WALK(&s->feeder, route_feed) { - if (s->max < 0) - { - FIB_ITERATE_PUT(&s->fit); - RT_RETURN(tab, 0); - } - /* With Always ADD_PATH option, we jump directly to second phase */ s->want_add_path = s->always_add_path; if (s->want_add_path == 0) - mrt_rib_table_dump(s, n, 0); + mrt_rib_table_dump(s, route_feed, 0); if (s->want_add_path == 1) - mrt_rib_table_dump(s, n, 1); - } - FIB_ITERATE_END; - s->table_open = 0; + mrt_rib_table_dump(s, route_feed, 1); + MAYBE_DEFER_TASK(s->target, s->event, + "MRT dump %s", s->feeder.name); } + RT_LOCKED(s->table_open, tab) + rt_feeder_unsubscribe(&s->feeder); + + s->table_open = NULL; + mrt_close_file(s); mrt_peer_table_flush(s); } - return 1; + CALL(s->cleanup, s); } +static void mrt_proto_dump_done(struct mrt_table_dump_state *s); + static void mrt_timer(timer *t) { @@ -662,44 +697,40 @@ mrt_timer(timer *t) TRACE(D_EVENTS, "RIB table dump started"); - struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool); + struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool, p->p.name); s->proto = p; - s->table_expr = cf->table_expr; - s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL; + s->table_list = p->table_list; + s->table_cur = -1; + s->table_end = p->table_list_len; s->filter = cf->filter; s->filename = cf->filename; s->always_add_path = cf->always_add_path; + s->cleanup = mrt_proto_dump_done; - if (s->table_ptr) - RT_LOCKED(s->table_ptr, tab) - rt_lock_table(tab); + s->event = ev_new_init(s->pool, mrt_table_dump_step, s); + s->target = proto_work_list(&p->p); p->table_dump = s; - ev_schedule(p->event); + ev_send_loop(p->p.loop, s->event); } static void -mrt_event(void *P) +mrt_proto_dump_done(struct mrt_table_dump_state *s) { - struct mrt_proto *p = P; - - if (!p->table_dump) - return; - - if (!mrt_table_dump_step(p->table_dump)) - { - ev_schedule(p->event); - return; - } + struct mrt_proto *p = s->proto; + ASSERT_DIE(p->table_dump == s); mrt_table_dump_free(p->table_dump); p->table_dump = NULL; TRACE(D_EVENTS, "RIB table dump done"); if (p->p.proto_state == PS_STOP) + { + mrt_free_table_list(p->table_list, p->table_list_len); proto_notify_state(&p->p, PS_DOWN); + } } @@ -708,24 +739,29 @@ mrt_event(void *P) */ static void -mrt_dump_cont(struct cli *c) +mrt_cli_dump_done(struct mrt_table_dump_state *s) { - if (!mrt_table_dump_step(c->rover)) - return; + struct cli *c = s->cli; + ASSERT_DIE(c->rover == c); cli_printf(c, 0, ""); - mrt_table_dump_free(c->rover); + mrt_table_dump_free(s); c->cont = NULL; c->cleanup = NULL; c->rover = NULL; } -static int +static void +mrt_dump_cont(struct cli *c) +{ + return mrt_table_dump_step(c->rover); +} + +void mrt_dump_cleanup(struct cli *c) { mrt_table_dump_free(c->rover); c->rover = NULL; - return 0; } void @@ -740,17 +776,33 @@ mrt_dump_cmd(struct mrt_dump_data *d) if (!d->filename) cf_error("File not specified"); - struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool); + struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool, "cli-mrt"); s->cli = this_cli; - s->table_expr = d->table_expr; - s->table_ptr = d->table_ptr; + + /* Either allocate single-pointer block or a full table list. + * We rather allocate the block anyway to make simpler cleanup, + * than to resolve corner cases in the end. + * + * This is the version for MRT requested from CLI */ + if (d->table_ptr) + { + s->table_end = 1; + s->table_list = mb_allocz(s->pool, sizeof *s->table_list); + s->table_list[0] = d->table_ptr; + rt_lock_table(s->table_list[0]); + } + else + s->table_end = mrt_get_table_list(s->pool, d->table_expr, &s->table_list); + + s->table_cur = -1; + s->filter = d->filter; s->filename = d->filename; - if (s->table_ptr) - RT_LOCKED(s->table_ptr, tab) - rt_lock_table(tab); + s->event = this_cli->event; + s->target = &global_work_list; + s->cleanup = mrt_cli_dump_done; this_cli->cont = mrt_dump_cont; this_cli->cleanup = mrt_dump_cleanup; @@ -763,14 +815,12 @@ mrt_dump_cmd(struct mrt_dump_data *d) */ static buffer * -mrt_bgp_buffer(void) +mrt_bgp_buffer(pool *p) { /* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */ - static buffer b; - - if (!b.start) - mrt_buffer_init(&b, &root_pool, 1024); + static _Thread_local buffer b; + mrt_buffer_init(&b, p, 1024); return &b; } @@ -804,7 +854,7 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d) } void -mrt_dump_bgp_message(struct mrt_bgp_data *d) +mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p) { const u16 subtypes[] = { MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4, @@ -813,15 +863,16 @@ mrt_dump_bgp_message(struct mrt_bgp_data *d) MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH, }; - buffer *b = mrt_bgp_buffer(); + buffer *b = mrt_bgp_buffer(p); mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]); mrt_bgp_header(b, d); mrt_put_data(b, d->message, d->msg_len); - mrt_dump_message(b, config->mrtdump_file); + mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file)); + mrt_buffer_free(b); } void -mrt_dump_bgp_state_change(struct mrt_bgp_data *d) +mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p) { /* Convert state from our BS_* values to values used in MRTDump */ const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1}; @@ -832,12 +883,13 @@ mrt_dump_bgp_state_change(struct mrt_bgp_data *d) /* Always use AS4 mode for STATE_CHANGE */ d->as4 = 1; - buffer *b = mrt_bgp_buffer(); + buffer *b = mrt_bgp_buffer(p); mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4); mrt_bgp_header(b, d); mrt_put_u16(b, states[d->old_state]); mrt_put_u16(b, states[d->new_state]); - mrt_dump_message(b, config->mrtdump_file); + mrt_dump_message(b, rf_fileno(OBSREF_GET(config)->mrtdump_file)); + mrt_buffer_free(b); } @@ -853,6 +905,9 @@ mrt_check_config(struct proto_config *CF) if (!cf->table_expr && !cf->table_cf) cf_error("Table not specified"); + if (cf->table_expr && cf->table_cf) + cf_error("Clashing table specifiers"); + if (!cf->filename) cf_error("File not specified"); @@ -860,6 +915,25 @@ mrt_check_config(struct proto_config *CF) cf_error("Period not specified"); } +static void +mrt_proto_get_table_list(struct mrt_proto *p, struct mrt_config *cf) +{ + /* Either allocate single-pointer block or a full table list. + * We rather allocate the block anyway to make simpler cleanup, + * than to resolve corner cases in the end. + * + * This is the version for MRT (pseudo)protocol */ + if (cf->table_cf) + { + p->table_list_len = 1; + p->table_list = mb_allocz(p->p.pool, sizeof *p->table_list); + p->table_list[0] = cf->table_cf->table; + rt_lock_table(p->table_list[0]); + } + else + p->table_list_len = mrt_get_table_list(p->p.pool, cf->table_expr, &p->table_list); +} + static struct proto * mrt_init(struct proto_config *CF) { @@ -875,9 +949,10 @@ mrt_start(struct proto *P) struct mrt_config *cf = (void *) (P->cf); p->timer = tm_new_init(P->pool, mrt_timer, p, cf->period S, 0); - p->event = ev_new_init(P->pool, mrt_event, p); - tm_start(p->timer, cf->period S); + tm_start_in(p->timer, cf->period S, p->p.loop); + + mrt_proto_get_table_list(p, cf); return PS_UP; } @@ -887,7 +962,11 @@ mrt_shutdown(struct proto *P) { struct mrt_proto *p = (void *) P; - return p->table_dump ? PS_STOP : PS_DOWN; + if (p->table_dump) + return PS_STOP; + + mrt_free_table_list(p->table_list, p->table_list_len); + return PS_DOWN; } static int @@ -904,9 +983,14 @@ mrt_reconfigure(struct proto *P, struct proto_config *CF) btime now = current_time(); btime new_time = p->timer->expires - (old->period S) + (new->period S); p->timer->recurrent = new->period S; - tm_set(p->timer, MAX(now, new_time)); + tm_set_in(p->timer, MAX(now, new_time), p->p.loop); } + if (!p->table_dump) + mrt_free_table_list(p->table_list, p->table_list_len); + + mrt_proto_get_table_list(p, new); + return 1; } diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h index 04865089d..b256ca9e9 100644 --- a/proto/mrt/mrt.h +++ b/proto/mrt/mrt.h @@ -36,6 +36,9 @@ struct mrt_proto { struct mrt_target *file; struct mrt_table_dump_state *table_dump; + + rtable **table_list; + int table_list_len; }; struct mrt_dump_data { @@ -56,11 +59,10 @@ struct mrt_peer_entry { struct mrt_table_dump_state { struct mrt_proto *proto; /* Protocol for regular MRT dumps (or NULL) */ struct cli *cli; /* CLI for irregular MRT dumps (or NULL) */ - struct config *config; /* Config valid during start of dump, locked */ + config_ref config; /* Config valid during start of dump, locked */ /* Configuration information */ - const char *table_expr; /* Wildcard for table name (or NULL) */ - rtable *table_ptr; /* Explicit table (or NULL) */ + struct rt_export_feeder feeder; /* Table feeder */ const struct filter *filter; /* Optional filter */ const char *filename; /* Filename pattern */ int always_add_path; /* Always use *_ADDPATH message subtypes */ @@ -73,9 +75,9 @@ struct mrt_table_dump_state { HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */ - rtable *table; /* Processed table, NULL initially */ - struct fib_iterator fit; /* Iterator in processed table */ - int table_open; /* Whether iterator is linked */ + rtable **table_list; /* List of tables to process */ + int table_cur, table_end; /* Table list iterator */ + rtable *table_open; /* Table to which the iterator is linked */ int ipv4; /* Processed table is IPv4 */ int add_path; /* Current message subtype is *_ADDPATH */ @@ -92,6 +94,11 @@ struct mrt_table_dump_state { struct rfile *file; /* tracking for mrt table dump file */ int fd; + + event *event; /* defer event */ + event_list *target; /* defer target */ + + void (*cleanup)(struct mrt_table_dump_state *); /* call when done */ }; struct mrt_bgp_data { @@ -147,12 +154,12 @@ struct mrt_bgp_data { #ifdef CONFIG_MRT void mrt_dump_cmd(struct mrt_dump_data *d); -void mrt_dump_bgp_message(struct mrt_bgp_data *d); -void mrt_dump_bgp_state_change(struct mrt_bgp_data *d); +void mrt_dump_bgp_message(struct mrt_bgp_data *d, pool *p); +void mrt_dump_bgp_state_change(struct mrt_bgp_data *d, pool *p); void mrt_check_config(struct proto_config *C); #else -static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { } -static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { } +static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { } +static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED, pool *p UNUSED) { } #endif #endif /* _BIRD_MRT_H_ */ diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 892044c5d..51de4a780 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -106,6 +106,12 @@ static struct resclass rf_class = { NULL }; +int +rf_fileno(struct rfile *f) +{ + return f->fd; +} + static int rf_open_get_fd(const char *name, enum rf_mode mode) { diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index 5e2144e41..e7c4c1436 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -126,6 +126,7 @@ off_t rf_size(struct rfile *); int rf_same(struct rfile *, struct rfile *); int rf_writev(struct rfile *, struct iovec *, int); void rf_write_crude(struct rfile *, const char *, int); +int rf_fileno(struct rfile *f); extern struct rfile rf_stderr;