diff --git a/nest/protocol.h b/nest/protocol.h index fd7d532d..2d180aa0 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -230,7 +230,7 @@ struct proto { int (*rte_recalculate)(struct rtable *, struct network *, struct rte_storage *, struct rte_storage *, struct rte_storage *); int (*rte_better)(struct rte_storage *, struct rte_storage *); - int (*rte_mergable)(struct rte_storage *, struct rte_storage *); + int (*rte_mergable)(struct rte, struct rte); struct rta *(*rte_modify)(struct rte_storage *, struct linpool *); void (*rte_insert)(struct network *, struct rte_storage *); void (*rte_remove)(struct network *, struct rte_storage *); @@ -491,7 +491,7 @@ struct channel_config { u8 ra_mode; /* Mode of received route advertisements (RA_*) */ u16 preference; /* Default route preference */ u32 debug; /* Debugging flags (D_*) */ - u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ + u8 merge_limit; /* Maximal number of nexthops for merging */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 rpki_reload; /* RPKI changes trigger channel reload */ }; @@ -523,7 +523,7 @@ struct channel { u8 ra_mode; /* Mode of received route advertisements (RA_*) */ u16 preference; /* Default route preference */ u32 debug; /* Debugging flags (D_*) */ - u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ + u8 merge_limit; /* Maximal number of nexthops for merging */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 disabled; u8 stale; /* Used in reconfiguration */ diff --git a/nest/route.h b/nest/route.h index d89b2f59..92b9cb3a 100644 --- a/nest/route.h +++ b/nest/route.h @@ -231,6 +231,8 @@ typedef struct rte { struct rta *attrs; /* Attributes of this route */ const net_addr *net; /* Network this RTE belongs to */ struct rte_src *src; /* Route source that created the route */ + byte flags; /* Flags (REF_...) */ + byte pflags; /* Protocol-specific flags */ } rte; struct rte_storage { @@ -251,6 +253,7 @@ struct rte_storage { #define REF_STALE 4 /* Route is stale in a refresh cycle */ #define REF_DISCARD 8 /* Route is scheduled for discard */ #define REF_MODIFY 16 /* Route is scheduled for modify */ +#define REF_E_MERGED 32 /* Route has been merged on export */ /* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ static inline int rte_is_valid(const struct rte_storage *r) { return r && !(r->flags & REF_FILTERED); } @@ -288,7 +291,6 @@ struct rte_export { #define RA_OPTIMAL 1 /* Announcement of optimal route change */ #define RA_ACCEPTED 2 /* Announcement of first accepted route */ #define RA_ANY 3 /* Announcement of any route change */ -#define RA_MERGED 4 /* Announcement of optimal route merged with next ones */ /* Return value of preexport() callback */ #define RIC_ACCEPT 1 /* Accepted by protocol */ @@ -348,7 +350,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f void *net_route(rtable *tab, const net_addr *n); int net_roa_check(rtable *tab, const net_addr *n, u32 asn); struct rte_storage *rte_find(net *net, struct rte_src *src); -_Bool rt_export_merged(struct channel *c, net *net, rte *best, linpool *pool, int silent); +rte rte_get_merged(net *n, linpool *p, u32 limit); void rt_refresh_begin(rtable *t, struct channel *c); void rt_refresh_end(rtable *t, struct channel *c); void rt_modify_stale(rtable *t, struct channel *c); @@ -358,7 +360,15 @@ void rte_free(struct rte_storage *); struct rte_storage *rte_store(const rte *, net *n); void rte_copy_metadata(struct rte_storage *dest, struct rte_storage *src); static inline rte rte_copy(const struct rte_storage *r) -{ return (rte) { .attrs = r->attrs, .net = r->net->n.addr, .src = r->src }; } +{ + return r ? (rte) { + .attrs = r->attrs, + .net = r->net->n.addr, + .src = r->src, + .flags = r->flags, + .pflags = r->pflags + } : (rte) {}; +} void rt_dump(rtable *); void rt_dump_all(void); int rt_feed_channel(struct channel *c); @@ -367,10 +377,9 @@ 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, 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); +_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e, linpool *p); void rt_out_sync_finish(struct channel *c); void rt_out_flush(struct channel *c); diff --git a/nest/rt-show.c b/nest/rt-show.c index 1b56d5b9..846e63f4 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -133,25 +133,26 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (d->export_mode == RSEM_EXPORTED) { - if (!bmap_test(&ec->export_map, er->id)) + if (ec->merge_limit > 1) + { + pass = 1; + e = rte_get_merged(n, c->show_pool, ec->merge_limit); + if (!e.attrs) + goto skip; + } + else if (!bmap_test(&ec->export_map, er->id)) goto skip; + // if (ec->ra_mode != RA_ANY) // pass = 1; } - else if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) - { - /* Special case for merged export */ - pass = 1; - if (!rt_export_merged(ec, n, &e, c->show_pool, 1)) - goto skip; - } else if (d->export_mode) { struct proto *ep = ec->proto; int ic = ep->preexport ? ep->preexport(ec, &e) : 0; - if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED) + if (ec->ra_mode == RA_OPTIMAL) pass = 1; if (ic < 0) @@ -230,7 +231,15 @@ rt_show_cont(struct cli *c) if (!d->table_open) { - FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib); + if (d->export_mode == RSEM_EXPORTED && + d->tab->export_channel && + d->tab->export_channel->out_table) + fib = &d->tab->export_channel->out_table->fib; + else + fib = &d->tab->table->fib; + + FIB_ITERATE_INIT(&d->fit, fib); + d->table_open = 1; d->table_counter++; d->kernel = rt_show_get_kernel(d); @@ -410,10 +419,12 @@ rt_show(struct rt_show_data *d) d->tab = tab; d->kernel = rt_show_get_kernel(d); + struct rtable *rt = (d->export_mode == RSEM_EXPORTED) ? tab->export_channel->out_table : tab->table; + if (d->show_for) - n = net_route(tab->table, d->addr); + n = net_route(rt, d->addr); else - n = net_find(tab->table, d->addr); + n = net_find(rt, d->addr); if (n) rt_show_net(this_cli, n, d); diff --git a/nest/rt-table.c b/nest/rt-table.c index 3ef052cc..e0898bc6 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -68,13 +68,15 @@ static linpool *rte_update_pool; list routing_tables; +struct rte_export_internal; + static void rt_free_hostcache(rtable *tab); static void rt_notify_hostcache(rtable *tab, net *net); static void rt_update_hostcache(rtable *tab); static void rt_next_hop_update(rtable *tab); static inline void rt_prune_table(rtable *tab); static inline void rt_schedule_notify(rtable *tab); - +static int rte_update_out(struct channel *c, struct rte_export_internal *e); /* Like fib_route(), but skips empty net entries */ static inline void * @@ -392,20 +394,20 @@ rte_better(struct rte_storage *new, struct rte_storage *old) } static int -rte_mergable(struct rte_storage *pri, struct rte_storage *sec) +rte_mergable(struct rte pri, struct rte sec) { - int (*mergable)(struct rte_storage *, struct rte_storage *); + int (*mergable)(struct rte, struct rte); - if (!rte_is_valid(pri) || !rte_is_valid(sec)) + ASSERT_DIE(pri.attrs); + ASSERT_DIE(sec.attrs); + + if (pri.attrs->pref != sec.attrs->pref) return 0; - if (pri->attrs->pref != sec->attrs->pref) + if (pri.src->proto->proto != sec.src->proto->proto) return 0; - if (pri->src->proto->proto != sec->src->proto->proto) - return 0; - - if (mergable = pri->src->proto->rte_mergable) + if (mergable = pri.src->proto->rte_mergable) return mergable(pri, sec); return 0; @@ -617,93 +619,33 @@ nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max) return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool); } -_Bool -rt_export_merged(struct channel *c, net *net, rte *best, linpool *pool, int silent) +rte +rte_get_merged(net *net, linpool *pool, uint limit) { - // struct proto *p = c->proto; + if (!net->routes || !(net->routes->flags & REF_E_MERGED)) + return (rte) {}; + struct nexthop *nhs = NULL; - struct rte_storage *best0 = net->routes; + struct rte e = rte_copy(net->routes); - if (!rte_is_valid(best0)) - return 0; - - *best = rte_copy(best0); - if (export_filter_(c, best, best0->id, pool, silent) >= EFR_FILTER_REJECT) - /* Best route doesn't pass the filter */ - return 0; - - if (!rte_is_reachable(best)) - /* Unreachable routes can't be merged */ - return 1; - - for (struct rte_storage *rt0 = best0->next; rt0; rt0 = rt0->next) + for (struct rte_storage *rt0 = net->routes->next; rt0; rt0 = rt0->next) { - if (!rte_mergable(best0, rt0)) + if (!(rt0->flags & REF_E_MERGED)) continue; - struct rte tmp = rte_copy(rt0); - if (export_filter_(c, &tmp, rt0->id, pool, 1) >= EFR_FILTER_REJECT) - continue; - - if (!rte_is_reachable(&tmp)) - continue; - - nhs = nexthop_merge_rta(nhs, tmp.attrs, pool, c->merge_limit); + nhs = nexthop_merge_rta(nhs, rte_copy(rt0).attrs, pool, limit); } if (nhs) { - nhs = nexthop_merge_rta(nhs, best->attrs, pool, c->merge_limit); - + nhs = nexthop_merge_rta(nhs, e.attrs, pool, limit); if (nhs->next) - best->attrs = rta_cow(best->attrs, pool); + e.attrs = rta_cow(e.attrs, pool); - nexthop_link(best->attrs, nhs); + nexthop_link(e.attrs, nhs); } - return 1; -} - - -USE_RESULT static _Bool -rt_notify_merged(struct channel *c, struct rte_export_internal *e) -{ - /* We assume that all rte arguments are either NULL or rte_is_valid() */ - - /* This check should be done by the caller */ - if (!e->new_best && !e->old_best) - return 0; - - /* Check whether the change is relevant to the merged route */ - if ((e->new_best == e->old_best) && - (e->new != e->old) && - !rte_mergable(e->new_best, e->new) && - !rte_mergable(e->old_best, e->old)) - return 0; - - if (e->new_best) - c->stats.exp_updates_received++; - else - c->stats.exp_withdraws_received++; - - struct rte_export *ep = &e->pub; - - /* Prepare new merged route */ - if (e->new_best) - { - ep->new_id = e->new_best->id; - if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0)) - ep->new.attrs = NULL; - } - - /* Check old merged route */ - if (e->old_best && bmap_test(&c->export_map, e->old_best->id)) - { - ep->old_id = e->old_best->id; - ep->old = rte_copy(e->old_best); - } - - return RTE_EXPORT_IS_OK(ep); + return e; } static struct rte_export * @@ -729,10 +671,6 @@ rte_export_obtain(struct channel *c, struct rte_export_internal *e) accepted = rt_notify_accepted(c, e); break; - case RA_MERGED: - accepted = rt_notify_merged(c, e); - break; - default: bug("Strange channel route announcement mode"); } @@ -774,7 +712,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->pub.new_id, e->refeed)) + if (!rte_update_out(c, e)) return 0; } else if (c->out_filter != FILTER_ACCEPT) @@ -938,7 +876,7 @@ rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct r .new = new, .old = old, .new_best = new_best, .old_best = old_best, }; - + rte_export(c, &rei); } } @@ -2477,106 +2415,164 @@ rt_prune_sync(rtable *t, int all) * Export table */ -int -rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed) +static int +rte_update_out(struct channel *c, struct rte_export_internal *e) { struct rtable *tab = c->out_table; struct rte_storage **pos; net *net; + rte *new = &e->pub.new; + rte *old = &e->pub.old; + + _Bool new_is_best = (e->new == e->new_best); + _Bool old_is_best = (e->old == e->old_best); + _Bool merging = c->merge_limit > 1; + if (new->attrs) { - net = net_get(tab, new->net); - if (!rta_is_cached(new->attrs)) new->attrs = rta_lookup(new->attrs); - } - else - { - net = net_find(tab, old->net); - if (!net) - goto drop_withdraw; + net = net_get(tab, new->net); } + else if (!(net = net_find(tab, old->net))) + return 0; - /* Find the old rte */ + /* Find the old rte if exists */ for (pos = &net->routes; *pos; pos = &(*pos)->next) - if ((c->ra_mode != RA_ANY) || ((*pos)->src == old->src)) - { - if (new && rte_same(*pos, new, 0)) - { - /* REF_STALE / REF_DISCARD not used in export table */ - /* - if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY)) - { - old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY); - return 1; - } - */ - - goto drop_update; - } - - /* Keep the old rte */ - *old_stored = *pos; - *old = rte_copy(*pos); - - /* Remove the old rte from the list */ - *pos = (*pos)->next; - tab->rt_count--; - + if ((c->ra_mode != RA_ANY) || ((*pos)->src == new->src)) break; - } - if (!new->attrs) + /* Found exactly the same route, no update needed */ + if ((*pos) && new->attrs && rte_same(*pos, new, 0)) + return 0; + + /* Are the new/old routes mergable with the old_best? */ + struct rte_storage *best_stored = + (!merging || net->routes && (net->routes->flags & REF_E_MERGED)) + ? net->routes : NULL; + + _Bool best_changed = new_is_best || old_is_best; + + _Bool new_mergable_with_best_stored = + !best_changed && + new->attrs && best_stored && + rte_mergable(rte_copy(best_stored), *new); + + _Bool gen_old = merging ? + best_changed || + (*pos) && ((*pos)->flags & REF_E_MERGED) || + new_mergable_with_best_stored + : 0; + + if (gen_old) + /* Reconstruct the old merged rte completely. It's gonna change */ + *old = rte_get_merged(net, rte_update_pool, c->merge_limit); + else if (!merging && *pos) + /* A plain old route */ + *old = rte_copy(*pos); + + /* Keep the old_stored but remove it from the list */ + tab->rt_count--; + e->old_stored = *pos; + if (*pos) + *pos = (*pos)->next; + + /* Idempotent withdraw */ + if (!e->old_stored && !new->attrs) + return 0; + + /* Best route must be inserted to the beginning */ + if (merging) { - if (!*old_stored) - goto drop_withdraw; + if (new_is_best) + pos = &net->routes; + else if (old_is_best && (c->ra_mode == RA_ANY)) + { + /* We have to find the new best route and put it first */ + for (pos = &net->routes; *pos; pos = &(*pos)->next) + if ((c->ra_mode != RA_ANY) || ((*pos)->src == e->new_best->src)) + break; - return 1; + if (best_stored = *pos) + { + *pos = best_stored->next; + best_stored->next = net->routes; + net->routes = best_stored; + } + } + } + + /* Store the new rte */ + if (new->attrs) + { + struct rte_storage *es = rte_store(new, net); + es->sender = c; + es->lastmod = current_time(); + es->id = e->new->id; + es->next = *pos; + *pos = es; + tab->rt_count++; + + if (new_is_best) + best_stored = es; + else if (!best_changed && new_mergable_with_best_stored) + es->flags |= REF_E_MERGED; + } + + if (merging) + { + if (best_stored) + best_stored->flags |= REF_E_MERGED; + + ASSERT_DIE(best_stored == net->routes); + + /* Recalculate REF_E_MERGED for other routes */ + if (best_changed && net->routes) + for (struct rte_storage *rt0 = best_stored ? net->routes->next : net->routes; rt0; rt0 = rt0->next) + if (best_stored && rte_mergable(rte_copy(best_stored), rte_copy(rt0))) + rt0->flags |= REF_E_MERGED; + else + rt0->flags &= ~REF_E_MERGED; + + if (!gen_old) + /* Not mergable before nor after, no update generated at all. */ + return 0; + + *new = rte_get_merged(net, rte_update_pool, c->merge_limit); } - /* Insert the new rte */ - 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++; return 1; - -drop_update: - return refeed; - -drop_withdraw: - return 0; } void rt_out_sync_start(struct channel *c) { ASSERT_DIE(c->out_table); - ASSERT_DIE(c->ra_mode != RA_ANY); + ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1)); bmap_reset(&c->out_seen_map, 1024); } _Bool -rt_out_sync_mark(struct channel *c, struct rte_export *e) +rt_out_sync_mark(struct channel *c, struct rte_export *e, linpool *p) { ASSERT_DIE(c->out_table); - ASSERT_DIE(c->ra_mode != RA_ANY); + ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1)); 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; + if (c->merge_limit > 1) + e->new = rte_get_merged(n, p, c->merge_limit); + else + e->new = rte_copy(n->routes); + bmap_set(&c->out_seen_map, n->routes->id); return 1; } @@ -2585,7 +2581,7 @@ void rt_out_sync_finish(struct channel *c) { ASSERT_DIE(c->out_table); - ASSERT_DIE(c->ra_mode != RA_ANY); + ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1)); FIB_WALK(&c->out_table->fib, net, n) { @@ -2594,12 +2590,14 @@ rt_out_sync_finish(struct channel *c) if (!bmap_test(&c->out_seen_map, n->routes->id)) { + rte_update_lock(); struct rte_export ex = { .new_id = n->routes->id, - .new = rte_copy(n->routes), + .new = ((c->merge_limit > 1) ? rte_get_merged(n, rte_update_pool, c->merge_limit) : rte_copy(n->routes)), }; c->proto->rt_notify(c, &ex); + rte_update_unlock(); } } FIB_WALK_END; @@ -2610,19 +2608,21 @@ void rt_out_flush(struct channel *c) { ASSERT_DIE(c->out_table); - ASSERT_DIE(c->ra_mode != RA_ANY); + ASSERT_DIE((c->ra_mode != RA_ANY) || (c->merge_limit > 1)); FIB_WALK(&c->out_table->fib, net, n) { if (!n->routes) continue; + rte_update_lock(); struct rte_export ex = { .old_id = n->routes->id, - .old = rte_copy(n->routes), + .old = ((c->merge_limit > 1) ? rte_get_merged(n, rte_update_pool, c->merge_limit) : rte_copy(n->routes)), }; c->proto->rt_notify(c, &ex); + rte_update_unlock(); } FIB_WALK_END; } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index be16c81e..a3dd08f3 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1869,19 +1869,27 @@ bgp_rt_notify(struct channel *C, struct rte_export *e) static inline u32 -bgp_get_neighbor(struct rte_storage *r) +bgp_get_neighbor(const struct rte r) { - eattr *e = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); + eattr *e = ea_find(r.attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH)); u32 as; if (e && as_path_get_first_regular(e->u.ptr, &as)) return as; /* If AS_PATH is not defined, we treat rte as locally originated */ - struct bgp_proto *p = (void *) r->src->proto; + struct bgp_proto *p = (void *) r.src->proto; return p->cf->confederation ?: p->local_as; } +static inline int +rte_stale_get(rta *r) +{ + /* If staleness is unknown, compute and cache it */ + eattr *a = ea_find(r->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); + return (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE)); +} + static inline int rte_stale(struct rte_storage *r) { @@ -1891,9 +1899,7 @@ rte_stale(struct rte_storage *r) if (r->pflags & BGP_REF_NOT_STALE) return 0; - /* If staleness is unknown, compute and cache it */ - eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); - if (a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE)) + if (rte_stale_get(r->attrs)) { r->pflags |= BGP_REF_STALE; return 1; @@ -1990,7 +1996,7 @@ bgp_rte_better(struct rte_storage *new, struct rte_storage *old) * probably not a big issue. */ if (new_bgp->cf->med_metric || old_bgp->cf->med_metric || - (bgp_get_neighbor(new) == bgp_get_neighbor(old))) + (bgp_get_neighbor(rte_copy(new)) == bgp_get_neighbor(rte_copy(old)))) { x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); @@ -2049,9 +2055,8 @@ bgp_rte_better(struct rte_storage *new, struct rte_storage *old) return ipa_compare(new_bgp->remote_ip, old_bgp->remote_ip) < 0; } - -int -bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec) +static int +bgp_rte_mergable_internal(struct rte *pri, struct rte *sec) { struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->src->proto; struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->src->proto; @@ -2059,14 +2064,17 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec) u32 p, s; /* Skip suppressed routes (see bgp_rte_recalculate()) */ - /* LLGR draft - depreference stale routes */ - if (pri->pflags != sec->pflags) + if ((pri->pflags ^ sec->pflags) & BGP_REF_SUPPRESSED) return 0; /* RFC 4271 9.1.2.1. Route resolvability test */ if (rta_resolvable(pri->attrs) != rta_resolvable(sec->attrs)) return 0; + /* LLGR draft - depreference stale routes */ + if (rte_stale_get(pri->attrs) != rte_stale_get(sec->attrs)) + return 0; + /* Start with local preferences */ x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF)); @@ -2100,7 +2108,7 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec) /* RFC 4271 9.1.2.2. c) Compare MED's */ if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric || - (bgp_get_neighbor(pri) == bgp_get_neighbor(sec))) + (bgp_get_neighbor(*pri) == bgp_get_neighbor(*sec))) { x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC)); @@ -2125,11 +2133,17 @@ bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec) return 1; } +int +bgp_rte_mergable(struct rte pri, struct rte sec) +{ + return bgp_rte_mergable_internal(&pri, &sec); +} + static inline int same_group(struct rte_storage *r, u32 lpref, u32 lasn) { - return (r->attrs->pref == lpref) && (bgp_get_neighbor(r) == lasn); + return (r->attrs->pref == lpref) && (bgp_get_neighbor(rte_copy(r)) == lasn); } static inline int @@ -2145,7 +2159,7 @@ bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte struct rte_storage *r, *s; struct rte_storage *key = new ? new : old; u32 lpref = key->attrs->pref; - u32 lasn = bgp_get_neighbor(key); + u32 lasn = bgp_get_neighbor(rte_copy(key)); int old_suppressed = old ? !!(old->pflags & BGP_REF_SUPPRESSED) : 0; /* @@ -2224,13 +2238,13 @@ bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte return 0; /* Found if new is mergable with best-in-group */ - if (new && (new != r) && bgp_rte_mergable(r, new)) + if (new && (new != r) && bgp_rte_mergable(rte_copy(r), rte_copy(new))) new->pflags &= ~BGP_REF_SUPPRESSED; /* Found all existing routes mergable with best-in-group */ for (s=net->routes; rte_is_valid(s); s=s->next) if (use_deterministic_med(s) && same_group(s, lpref, lasn)) - if ((s != r) && bgp_rte_mergable(r, s)) + if ((s != r) && bgp_rte_mergable(rte_copy(r), rte_copy(s))) s->pflags &= ~BGP_REF_SUPPRESSED; /* Found best-in-group */ diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 520c55f6..352b19ae 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -583,7 +583,7 @@ void bgp_free_prefix_table(struct bgp_channel *c); void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp); int bgp_rte_better(struct rte_storage *, struct rte_storage *); -int bgp_rte_mergable(struct rte_storage *pri, struct rte_storage *sec); +int bgp_rte_mergable(struct rte pri, struct rte sec); int bgp_rte_recalculate(rtable *table, net *net, struct rte_storage *new, struct rte_storage *old, struct rte_storage *old_best); struct rta *bgp_rte_modify_stale(struct rte_storage *r, struct linpool *pool); void bgp_rt_notify(struct channel *C, struct rte_export *e); diff --git a/proto/static/static.c b/proto/static/static.c index 20edcf1d..9c5886d5 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -410,10 +410,10 @@ static_rte_better(struct rte_storage *new, struct rte_storage *old) } static int -static_rte_mergable(struct rte_storage *pri, struct rte_storage *sec) +static_rte_mergable(struct rte pri, struct rte sec) { - u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); - u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); + u32 a = ea_get_int(pri.attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); + u32 b = ea_get_int(sec.attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN); return a == b; } diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 38d87444..e3421ce4 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -68,12 +68,14 @@ */ 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(); } @@ -558,7 +560,6 @@ krt_same_dest(rte *k, rte *e) void krt_got_route(struct krt_proto *p, rte *e, s8 src) { - struct rte_export ex = { .old = *e, }; @@ -587,7 +588,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src) if (!p->ready) goto ignore; - if (!rt_out_sync_mark(p->p.main_channel, &ex)) + if (!rt_out_sync_mark(p->p.main_channel, &ex, krt_filter_lp)) goto aseen; if (!ex.new.attrs) @@ -622,6 +623,7 @@ delete: goto done; done: + lp_flush(krt_filter_lp); return; } @@ -896,7 +898,7 @@ krt_postconfig(struct proto_config *CF) if (cf->merge_paths) { - cc->ra_mode = RA_MERGED; + cc->ra_mode = RA_ANY; cc->merge_limit = cf->merge_paths; }