From f23f014ef3da3082bbee5474ecd1263bfa9952f6 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 23 Feb 2021 23:54:13 +0100 Subject: [PATCH] Kernel protocol now uses out_table resync mechanism for periodic scanning --- nest/proto.c | 10 ++++ nest/protocol.h | 2 + nest/route.h | 6 ++- nest/rt-table.c | 80 ++++++++++++++++++++++++++++-- sysdep/unix/krt.c | 121 +++++++--------------------------------------- sysdep/unix/krt.h | 2 +- 6 files changed, 112 insertions(+), 109 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 2ffb897c..945524a1 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -542,8 +542,12 @@ channel_reset_import(struct channel *c) static void channel_reset_export(struct channel *c) { + if (c->out_flush_refeed) + rt_out_flush(c); + /* Just free the routes */ rt_prune_sync(c->out_table, 1); + bmap_reset(&c->out_seen_map, 1024); } /* Called by protocol to activate in_table */ @@ -584,6 +588,10 @@ channel_do_start(struct channel *c) bmap_init(&c->export_map, c->proto->pool, 1024); bmap_init(&c->export_reject_map, c->proto->pool, 1024); + + if (c->out_table) + bmap_init(&c->out_seen_map, c->proto->pool, 1024); + memset(&c->stats, 0, sizeof(struct proto_stats)); channel_reset_limit(&c->rx_limit); @@ -618,6 +626,8 @@ channel_do_flush(struct channel *c) /* This have to be done in here, as channel pool is freed before channel_do_down() */ bmap_free(&c->export_map); bmap_free(&c->export_reject_map); + if (c->out_table) + bmap_free(&c->out_seen_map); c->in_table = NULL; c->reload_event = NULL; c->out_table = NULL; diff --git a/nest/protocol.h b/nest/protocol.h index cb368ac3..fd7d532d 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -509,6 +509,7 @@ struct channel { const struct filter *out_filter; /* Output filter */ struct bmap export_map; /* Keeps track which routes were really exported */ struct bmap export_reject_map; /* Keeps track which routes were rejected by export filter */ + struct bmap out_seen_map; /* Keeps track which routes have been seen by out_sync */ struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */ struct channel_limit in_limit; /* Input limit */ struct channel_limit out_limit; /* Output limit */ @@ -546,6 +547,7 @@ struct channel { u8 reload_pending; /* Reloading and another reload is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */ u8 rpki_reload; /* RPKI changes trigger channel reload */ + u8 out_flush_refeed; /* Feed by withdrawals on export reset */ list net_feed; /* Active net feeders (struct channel_net_feed) */ diff --git a/nest/route.h b/nest/route.h index 41765638..d89b2f59 100644 --- a/nest/route.h +++ b/nest/route.h @@ -367,8 +367,12 @@ void rt_feed_channel_abort(struct channel *c); int rt_reload_channel(struct channel *c); void rt_reload_channel_abort(struct channel *c); void rt_prune_sync(rtable *t, int all); -int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, int refeed); +int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed); struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); +void rt_out_sync_start(struct channel *c); +_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e); +void rt_out_sync_finish(struct channel *c); +void rt_out_flush(struct channel *c); /* Default limit for ECMP next hops, defined in sysdep code */ diff --git a/nest/rt-table.c b/nest/rt-table.c index d5f05822..3c868f99 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -691,7 +691,7 @@ rt_notify_merged(struct channel *c, struct rte_export_internal *e) /* Prepare new merged route */ if (e->new_best) { - ep->new_id = e->new->id; + ep->new_id = e->new_best->id; if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0)) ep->new.attrs = NULL; } @@ -774,7 +774,7 @@ rte_export_store(struct channel *c, struct rte_export_internal *e) /* Apply export table */ if (c->out_table) { - if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->refeed)) + if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->pub.new_id, e->refeed)) return 0; } else if (c->out_filter != FILTER_ACCEPT) @@ -2471,7 +2471,7 @@ rt_prune_sync(rtable *t, int all) */ int -rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, int refeed) +rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed) { struct rtable *tab = c->out_table; struct rte_storage **pos; @@ -2533,6 +2533,7 @@ rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_s struct rte_storage *e = rte_store(new, net); e->sender = c; e->lastmod = current_time(); + e->id = id; e->next = *pos; *pos = e; tab->rt_count++; @@ -2545,6 +2546,79 @@ drop_withdraw: return 0; } +void +rt_out_sync_start(struct channel *c) +{ + ASSERT_DIE(c->out_table); + ASSERT_DIE(c->ra_mode != RA_ANY); + bmap_reset(&c->out_seen_map, 1024); +} + +_Bool +rt_out_sync_mark(struct channel *c, struct rte_export *e) +{ + ASSERT_DIE(c->out_table); + ASSERT_DIE(c->ra_mode != RA_ANY); + + net *n = net_find(c->out_table, e->old.net); + if (!n || !n->routes) + return 1; + + e->new = rte_copy(n->routes); + e->new_id = n->routes->id; + + if (bmap_test(&c->out_seen_map, n->routes->id)) + return 0; + + bmap_set(&c->out_seen_map, n->routes->id); + return 1; +} + +void +rt_out_sync_finish(struct channel *c) +{ + ASSERT_DIE(c->out_table); + ASSERT_DIE(c->ra_mode != RA_ANY); + + FIB_WALK(&c->out_table->fib, net, n) + { + if (!n->routes) + continue; + + if (!bmap_test(&c->out_seen_map, n->routes->id)) + { + struct rte_export ex = { + .new_id = n->routes->id, + .new = rte_copy(n->routes), + }; + + c->proto->rt_notify(c, &ex); + } + } + FIB_WALK_END; + bmap_reset(&c->out_seen_map, 1024); +} + +void +rt_out_flush(struct channel *c) +{ + ASSERT_DIE(c->out_table); + ASSERT_DIE(c->ra_mode != RA_ANY); + + FIB_WALK(&c->out_table->fib, net, n) + { + if (!n->routes) + continue; + + struct rte_export ex = { + .old_id = n->routes->id, + .old = rte_copy(n->routes), + }; + + c->proto->rt_notify(c, &ex); + } + FIB_WALK_END; +} /* * Hostcache diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index c4c74e13..38d87444 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -68,14 +68,12 @@ */ pool *krt_pool; -static linpool *krt_filter_lp; static list krt_proto_list; void krt_io_init(void) { krt_pool = rp_new(&root_pool, "Kernel Syncer"); - krt_filter_lp = lp_new_default(krt_pool); init_list(&krt_proto_list); krt_sys_io_init(); } @@ -538,61 +536,6 @@ krt_dump(struct proto *P) * Routes */ -static inline int -krt_is_installed(struct krt_proto *p, net *n) -{ - return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id); -} - -static void -krt_flush_routes(struct krt_proto *p) -{ - struct rtable *t = p->p.main_channel->table; - - KRT_TRACE(p, D_EVENTS, "Flushing kernel routes"); - FIB_WALK(&t->fib, net, n) - { - if (krt_is_installed(p, n)) - { - struct rte_export e = { - .old = rte_copy(n->routes), - .old_id = n->routes->id, - }; - - /* FIXME: this does not work if gw is changed in export filter */ - krt_replace_rte(p, &e); - } - } - FIB_WALK_END; -} - -static _Bool -krt_export_net(struct krt_proto *p, net *net, rte *rt) -{ - struct channel *c = p->p.main_channel; - const struct filter *filter = c->out_filter; - - if (c->ra_mode == RA_MERGED) - return rt_export_merged(c, net, rt, krt_filter_lp, 1); - - if (!rte_is_valid(net->routes)) - return 0; - - if (filter == FILTER_REJECT) - return 0; - - /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */ - *rt = rte_copy(net->routes); - - if (filter == FILTER_ACCEPT) - return 1; - - if (f_run(filter, rt, krt_filter_lp, FF_SILENT) > F_ACCEPT) - return 0; - - return 1; -} - static int krt_same_dest(rte *k, rte *e) { @@ -644,24 +587,14 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src) if (!p->ready) goto ignore; - net *n = net_find(p->p.main_channel->table, e->net); - - if (!n || !krt_is_installed(p, n)) - goto delete; - - /* Rejected by filters */ - if (!krt_export_net(p, n, &ex.new)) - goto delete; - - /* Route to this destination was already seen. Strange, but it happens... */ - if (bmap_test(&p->seen_map, n->routes->id)) + if (!rt_out_sync_mark(p->p.main_channel, &ex)) goto aseen; - /* Mark route as seen */ - bmap_set(&p->seen_map, n->routes->id); + if (!ex.new.attrs) + goto delete; /* TODO: There also may be changes in route eattrs, we ignore that for now. */ - if (!bmap_test(&p->sync_map, n->routes->id) || !krt_same_dest(e, &ex.new)) + if (!bmap_test(&p->sync_map, ex.new_id) || !krt_same_dest(e, &ex.new)) goto update; goto seen; @@ -680,7 +613,6 @@ ignore: update: krt_trace_in(p, &ex.new, "updating"); - ex.new_id = n->routes->id; krt_replace_rte(p, &ex); goto done; @@ -690,39 +622,23 @@ delete: goto done; done: - lp_flush(krt_filter_lp); + return; } static void krt_init_scan(struct krt_proto *p) { - bmap_reset(&p->seen_map, 1024); + rt_out_sync_start(p->p.main_channel); } static void krt_prune(struct krt_proto *p) { - struct rtable *t = p->p.main_channel->table; + KRT_TRACE(p, D_EVENTS, "Sync finished, pruning table %s", p->p.main_channel->table->name); - KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name); - FIB_WALK(&t->fib, net, n) - { - if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id)) - { - struct rte_export ex = { - .new_id = n->routes->id - }; - - if (krt_export_net(p, n, &ex.new)) - { - krt_trace_in(p, &ex.new, "installing"); - krt_replace_rte(p, &ex); - } - - lp_flush(krt_filter_lp); - } - } - FIB_WALK_END; + p->pruning = 1; + rt_out_sync_finish(p->p.main_channel); + p->pruning = 0; #ifdef KRT_ALLOW_LEARN if (KRT_CF->learn) @@ -897,7 +813,7 @@ krt_rt_notify(struct channel *ch, struct rte_export *e) return; #endif - if (p->initialized) /* Before first scan we don't touch the routes */ + if (p->initialized || p->ready && p->pruning) /* Before first scan we don't touch the routes */ krt_replace_rte(p, e); } @@ -994,6 +910,7 @@ krt_init(struct proto_config *CF) // struct krt_config *cf = (void *) CF; p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF)); + p->p.main_channel->out_flush_refeed = 1; p->p.preexport = krt_preexport; p->p.rt_notify = krt_rt_notify; @@ -1022,12 +939,11 @@ krt_start(struct proto *P) } /* If it is needed, setup out table automagically */ - if (!TRIVIAL_FILTER(p->p.main_channel->out_filter)) + /* For now, setup out table always. + if (!TRIVIAL_FILTER(p->p.main_channel->out_filter)) */ channel_setup_out_table(p->p.main_channel); - bmap_init(&p->sync_map, p->p.pool, 1024); - bmap_init(&p->seen_map, p->p.pool, 1024); add_tail(&krt_proto_list, &p->krt_node); #ifdef KRT_ALLOW_LEARN @@ -1057,7 +973,7 @@ krt_shutdown(struct proto *P) /* FIXME we should flush routes even when persist during reconfiguration */ if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN)) - krt_flush_routes(p); + rt_out_flush(p->p.main_channel); p->ready = 0; p->initialized = 0; @@ -1073,12 +989,9 @@ krt_shutdown(struct proto *P) } static int -krt_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed UNUSED, int *export_changed) +krt_channel_reconfigure(struct channel *C UNUSED, struct channel_config *CC UNUSED, int *import_changed UNUSED, int *export_changed) { - if (!*export_changed) - return 1; - - return (TRIVIAL_FILTER(C->out_filter) == TRIVIAL_FILTER(CC->out_filter)); + return !*export_changed; } static int diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index a0c60d80..bdb5af7c 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -60,11 +60,11 @@ struct krt_proto { #endif struct bmap sync_map; /* Keeps track which exported routes were successfully written to kernel */ - struct bmap seen_map; /* Routes seen during last periodic scan */ node krt_node; /* Node in krt_proto_list */ byte af; /* Kernel address family (AF_*) */ byte ready; /* Initial feed has been finished */ byte initialized; /* First scan has been finished */ + byte pruning; /* Pruning */ byte reload; /* Next scan is doing reload */ };