diff options
Diffstat (limited to 'nest')
-rw-r--r-- | nest/config.Y | 6 | ||||
-rw-r--r-- | nest/proto.c | 8 | ||||
-rw-r--r-- | nest/protocol.h | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 89 | ||||
-rw-r--r-- | nest/rt.h | 3 |
5 files changed, 91 insertions, 17 deletions
diff --git a/nest/config.Y b/nest/config.Y index ea7e1266..c3f2532f 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -306,6 +306,12 @@ channel_item_: this_channel->table = $2; } | IMPORT imexport { this_channel->in_filter = $2; } + | EXPORT IN net_any imexport { + if (this_channel->net_type && ($3->type != this_channel->net_type)) + cf_error("Incompatible export prefilter type"); + this_channel->out_subprefix = $3; + this_channel->out_filter = $4; + } | EXPORT imexport { this_channel->out_filter = $2; } | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; } | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; } diff --git a/nest/proto.c b/nest/proto.c index 8513b9cb..3792fde4 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -214,6 +214,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf) c->in_filter = cf->in_filter; c->out_filter = cf->out_filter; + c->out_subprefix = cf->out_subprefix; channel_init_limit(c, &c->rx_limit, PLD_RX, &cf->rx_limit); channel_init_limit(c, &c->in_limit, PLD_IN, &cf->in_limit); @@ -467,6 +468,7 @@ channel_start_export(struct channel *c) c->out_req = (struct rt_export_request) { .name = rn, + .addr_in = c->out_subprefix, .trace_routes = c->debug | c->proto->debug, .dump_req = channel_dump_export_req, .log_state_change = channel_export_log_state_change, @@ -922,7 +924,10 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) /* FIXME: better handle these changes, also handle in_keep_filtered */ if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)) || - (cf->in_keep != c->in_keep)) + (cf->in_keep != c->in_keep) || + cf->out_subprefix && c->out_subprefix && + !net_equal(cf->out_subprefix, c->out_subprefix) || + (!cf->out_subprefix != !c->out_subprefix)) return 0; /* Note that filter_same() requires arguments in (new, old) order */ @@ -947,6 +952,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf) // c->ra_mode = cf->ra_mode; c->merge_limit = cf->merge_limit; c->preference = cf->preference; + c->out_req.addr_in = c->out_subprefix = cf->out_subprefix; c->debug = cf->debug; c->in_req.trace_routes = c->out_req.trace_routes = c->debug | c->proto->debug; c->rpki_reload = cf->rpki_reload; diff --git a/nest/protocol.h b/nest/protocol.h index b482ed99..a1701a7e 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -452,6 +452,7 @@ struct channel_config { struct proto_config *parent; /* Where channel is defined (proto or template) */ struct rtable_config *table; /* Table we're attached to */ const struct filter *in_filter, *out_filter; /* Attached filters */ + const net_addr *out_subprefix; /* Export only subprefixes of this net */ struct channel_limit rx_limit; /* Limit for receiving routes from protocol (relevant when in_keep & RIK_REJECTED) */ @@ -477,6 +478,7 @@ struct channel { struct rtable *table; const struct filter *in_filter; /* Input filter */ const struct filter *out_filter; /* Output filter */ + const net_addr *out_subprefix; /* Export only subprefixes of this net */ 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 */ diff --git a/nest/rt-table.c b/nest/rt-table.c index 14c80138..afafef62 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -126,7 +126,9 @@ static inline void rt_flowspec_resolve_rte(rte *r, struct channel *c); static inline void rt_prune_table(rtable *tab); static inline void rt_schedule_notify(rtable *tab); static void rt_flowspec_notify(rtable *tab, net *net); -static void rt_feed_channel(void *); +static void rt_feed_by_fib(void *); +static void rt_feed_by_trie(void *); +static uint rt_feed_net(struct rt_export_hook *c, net *n); const char *rt_import_state_name_array[TIS_MAX] = { [TIS_DOWN] = "DOWN", @@ -1187,6 +1189,9 @@ rte_announce(rtable *tab, net *net, struct rte_storage *new, struct rte_storage if (eh->export_state == TES_STOP) continue; + if (eh->req->addr_in && !net_in_netX(net->n.addr, eh->req->addr_in)) + continue; + if (new) eh->stats.updates_received++; else @@ -1768,13 +1773,21 @@ rt_table_export_start(struct rt_exporter *re, struct rt_export_request *req) hook->lp = lp_new_default(p); /* stats zeroed by mb_allocz */ - - FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); + if (tab->trie && req->addr_in && net_val_match(tab->addr_type, NB_IP)) + { + hook->walk_state = mb_allocz(p, sizeof (struct f_trie_walk_state)); + hook->walk_lock = rt_lock_trie(tab); + trie_walk_init(hook->walk_state, tab->trie, req->addr_in); + hook->event = ev_new_init(p, rt_feed_by_trie, hook); + } + else + { + FIB_ITERATE_INIT(&hook->feed_fit, &tab->fib); + hook->event = ev_new_init(p, rt_feed_by_fib, hook); + } DBG("New export hook %p req %p in table %s uc=%u\n", hook, req, tab->name, tab->use_count); - hook->event = ev_new_init(p, rt_feed_channel, hook); - return hook; } @@ -3154,7 +3167,7 @@ rt_commit(struct config *new, struct config *old) } /** - * rt_feed_channel - advertise all routes to a channel + * rt_feed_by_fib - advertise all routes to a channel by walking a fib * @c: channel to be fed * * This function performs one pass of advertisement of routes to a channel that @@ -3163,7 +3176,7 @@ rt_commit(struct config *new, struct config *old) * order not to monopolize CPU time.) */ static void -rt_feed_channel(void *data) +rt_feed_by_fib(void *data) { struct rt_export_hook *c = data; @@ -3183,9 +3196,55 @@ rt_feed_channel(void *data) return; } - if (c->export_state != TES_FEEDING) - goto done; + ASSERT(c->export_state == TES_FEEDING); + + if (!c->req->addr_in || net_in_netX(n->n.addr, c->req->addr_in)) + max_feed -= rt_feed_net(c, n); + } + FIB_ITERATE_END; + + rt_set_export_state(c, TES_READY); +} + +static void +rt_feed_by_trie(void *data) +{ + struct rt_export_hook *c = data; + rtable *tab = SKIP_BACK(rtable, exporter, c->table); + + ASSERT_DIE(c->walk_state); + struct f_trie_walk_state *ws = c->walk_state; + + int max_feed = 256; + + ASSERT_DIE(c->export_state == TES_FEEDING); + + net_addr addr; + while (trie_walk_next(ws, &addr)) + { + net *n = net_find(tab, &addr); + if (!n) + continue; + + if ((max_feed -= rt_feed_net(c, n)) <= 0) + return; + + ASSERT_DIE(c->export_state == TES_FEEDING); + } + rt_unlock_trie(tab, c->walk_lock); + c->walk_lock = NULL; + + mb_free(c->walk_state); + c->walk_state = NULL; + + rt_set_export_state(c, TES_READY); +} + + +static uint +rt_feed_net(struct rt_export_hook *c, net *n) +{ if (c->req->export_bulk) { uint count = rte_feed_count(n); @@ -3196,23 +3255,21 @@ rt_feed_channel(void *data) rte_feed_obtain(n, feed, count); struct rt_pending_export rpe = { .new_best = n->routes }; c->req->export_bulk(c->req, n->n.addr, &rpe, feed, count); - max_feed -= count; rte_update_unlock(); } + return count; } - else if (n->routes && rte_is_valid(&n->routes->rte)) + + if (n->routes && rte_is_valid(&n->routes->rte)) { rte_update_lock(); struct rt_pending_export rpe = { .new = n->routes, .new_best = n->routes }; c->req->export_one(c->req, n->n.addr, &rpe); - max_feed--; rte_update_unlock(); + return 1; } - } - FIB_ITERATE_END; -done: - rt_set_export_state(c, TES_READY); + return 0; } @@ -212,6 +212,7 @@ struct rt_pending_export { struct rt_export_request { struct rt_export_hook *hook; /* Table part of the export */ + const net_addr *addr_in; /* Subnet export request */ char *name; u8 trace_routes; @@ -245,6 +246,8 @@ struct rt_export_hook { } stats; struct fib_iterator feed_fit; /* Routing table iterator used during feeding */ + struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */ + struct f_trie *walk_lock; /* Locked trie for walking */ btime last_state_change; /* Time of last state transition */ |