diff --git a/filter/f-inst.c b/filter/f-inst.c index 83d86295..532c6989 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -519,14 +519,14 @@ { STATIC_ATTR; ACCESS_RTE; - struct rta *rta = (*fs->rte)->attrs; + struct rta *rta = fs->rte->attrs; switch (sa.sa_code) { case SA_FROM: RESULT(sa.f_type, ip, rta->from); break; case SA_GW: RESULT(sa.f_type, ip, rta->nh.gw); break; - case SA_NET: RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break; - case SA_PROTO: RESULT(sa.f_type, s, (*fs->rte)->src->proto->name); break; + case SA_NET: RESULT(sa.f_type, net, fs->rte->net); break; + case SA_PROTO: RESULT(sa.f_type, s, fs->rte->src->proto->name); break; case SA_SOURCE: RESULT(sa.f_type, i, rta->source); break; case SA_SCOPE: RESULT(sa.f_type, i, rta->scope); break; case SA_DEST: RESULT(sa.f_type, i, rta->dest); break; @@ -550,7 +550,7 @@ f_rta_cow(fs); { - struct rta *rta = (*fs->rte)->attrs; + struct rta *rta = fs->rte->attrs; switch (sa.sa_code) { @@ -562,7 +562,7 @@ { ip_addr ip = v1.val.ip; struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL; - neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, 0); + neighbor *n = neigh_find(fs->rte->src->proto, ip, ifa, 0); if (!n || (n->scope == SCOPE_HOST)) runtime( "Invalid gw address" ); @@ -1314,7 +1314,7 @@ struct rtable *table = rtc->table; ACCESS_RTE; ACCESS_EATTRS; - const net_addr *net = (*fs->rte)->net->n.addr; + const net_addr *net = fs->rte->net; /* We ignore temporary attributes, probably not a problem here */ /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */ diff --git a/filter/filter.c b/filter/filter.c index 7004b96d..6f1e6ea0 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -74,10 +74,7 @@ struct filter_state { } stack; /* The route we are processing. This may be NULL to indicate no route available. */ - struct rte **rte; - - /* The old rta to be freed after filters are done. */ - struct rta *old_rta; + struct rte *rte; /* Cached pointer to ea_list */ struct ea_list **eattrs; @@ -102,15 +99,7 @@ void (*bt_assert_hook)(int result, const struct f_line_item *assert); static inline void f_cache_eattrs(struct filter_state *fs) { - fs->eattrs = &((*fs->rte)->attrs->eattrs); -} - -static inline void f_rte_cow(struct filter_state *fs) -{ - if (!((*fs->rte)->flags & REF_COW)) - return; - - *fs->rte = rte_cow(*fs->rte); + fs->eattrs = &(fs->rte->attrs->eattrs); } /* @@ -119,22 +108,16 @@ static inline void f_rte_cow(struct filter_state *fs) static void f_rta_cow(struct filter_state *fs) { - if (!rta_is_cached((*fs->rte)->attrs)) + if (!rta_is_cached(fs->rte->attrs)) return; - /* Prepare to modify rte */ - f_rte_cow(fs); - - /* Store old rta to free it later, it stores reference from rte_cow() */ - fs->old_rta = (*fs->rte)->attrs; - /* * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared * with fs->old_rta (they will be copied when the cached rta will be obtained * at the end of f_run()), also the lock of hostentry is inherited (we * suppose hostentry is not changed by filters). */ - (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool); + fs->rte->attrs = rta_do_cow(fs->rte->attrs, fs->pool); /* Re-cache the ea_list */ f_cache_eattrs(fs); @@ -246,29 +229,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val) /** * f_run - run a filter for a route * @filter: filter to run - * @rte: route being filtered, may be modified + * @rte: route being filtered, must be write-able * @tmp_pool: all filter allocations go from this pool * @flags: flags * - * If filter needs to modify the route, there are several - * posibilities. @rte might be read-only (with REF_COW flag), in that - * case rw copy is obtained by rte_cow() and @rte is replaced. If - * @rte is originally rw, it may be directly modified (and it is never - * copied). - * - * The returned rte may reuse the (possibly cached, cloned) rta, or - * (if rta was modified) contains a modified uncached rta, which - * uses parts allocated from @tmp_pool and parts shared from original - * rta. There is one exception - if @rte is rw but contains a cached - * rta and that is modified, rta in returned rte is also cached. - * - * Ownership of cached rtas is consistent with rte, i.e. - * if a new rte is returned, it has its own clone of cached rta - * (and cached rta of read-only source rte is intact), if rte is - * modified in place, old cached rta is possibly freed. + * If @rte->attrs is cached, the returned rte allocates a new rta on + * tmp_pool, otherwise the filters may modify it. */ enum filter_return -f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags) +f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags) { if (filter == FILTER_ACCEPT) return F_ACCEPT; @@ -276,7 +245,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i if (filter == FILTER_REJECT) return F_REJECT; - int rte_cow = ((*rte)->flags & REF_COW); DBG( "Running filter `%s'...", filter->name ); /* Initialize the filter state */ @@ -293,32 +261,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i /* Run the interpreter itself */ enum filter_return fret = interpret(&filter_state, filter->root, NULL); - if (filter_state.old_rta) { - /* - * Cached rta was modified and filter_state->rte contains now an uncached one, - * sharing some part with the cached one. The cached rta should - * be freed (if rte was originally COW, filter_state->old_rta is a clone - * obtained during rte_cow()). - * - * This also implements the exception mentioned in f_run() - * description. The reason for this is that rta reuses parts of - * filter_state->old_rta, and these may be freed during rta_free(filter_state->old_rta). - * This is not the problem if rte was COW, because original rte - * also holds the same rta. - */ - if (!rte_cow) { - /* Cache the new attrs */ - (*filter_state.rte)->attrs = rta_lookup((*filter_state.rte)->attrs); - - /* Drop cached ea_list pointer */ - filter_state.eattrs = NULL; - } - - /* Uncache the old attrs and drop the pointer as it is invalid now. */ - rta_free(filter_state.old_rta); - filter_state.old_rta = NULL; - } - /* Process the filter output, log it and return */ if (fret < F_ACCEPT) { if (!(filter_state.flags & FF_SILENT)) @@ -343,7 +285,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i */ enum filter_return -f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool) +f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool) { filter_state = (struct filter_state) { .rte = rte, @@ -354,8 +296,7 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool LOG_BUFFER_INIT(filter_state.buf); - ASSERT(!((*rte)->flags & REF_COW)); - ASSERT(!rta_is_cached((*rte)->attrs)); + ASSERT(!rta_is_cached(rte->attrs)); return interpret(&filter_state, expr, NULL); } diff --git a/filter/filter.h b/filter/filter.h index 26c1037b..9964831c 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -51,8 +51,8 @@ struct filter { struct rte; -enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags); -enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool); +enum filter_return f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags); +enum filter_return f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool); uint f_eval_int(const struct f_line *expr); enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf); diff --git a/nest/protocol.h b/nest/protocol.h index e05dd7ec..80b4509b 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -211,9 +211,9 @@ struct proto { void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); - void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old); + void (*rt_notify)(struct proto *, struct channel *, const net_addr *net, struct rte *new, const struct rte *old); void (*neigh_notify)(struct neighbor *neigh); - int (*preexport)(struct proto *, struct rte *rt); + int (*preexport)(struct channel *, struct rte *rt); void (*reload_routes)(struct channel *); void (*feed_begin)(struct channel *, int initial); void (*feed_end)(struct channel *); @@ -232,7 +232,7 @@ struct proto { int (*rte_recalculate)(struct rtable *, struct network *, struct rte *, struct rte *, struct rte *); int (*rte_better)(struct rte *, struct rte *); int (*rte_mergable)(struct rte *, struct rte *); - struct rte * (*rte_modify)(struct rte *, struct linpool *); + struct rte *(*rte_modify)(struct rte *, struct linpool *); void (*rte_insert)(struct network *, struct rte *); void (*rte_remove)(struct network *, struct rte *); u32 (*rte_igp_metric)(struct rte *); @@ -542,7 +542,7 @@ struct channel { struct rtable *in_table; /* Internal table for received routes */ struct event *reload_event; /* Event responsible for reloading from in_table */ struct fib_iterator reload_fit; /* FIB iterator in in_table used during reloading */ - struct rte *reload_next_rte; /* Route iterator in in_table used during reloading */ + struct rte_storage *reload_next_rte; /* Route iterator in in_table used during reloading */ u8 reload_active; /* Iterator reload_fit is linked */ u8 reload_pending; /* Reloading and another reload is scheduled */ @@ -632,18 +632,4 @@ void *channel_config_new(const struct channel_class *cc, const char *name, uint void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto); int channel_reconfigure(struct channel *c, struct channel_config *cf); - -/* Moved from route.h to avoid dependency conflicts */ -static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); } - -static inline void -rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) -{ - if (c->in_table && !rte_update_in(c, n, new, src)) - return; - - rte_update2(c, n, new, src); -} - - #endif diff --git a/nest/route.h b/nest/route.h index 595acabd..c7fb67aa 100644 --- a/nest/route.h +++ b/nest/route.h @@ -161,6 +161,7 @@ typedef struct rtable { resource r; node n; /* Node in list of all tables */ pool *rp; /* Resource pool to allocate everything from, including itself */ + struct slab *rte_slab; /* Slab to allocate route objects */ struct fib fib; struct f_trie *trie; /* Trie of prefixes defined in fib */ char *name; /* Name of this table */ @@ -221,7 +222,7 @@ struct rt_flowspec_link { #define NHU_DIRTY 3 typedef struct network { - struct rte *routes; /* Available routes for this network */ + struct rte_storage *routes; /* Available routes for this network */ struct fib_node n; /* FIB flags reserved for kernel syncer */ } net; @@ -253,25 +254,34 @@ struct hostentry { }; typedef struct rte { - struct rte *next; - net *net; /* Network this RTE belongs to */ + 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 */ struct channel *sender; /* Channel used to send the route to the routing table */ - struct rta *attrs; /* Attributes of this route */ + btime lastmod; /* Last modified (set by table) */ u32 id; /* Table specific route id */ - byte flags; /* Flags (REF_...) */ + byte flags; /* Table-specific flags */ byte pflags; /* Protocol-specific flags */ - btime lastmod; /* Last modified */ } rte; -#define REF_COW 1 /* Copy this rte on write */ +struct rte_storage { + struct rte_storage *next; /* Next in chain */ + struct rte rte; /* Route data */ +}; + +#define RTE_COPY(r, l) ((r) ? (((*(l)) = (r)->rte), (l)) : NULL) +#define RTE_OR_NULL(r) ((r) ? &((r)->rte) : NULL) + #define REF_FILTERED 2 /* Route is rejected by import filter */ #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 */ /* Route is valid for propagation (may depend on other flags in the future), accepts NULL */ -static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); } +static inline int rte_is_valid_rte(rte *r) { return r && !(r->flags & REF_FILTERED); } +static inline int rte_is_valid_storage(struct rte_storage *r) { return r && rte_is_valid_rte(&r->rte); } + +#define rte_is_valid(r) _Generic((*r), rte: rte_is_valid_rte, struct rte_storage: rte_is_valid_storage)(r) /* Route just has REF_FILTERED flag */ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); } @@ -290,6 +300,40 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); #define RIC_REJECT -1 /* Rejected by protocol */ #define RIC_DROP -2 /* Silently dropped by protocol */ +/** + * rte_update - enter a new update to a routing table + * @c: channel doing the update + * @net: network address + * @rte: a &rte representing the new route + * @src: old route source identifier + * + * This function imports a new route to the appropriate table (via the channel). + * Table keys are @net (obligatory) and @rte->attrs->src. + * Both the @net and @rte pointers can be local. + * + * The route attributes (@rte->attrs) are obligatory. They can be also allocated + * locally. Anyway, if you use an already-cached attribute object, you shall + * call rta_clone() on that object yourself. (This semantics may change in future.) + * + * If the route attributes are local, you may set @rte->attrs->src to NULL, then + * the protocol's default route source will be supplied. + * + * When rte_update() gets a route, it automatically validates it. This includes + * checking for validity of the given network and next hop addresses and also + * checking for host-scope or link-scope routes. Then the import filters are + * processed and if accepted, the route is passed to route table recalculation. + * + * The accepted routes are then inserted into the table, replacing the old route + * for the same @net identified by @src. Then the route is announced + * to all the channels connected to the table using the standard export mechanism. + * Setting @rte to NULL makes this a withdraw, otherwise @rte->src must be the same + * as @src. + * + * All memory used for temporary allocations is taken from a special linpool + * @rte_update_pool and freed when rte_update() finishes. + */ +void rte_update(struct channel *c, const net_addr *net, struct rte *rte, struct rte_src *src); + extern list routing_tables; struct config; @@ -309,35 +353,28 @@ static inline void rt_shutdown(rtable *r) { rfree(r->rp); } static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } static inline net *net_find_valid(rtable *tab, const net_addr *addr) -{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; } +{ net *n = net_find(tab, addr); return (n && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; } static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); } net *net_get(rtable *tab, const net_addr *addr); net *net_route(rtable *tab, const net_addr *n); int net_roa_check(rtable *tab, const net_addr *n, u32 asn); -rte *rte_find(net *net, struct rte_src *src); -rte *rte_get_temp(struct rta *, struct rte_src *src); -void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); -/* rte_update() moved to protocol.h to avoid dependency conflicts */ -int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter); -rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent); +int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter); +rte *rt_export_merged(struct channel *c, net *net, linpool *pool, int silent); 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); void rt_schedule_prune(rtable *t); -void rte_dump(rte *); -void rte_free(rte *); -rte *rte_do_cow(rte *); -static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; } -rte *rte_cow_rta(rte *r, linpool *lp); +void rte_dump(struct rte_storage *); +void rte_free(struct rte_storage *, rtable *); +struct rte_storage *rte_store(const rte *, net *net, rtable *); void rt_dump(rtable *); void rt_dump_all(void); int rt_feed_channel(struct channel *c); void rt_feed_channel_abort(struct channel *c); -int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); 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, const net_addr *n, rte *new, rte *old, rte **old_exported, int refeed); +int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported, int refeed); struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); static inline int rt_is_ip(rtable *tab) @@ -678,7 +715,7 @@ void rta_dump(rta *); void rta_dump_all(void); void rta_show(struct cli *, rta *); -u32 rt_get_igp_metric(rte *rt); +u32 rt_get_igp_metric(rte *); struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep); void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls); diff --git a/nest/rt-dev.c b/nest/rt-dev.c index e2e65926..5d1e57b3 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -67,13 +67,10 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) /* Use iface ID as local source ID */ struct rte_src *src = rt_get_source(P, ad->iface->index); - rte_update2(c, net, NULL, src); + rte_update(c, net, NULL, src); } else if (flags & IF_CHANGE_UP) { - rta *a; - rte *e; - DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip); if (cf->check_link && !(ad->iface->flags & IF_LINK_UP)) @@ -90,10 +87,12 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) .nh.iface = ad->iface, }; - a = rta_lookup(&a0); - e = rte_get_temp(a, src); - e->pflags = 0; - rte_update2(c, net, e, src); + rte e0 = { + .attrs = rta_lookup(&a0), + .src = src, + }; + + rte_update(c, net, &e0, src); } } diff --git a/nest/rt-show.c b/nest/rt-show.c index 19877966..7b05c64e 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -102,7 +102,6 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary static void rt_show_net(struct cli *c, net *n, struct rt_show_data *d) { - rte *e, *ee; byte ia[NET_MAX_TEXT_LENGTH+1]; struct channel *ec = d->tab->export_channel; @@ -114,9 +113,9 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) int first_show = 1; int pass = 0; - for (e = n->routes; e; e = e->next) + for (struct rte_storage *er = n->routes; er; er = er->next) { - if (rte_is_filtered(e) != d->filtered) + if (rte_is_filtered(&er->rte) != d->filtered) continue; d->rt_counter++; @@ -126,7 +125,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (pass) continue; - ee = e; + struct rte e = er->rte; /* Export channel is down, do not try to export routes to it */ if (ec && (ec->export_state == ES_DOWN)) @@ -134,7 +133,7 @@ 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, ee->id)) + if (!bmap_test(&ec->export_map, e.id)) goto skip; // if (ec->ra_mode != RA_ANY) @@ -143,17 +142,17 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) else if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) { /* Special case for merged export */ - rte *rt_free; - e = rt_export_merged(ec, n, &rt_free, c->show_pool, 1); pass = 1; - - if (!e) - { e = ee; goto skip; } + rte *em = rt_export_merged(ec, n, c->show_pool, 1); + if (em) + e = *em; + else + goto skip; } else if (d->export_mode) { struct proto *ep = ec->proto; - int ic = ep->preexport ? ep->preexport(ep, e) : 0; + int ic = ep->preexport ? ep->preexport(ec, &e) : 0; if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED) pass = 1; @@ -179,7 +178,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) } } - if (d->show_protocol && (d->show_protocol != e->src->proto)) + if (d->show_protocol && (d->show_protocol != e.src->proto)) goto skip; if (f_run(d->filter, &e, c->show_pool, 0) > F_ACCEPT) @@ -192,18 +191,13 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) else ia[0] = 0; - rt_show_rte(c, ia, e, d, (e->net->routes == ee)); + rt_show_rte(c, ia, &e, d, (n->routes == er)); first_show = 0; } d->show_counter++; skip: - if (e != ee) - { - rte_free(e); - e = ee; - } lp_flush(c->show_pool); if (d->primary_only) diff --git a/nest/rt-table.c b/nest/rt-table.c index b3ca3d05..9a9d57ad 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -112,7 +112,6 @@ pool *rt_table_pool; -static slab *rte_slab; static linpool *rte_update_pool; list routing_tables; @@ -540,106 +539,53 @@ net_roa_check(rtable *tab, const net_addr *n, u32 asn) * @net: network node * @src: route source * - * The rte_find() function returns a route for destination @net - * which is from route source @src. + * The rte_find() function returns a pointer to a route for destination @net + * which is from route source @src. List end pointer is returned if no route is found. */ -rte * +static struct rte_storage ** rte_find(net *net, struct rte_src *src) { - rte *e = net->routes; + struct rte_storage **e = &net->routes; + + while ((*e) && (*e)->rte.src != src) + e = &(*e)->next; - while (e && e->src != src) - e = e->next; return e; } -/** - * rte_get_temp - get a temporary &rte - * @a: attributes to assign to the new route (a &rta; in case it's - * un-cached, rte_update() will create a cached copy automatically) - * - * Create a temporary &rte and bind it with the attributes @a. - * Also set route preference to the default preference set for - * the protocol. - */ -rte * -rte_get_temp(rta *a, struct rte_src *src) -{ - rte *e = sl_alloc(rte_slab); - e->attrs = a; - e->id = 0; - e->flags = 0; - rt_lock_source(e->src = src); +struct rte_storage * +rte_store(const rte *r, net *net, rtable *tab) +{ + struct rte_storage *e = sl_alloc(tab->rte_slab); + + e->rte = *r; + e->rte.net = net->n.addr; + + rt_lock_source(e->rte.src); + + if (e->rte.attrs->cached) + e->rte.attrs = rta_clone(e->rte.attrs); + else + e->rte.attrs = rta_lookup(e->rte.attrs); + return e; } -rte * -rte_do_cow(rte *r) -{ - rte *e = sl_alloc(rte_slab); - - memcpy(e, r, sizeof(rte)); - - rt_lock_source(e->src); - e->attrs = rta_clone(r->attrs); - e->flags = 0; - return e; -} - -/** - * rte_cow_rta - get a private writable copy of &rte with writable &rta - * @r: a route entry to be copied - * @lp: a linpool from which to allocate &rta - * - * rte_cow_rta() takes a &rte and prepares it and associated &rta for - * modification. There are three possibilities: First, both &rte and &rta are - * private copies, in that case they are returned unchanged. Second, &rte is - * private copy, but &rta is cached, in that case &rta is duplicated using - * rta_do_cow(). Third, both &rte is shared and &rta is cached, in that case - * both structures are duplicated by rte_do_cow() and rta_do_cow(). - * - * Note that in the second case, cached &rta loses one reference, while private - * copy created by rta_do_cow() is a shallow copy sharing indirect data (eattrs, - * nexthops, ...) with it. To work properly, original shared &rta should have - * another reference during the life of created private copy. - * - * Result: a pointer to the new writable &rte with writable &rta. - */ -rte * -rte_cow_rta(rte *r, linpool *lp) -{ - if (!rta_is_cached(r->attrs)) - return r; - - r = rte_cow(r); - rta *a = rta_do_cow(r->attrs, lp); - rta_free(r->attrs); - r->attrs = a; - return r; -} - /** * rte_free - delete a &rte - * @e: &rte to be deleted + * @e: &struct rte_storage to be deleted + * @tab: the table which the rte belongs to * * rte_free() deletes the given &rte from the routing table it's linked to. */ -void -rte_free(rte *e) -{ - rt_unlock_source(e->src); - if (rta_is_cached(e->attrs)) - rta_free(e->attrs); - sl_free(rte_slab, e); -} -static inline void -rte_free_quick(rte *e) +void +rte_free(struct rte_storage *e, rtable *tab) { - rt_unlock_source(e->src); - rta_free(e->attrs); - sl_free(rte_slab, e); + rt_unlock_source(e->rte.src); + rta_free(e->rte.attrs); + sl_free(tab->rte_slab, e); } static int /* Actually better or at least as good as */ @@ -694,7 +640,7 @@ static void rte_trace(struct channel *c, rte *e, int dir, char *msg) { log(L_TRACE "%s.%s %c %s %N %uL %uG %s", - c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id, + c->proto->name, c->name ?: "?", dir, msg, e->net, e->src->private_id, e->src->global_id, rta_dest_name(e->attrs->dest)); } @@ -713,18 +659,14 @@ rte_trace_out(uint flag, struct channel *c, rte *e, char *msg) } static rte * -export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int silent) +export_filter_(struct channel *c, rte *rt, linpool *pool, int silent) { struct proto *p = c->proto; const struct filter *filter = c->out_filter; struct proto_stats *stats = &c->stats; - rte *rt; int v; - rt = rt0; - *rt_free = NULL; - - v = p->preexport ? p->preexport(p, rt) : 0; + v = p->preexport ? p->preexport(c, rt) : 0; if (v < 0) { if (silent) @@ -743,7 +685,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si } v = filter && ((filter == FILTER_REJECT) || - (f_run(filter, &rt, pool, + (f_run(filter, rt, pool, (silent ? FF_SILENT : 0)) > F_ACCEPT)); if (v) { @@ -756,25 +698,21 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si } accept: - if (rt != rt0) - *rt_free = rt; return rt; reject: /* Discard temporary rte */ - if (rt != rt0) - rte_free(rt); return NULL; } static inline rte * -export_filter(struct channel *c, rte *rt0, rte **rt_free, int silent) +export_filter(struct channel *c, rte *rt, int silent) { - return export_filter_(c, rt0, rt_free, rte_update_pool, silent); + return export_filter_(c, rt, rte_update_pool, silent); } static void -do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) +do_rt_notify(struct channel *c, const net_addr *net, rte *new, rte *old, int refeed) { struct proto *p = c->proto; struct proto_stats *stats = &c->stats; @@ -798,14 +736,12 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) } /* Apply export table */ - struct rte *old_exported = NULL; + struct rte_storage *old_exported = NULL; if (c->out_table) { - if (!rte_update_out(c, net->n.addr, new, old, &old_exported, refeed)) + if (!rte_update_out(c, net, new, old, &old_exported, refeed)) return; } - else if (c->out_filter == FILTER_ACCEPT) - old_exported = old; if (new) stats->exp_updates_accepted++; @@ -834,25 +770,22 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) rte_trace_out(D_ROUTES, c, old, "removed"); } - p->rt_notify(p, c, net, new, old); + p->rt_notify(p, c, net, new, old_exported ? &old_exported->rte : old); if (c->out_table && old_exported) - rte_free_quick(old_exported); + rte_free(old_exported, c->out_table); } static void -rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed) +rt_notify_basic(struct channel *c, const net_addr *net, rte *new, rte *old, int refeed) { - // struct proto *p = c->proto; - rte *new_free = NULL; - if (new) c->stats.exp_updates_received++; else c->stats.exp_withdraws_received++; if (new) - new = export_filter(c, new, &new_free, 0); + new = export_filter(c, new, 0); if (old && !bmap_test(&c->export_map, old->id)) old = NULL; @@ -861,19 +794,15 @@ rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed) return; do_rt_notify(c, net, new, old, refeed); - - /* Discard temporary rte */ - if (new_free) - rte_free(new_free); } static void rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, int refeed) { // struct proto *p = c->proto; + rte nb0; rte *new_best = NULL; rte *old_best = NULL; - rte *new_free = NULL; int new_first = 0; /* @@ -902,16 +831,16 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang old_best = old_changed; else { - for (rte *r = net->routes; rte_is_valid(r); r = r->next) + for (struct rte_storage *r = net->routes; rte_is_valid(r); r = r->next) { - if (bmap_test(&c->export_map, r->id)) + if (bmap_test(&c->export_map, r->rte.id)) { - old_best = r; + old_best = &r->rte; break; } /* Note if new_changed found before old_best */ - if (r == new_changed) + if (&r->rte == new_changed) new_first = 1; } } @@ -920,14 +849,14 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang if ((new_changed == old_changed) || (old_best == old_changed)) { /* Feed or old_best changed -> find first accepted by filters */ - for (rte *r = net->routes; rte_is_valid(r); r = r->next) - if (new_best = export_filter(c, r, &new_free, 0)) + for (struct rte_storage *r = net->routes; rte_is_valid(r); r = r->next) + if (new_best = export_filter(c, ((nb0 = r->rte), &nb0), 0)) break; } else { /* Other cases -> either new_changed, or old_best (and nothing changed) */ - if (new_first && (new_changed = export_filter(c, new_changed, &new_free, 0))) + if (new_first && (new_changed = export_filter(c, new_changed, 0))) new_best = new_changed; else return; @@ -936,11 +865,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang if (!new_best && !old_best) return; - do_rt_notify(c, net, new_best, old_best, refeed); - - /* Discard temporary rte */ - if (new_free) - rte_free(new_free); + do_rt_notify(c, net->n.addr, new_best, old_best, refeed); } @@ -951,38 +876,35 @@ nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max) } rte * -rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent) +rt_export_merged(struct channel *c, net *net, linpool *pool, int silent) { // struct proto *p = c->proto; struct nexthop *nhs = NULL; - rte *best0, *best, *rt0, *rt, *tmp; - - best0 = net->routes; - *rt_free = NULL; + _Thread_local static rte rme; + struct rte_storage *best0 = net->routes; + rte *best; if (!rte_is_valid(best0)) return NULL; - best = export_filter_(c, best0, rt_free, pool, silent); + best = export_filter_(c, ((rme = best0->rte), &rme), pool, silent); if (!best || !rte_is_reachable(best)) return best; - for (rt0 = best0->next; rt0; rt0 = rt0->next) + for (struct rte_storage *rt0 = best0->next; rt0; rt0 = rt0->next) { - if (!rte_mergable(best0, rt0)) + if (!rte_mergable(best, &rt0->rte)) continue; - rt = export_filter_(c, rt0, &tmp, pool, 1); + rte rnh = rt0->rte; + rte *rt = export_filter_(c, &rnh, pool, 1); if (!rt) continue; if (rte_is_reachable(rt)) nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit); - - if (tmp) - rte_free(tmp); } if (nhs) @@ -991,14 +913,11 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int if (nhs->next) { - best = rte_cow_rta(best, pool); + best->attrs = rta_cow(best->attrs, pool); nexthop_link(best->attrs, nhs); } } - if (best != best0) - *rt_free = best; - return best; } @@ -1007,9 +926,6 @@ static void rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *new_best, rte *old_best, int refeed) { - // struct proto *p = c->proto; - rte *new_free = NULL; - /* We assume that all rte arguments are either NULL or rte_is_valid() */ /* This check should be done by the caller */ @@ -1030,7 +946,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed /* Prepare new merged route */ if (new_best) - new_best = rt_export_merged(c, net, &new_free, rte_update_pool, 0); + new_best = rt_export_merged(c, net, rte_update_pool, 0); /* Check old merged route */ if (old_best && !bmap_test(&c->export_map, old_best->id)) @@ -1039,11 +955,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed if (!new_best && !old_best) return; - do_rt_notify(c, net, new_best, old_best, refeed); - - /* Discard temporary rte */ - if (new_free) - rte_free(new_free); + do_rt_notify(c, net->n.addr, new_best, old_best, refeed); } @@ -1087,8 +999,8 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed * done outside of scope of rte_announce(). */ static void -rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old, - rte *new_best, rte *old_best) +rte_announce(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old, + struct rte_storage *new_best, struct rte_storage *old_best) { if (!rte_is_valid(new)) new = NULL; @@ -1108,9 +1020,9 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old, if (new_best != old_best) { if (new_best) - new_best->sender->stats.pref_routes++; + new_best->rte.sender->stats.pref_routes++; if (old_best) - old_best->sender->stats.pref_routes--; + old_best->rte.sender->stats.pref_routes--; if (tab->hostcache) rt_notify_hostcache(tab, net); @@ -1130,24 +1042,25 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old, if (type && (type != c->ra_mode)) continue; + rte n0; switch (c->ra_mode) { case RA_OPTIMAL: if (new_best != old_best) - rt_notify_basic(c, net, new_best, old_best, 0); + rt_notify_basic(c, net->n.addr, RTE_COPY(new_best, &n0), RTE_OR_NULL(old_best), 0); break; case RA_ANY: if (new != old) - rt_notify_basic(c, net, new, old, 0); + rt_notify_basic(c, net->n.addr, RTE_COPY(new, &n0), RTE_OR_NULL(old), 0); break; case RA_ACCEPTED: - rt_notify_accepted(c, net, new, old, 0); + rt_notify_accepted(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), 0); break; case RA_MERGED: - rt_notify_merged(c, net, new, old, new_best, old_best, 0); + rt_notify_merged(c, net, RTE_OR_NULL(new), RTE_OR_NULL(old), RTE_OR_NULL(new_best), RTE_OR_NULL(old_best), 0); break; } } @@ -1157,40 +1070,40 @@ static inline int rte_validate(rte *e) { int c; - net *n = e->net; + const net_addr *n = e->net; - if (!net_validate(n->n.addr)) + if (!net_validate(n)) { log(L_WARN "Ignoring bogus prefix %N received via %s", - n->n.addr, e->sender->proto->name); + n, e->sender->proto->name); return 0; } /* FIXME: better handling different nettypes */ - c = !net_is_flow(n->n.addr) ? - net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE); + c = !net_is_flow(n) ? + net_classify(n): (IADDR_HOST | SCOPE_UNIVERSE); if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) { log(L_WARN "Ignoring bogus route %N received via %s", - n->n.addr, e->sender->proto->name); + n, e->sender->proto->name); return 0; } - if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest) + if (net_type_match(n, NB_DEST) == !e->attrs->dest) { /* Exception for flowspec that failed validation */ - if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE)) + if (net_is_flow(n) && (e->attrs->dest == RTD_UNREACHABLE)) return 1; log(L_WARN "Ignoring route %N with invalid dest %d received via %s", - n->n.addr, e->attrs->dest, e->sender->proto->name); + n, e->attrs->dest, e->sender->proto->name); return 0; } if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh))) { log(L_WARN "Ignoring unsorted multipath route %N received via %s", - n->n.addr, e->sender->proto->name); + n, e->sender->proto->name); return 0; } @@ -1217,16 +1130,17 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) struct rtable *table = c->table; struct proto_stats *stats = &c->stats; static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS; - rte *before_old = NULL; - rte *old_best = net->routes; + struct rte_storage *old_best_stored = net->routes, *old_stored = NULL; + rte *old_best = old_best_stored ? &old_best_stored->rte : NULL; rte *old = NULL; - rte **k; - k = &net->routes; /* Find and remove original route from the same protocol */ - while (old = *k) + /* Find and remove original route from the same protocol */ + struct rte_storage **before_old = rte_find(net, src); + + if (*before_old) { - if (old->src == src) - { + old = &(old_stored = (*before_old))->rte; + /* If there is the same route in the routing table but from * a different sender, then there are two paths from the * source protocol to this routing table through transparent @@ -1239,11 +1153,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) if (old->sender->proto != p) { if (new) - { log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %N to table %s", net->n.addr, table->name); - rte_free_quick(new); - } return; } @@ -1259,23 +1170,13 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) rte_trace_in(D_ROUTES, c, new, "ignored"); } - rte_free_quick(new); return; } - *k = old->next; + + *before_old = (*before_old)->next; table->rt_count--; - break; - } - k = &old->next; - before_old = old; } - /* Save the last accessed position */ - rte **pos = k; - - if (!old) - before_old = NULL; - if (!old && !new) { stats->imp_withdraws_ignored++; @@ -1300,7 +1201,6 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) stats->imp_updates_ignored++; rte_trace_in(D_FILTERS, c, new, "ignored [limit]"); - rte_free_quick(new); return; } } @@ -1326,7 +1226,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) if (c->in_keep_filtered) new->flags |= REF_FILTERED; else - { rte_free_quick(new); new = NULL; } + new = NULL; /* Note that old && !new could be possible when c->in_keep_filtered changed in the recent past. */ @@ -1349,7 +1249,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) if (old_ok || new_ok) table->last_rt_change = current_time(); - skip_stats1: + skip_stats1:; + struct rte_storage *new_stored = new ? rte_store(new, net, table) : NULL; if (new) rte_is_filtered(new) ? stats->filt_routes++ : stats->imp_routes++; @@ -1359,19 +1260,20 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) if (table->config->sorted) { /* If routes are sorted, just insert new route to appropriate position */ - if (new) + if (new_stored) { - if (before_old && !rte_better(new, before_old)) - k = &before_old->next; + struct rte_storage **k; + if ((before_old != &net->routes) && !rte_better(new, &SKIP_BACK(struct rte_storage, next, before_old)->rte)) + k = before_old; else k = &net->routes; for (; *k; k=&(*k)->next) - if (rte_better(new, *k)) + if (rte_better(new, &(*k)->rte)) break; - new->next = *k; - *k = new; + new_stored->next = *k; + *k = new_stored; table->rt_count++; } @@ -1381,16 +1283,17 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) /* If routes are not sorted, find the best route and move it on the first position. There are several optimized cases. */ - if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best)) + if (src->proto->rte_recalculate && + src->proto->rte_recalculate(table, net, new_stored ? &new_stored->rte : NULL, old, old_best)) goto do_recalculate; - if (new && rte_better(new, old_best)) + if (new_stored && rte_better(&new_stored->rte, old_best)) { /* The first case - the new route is cleary optimal, we link it at the first position */ - new->next = net->routes; - net->routes = new; + new_stored->next = net->routes; + net->routes = new_stored; table->rt_count++; } @@ -1404,10 +1307,10 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) do_recalculate: /* Add the new route to the list */ - if (new) + if (new_stored) { - new->next = *pos; - *pos = new; + new_stored->next = *before_old; + *before_old = new_stored; table->rt_count++; } @@ -1415,56 +1318,56 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) /* Find a new optimal route (if there is any) */ if (net->routes) { - rte **bp = &net->routes; - for (k=&(*bp)->next; *k; k=&(*k)->next) - if (rte_better(*k, *bp)) + struct rte_storage **bp = &net->routes; + for (struct rte_storage **k=&(*bp)->next; *k; k=&(*k)->next) + if (rte_better(&(*k)->rte, &(*bp)->rte)) bp = k; /* And relink it */ - rte *best = *bp; + struct rte_storage *best = *bp; *bp = best->next; best->next = net->routes; net->routes = best; } } - else if (new) + else if (new_stored) { /* The third case - the new route is not better than the old best route (therefore old_best != NULL) and the old best route was not removed (therefore old_best == net->routes). We just link the new route to the old/last position. */ - new->next = *pos; - *pos = new; + new_stored->next = *before_old; + *before_old = new_stored; table->rt_count++; } /* The fourth (empty) case - suboptimal route was removed, nothing to do */ } - if (new) + if (new_stored) { - new->lastmod = current_time(); + new_stored->rte.lastmod = current_time(); if (!old) { - new->id = hmap_first_zero(&table->id_map); - hmap_set(&table->id_map, new->id); + new_stored->rte.id = hmap_first_zero(&table->id_map); + hmap_set(&table->id_map, new_stored->rte.id); } else - new->id = old->id; + new_stored->rte.id = old->id; } /* Log the route change */ if ((c->debug & D_ROUTES) || (p->debug & D_ROUTES)) { if (new_ok) - rte_trace(c, new, '>', new == net->routes ? "added [best]" : "added"); + rte_trace(c, &new_stored->rte, '>', new_stored == net->routes ? "added [best]" : "added"); else if (old_ok) { if (old != old_best) rte_trace(c, old, '>', "removed"); - else if (rte_is_ok(net->routes)) + else if (net->routes && rte_is_ok(&net->routes->rte)) rte_trace(c, old, '>', "removed [replaced]"); else rte_trace(c, old, '>', "removed [sole]"); @@ -1472,7 +1375,8 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) } /* Propagate the route change */ - rte_announce(table, RA_UNDEF, net, new, old, net->routes, old_best); + rte_announce(table, RA_UNDEF, net, new_stored, old_stored, + net->routes, old_best_stored); if (!net->routes && (table->gc_counter++ >= table->config->gc_max_ops) && @@ -1482,14 +1386,14 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) if (old_ok && p->rte_remove) p->rte_remove(net, old); if (new_ok && p->rte_insert) - p->rte_insert(net, new); + p->rte_insert(net, &new_stored->rte); if (old) { - if (!new) + if (!new_stored) hmap_clear(&table->id_map, old->id); - rte_free_quick(old); + rte_free(old_stored, table); } } @@ -1508,51 +1412,14 @@ rte_update_unlock(void) lp_flush(rte_update_pool); } -/** - * rte_update - enter a new update to a routing table - * @table: table to be updated - * @c: channel doing the update - * @net: network node - * @p: protocol submitting the update - * @src: protocol originating the update - * @new: a &rte representing the new route or %NULL for route removal. - * - * This function is called by the routing protocols whenever they discover - * a new route or wish to update/remove an existing route. The right announcement - * sequence is to build route attributes first (either un-cached with @aflags set - * to zero or a cached one using rta_lookup(); in this case please note that - * you need to increase the use count of the attributes yourself by calling - * rta_clone()), call rte_get_temp() to obtain a temporary &rte, fill in all - * the appropriate data and finally submit the new &rte by calling rte_update(). - * - * @src specifies the protocol that originally created the route and the meaning - * of protocol-dependent data of @new. If @new is not %NULL, @src have to be the - * same value as @new->attrs->proto. @p specifies the protocol that called - * rte_update(). In most cases it is the same protocol as @src. rte_update() - * stores @p in @new->sender; - * - * When rte_update() gets any route, it automatically validates it (checks, - * whether the network and next hop address are valid IP addresses and also - * whether a normal routing protocol doesn't try to smuggle a host or link - * scope route to the table), converts all protocol dependent attributes stored - * in the &rte to temporary extended attributes, consults import filters of the - * protocol to see if the route should be accepted and/or its attributes modified, - * stores the temporary attributes back to the &rte. - * - * Now, having a "public" version of the route, we - * automatically find any old route defined by the protocol @src - * for network @n, replace it by the new one (or removing it if @new is %NULL), - * recalculate the optimal route for this destination and finally broadcast - * the change (if any) to all routing protocols by calling rte_announce(). - * - * All memory used for attribute lists and other temporary allocations is taken - * from a special linear pool @rte_update_pool and freed when rte_update() - * finishes. - */ +static int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src); void -rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) +rte_update(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { + if (c->in_table && !rte_update_in(c, n, new, src)) + return; + // struct proto *p = c->proto; struct proto_stats *stats = &c->stats; const struct filter *filter = c->in_filter; @@ -1563,12 +1430,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) rte_update_lock(); if (new) { - /* Create a temporary table node */ - nn = alloca(sizeof(net) + n->length); - memset(nn, 0, sizeof(net) + n->length); - net_copy(nn->n.addr, n); - - new->net = nn; + new->net = n; new->sender = c; stats->imp_updates_received++; @@ -1592,7 +1454,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) } else if (filter) { - int fr = f_run(filter, &new, rte_update_pool, 0); + int fr = f_run(filter, new, rte_update_pool, 0); if (fr > F_ACCEPT) { stats->imp_updates_filtered++; @@ -1604,13 +1466,10 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) new->flags |= REF_FILTERED; } } - if (!rta_is_cached(new->attrs)) /* Need to copy attributes */ - new->attrs = rta_lookup(new->attrs); - new->flags |= REF_COW; /* Use the actual struct network, not the dummy one */ nn = net_get(c->table, n); - new->net = nn; + new->net = nn->n.addr; } else { @@ -1632,7 +1491,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) return; drop: - rte_free(new); new = NULL; if (nn = net_find(c->table, n)) goto recalc; @@ -1643,8 +1501,8 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) /* Independent call to rte_announce(), used from next hop recalculation, outside of rte_update(). new must be non-NULL */ static inline void -rte_announce_i(rtable *tab, uint type, net *net, rte *new, rte *old, - rte *new_best, rte *old_best) +rte_announce_i(rtable *tab, uint type, net *net, struct rte_storage *new, struct rte_storage *old, + struct rte_storage *new_best, struct rte_storage *old_best) { rte_update_lock(); rte_announce(tab, type, net, new, old, new_best, old_best); @@ -1652,16 +1510,16 @@ rte_announce_i(rtable *tab, uint type, net *net, rte *new, rte *old, } static inline void -rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */ +rte_discard(net *net, rte *old) /* Non-filtered route deletion, used during garbage collection */ { rte_update_lock(); - rte_recalculate(old->sender, old->net, NULL, old->src); + rte_recalculate(old->sender, net, NULL, old->src); rte_update_unlock(); } /* Modify existing route by protocol hook, used for long-lived graceful restart */ static inline void -rte_modify(rte *old) +rte_modify(net *net, rte *old) { rte_update_lock(); @@ -1669,13 +1527,9 @@ rte_modify(rte *old) if (new != old) { if (new) - { - if (!rta_is_cached(new->attrs)) - new->attrs = rta_lookup(new->attrs); - new->flags = (old->flags & ~REF_MODIFY) | REF_COW; - } + new->flags = old->flags & ~REF_MODIFY; - rte_recalculate(old->sender, old->net, new, old->src); + rte_recalculate(old->sender, net, new, old->src); } rte_update_unlock(); @@ -1683,25 +1537,22 @@ rte_modify(rte *old) /* Check rtable for best route to given net whether it would be exported do p */ int -rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter) +rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter) { net *n = net_find(t, a); - rte *rt = n ? n->routes : NULL; - if (!rte_is_valid(rt)) + if (!n || !rte_is_valid(n->routes)) return 0; + rte rt = n->routes->rte; + rte_update_lock(); /* Rest is stripped down export_filter() */ - int v = p->preexport ? p->preexport(p, rt) : 0; + int v = c->proto->preexport ? c->proto->preexport(c, &rt) : 0; if (v == RIC_PROCESS) v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); - /* Discard temporary rte */ - if (rt != n->routes) - rte_free(rt); - rte_update_unlock(); return v > 0; @@ -1727,10 +1578,9 @@ rt_refresh_begin(rtable *t, struct channel *c) { FIB_WALK(&t->fib, net, n) { - rte *e; - for (e = n->routes; e; e = e->next) - if (e->sender == c) - e->flags |= REF_STALE; + for (struct rte_storage *e = n->routes; e; e = e->next) + if (e->rte.sender == c) + e->rte.flags |= REF_STALE; } FIB_WALK_END; } @@ -1750,11 +1600,10 @@ rt_refresh_end(rtable *t, struct channel *c) FIB_WALK(&t->fib, net, n) { - rte *e; - for (e = n->routes; e; e = e->next) - if ((e->sender == c) && (e->flags & REF_STALE)) + for (struct rte_storage *e = n->routes; e; e = e->next) + if ((e->rte.sender == c) && (e->rte.flags & REF_STALE)) { - e->flags |= REF_DISCARD; + e->rte.flags |= REF_DISCARD; prune = 1; } } @@ -1771,11 +1620,10 @@ rt_modify_stale(rtable *t, struct channel *c) FIB_WALK(&t->fib, net, n) { - rte *e; - for (e = n->routes; e; e = e->next) - if ((e->sender == c) && (e->flags & REF_STALE) && !(e->flags & REF_FILTERED)) + for (struct rte_storage *e = n->routes; e; e = e->next) + if ((e->rte.sender == c) && (e->rte.flags & REF_STALE) && !(e->rte.flags & REF_FILTERED)) { - e->flags |= REF_MODIFY; + e->rte.flags |= REF_MODIFY; prune = 1; } } @@ -1792,12 +1640,11 @@ rt_modify_stale(rtable *t, struct channel *c) * This functions dumps contents of a &rte to debug output. */ void -rte_dump(rte *e) +rte_dump(struct rte_storage *e) { - net *n = e->net; - debug("%-1N ", n->n.addr); - debug("PF=%02x ", e->pflags); - rta_dump(e->attrs); + debug("%-1N ", e->rte.net); + debug("PF=%02x ", e->rte.pflags); + rta_dump(e->rte.attrs); debug("\n"); } @@ -1816,8 +1663,7 @@ rt_dump(rtable *t) #endif FIB_WALK(&t->fib, net, n) { - rte *e; - for(e=n->routes; e; e=e->next) + for(struct rte_storage *e=n->routes; e; e=e->next) rte_dump(e); } FIB_WALK_END; @@ -2104,6 +1950,8 @@ rt_setup(pool *pp, struct rtable_config *cf) rtable *t = ralloc(p, &rt_class); t->rp = p; + t->rte_slab = sl_new(p, sizeof(struct rte_storage)); + t->name = cf->name; t->config = cf; t->addr_type = cf->addr_type; @@ -2152,7 +2000,6 @@ rt_init(void) rta_init(); rt_table_pool = rp_new(&root_pool, "Routing tables"); rte_update_pool = lp_new_default(rt_table_pool); - rte_slab = sl_new(rt_table_pool, sizeof(rte)); init_list(&routing_tables); } @@ -2209,8 +2056,6 @@ rt_prune_table(rtable *tab) again: FIB_ITERATE_START(&tab->fib, fit, net, n) { - rte *e; - rescan: if (limit <= 0) { @@ -2219,19 +2064,19 @@ again: return; } - for (e=n->routes; e; e=e->next) + for (struct rte_storage *e=n->routes; e; e=e->next) { - if (e->sender->flush_active || (e->flags & REF_DISCARD)) + if (e->rte.sender->flush_active || (e->rte.flags & REF_DISCARD)) { - rte_discard(e); + rte_discard(n, &e->rte); limit--; goto rescan; } - if (e->flags & REF_MODIFY) + if (e->rte.flags & REF_MODIFY) { - rte_modify(e); + rte_modify(n, &e->rte); limit--; goto rescan; @@ -2498,8 +2343,8 @@ rta_next_hop_outdated(rta *a) (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh)); } -static inline rte * -rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) +static inline struct rte_storage * +rt_next_hop_update_rte(rtable *tab, net *n, rte *old) { if (!rta_next_hop_outdated(old->attrs)) return NULL; @@ -2513,12 +2358,10 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) rta_apply_hostentry(a, old->attrs->hostentry, &mls); a->cached = 0; - rte *e = sl_alloc(rte_slab); - memcpy(e, old, sizeof(rte)); - e->attrs = rta_lookup(a); - rt_lock_source(e->src); + rte e0 = *old; + e0.attrs = a; - return e; + return rte_store(&e0, n, tab); } @@ -2587,7 +2430,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i /* Find best-match BGP unicast route for flowspec dst prefix */ net *nb = net_route(tab_ip, &dst); - rte *rb = nb ? nb->routes : NULL; + const rte *rb = nb ? &nb->routes->rte : NULL; /* Register prefix to trie for tracking further changes */ int max_pxlen = (n->type == NET_FLOW4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH; @@ -2622,7 +2465,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i if (!nc) continue; - rte *rc = nc->routes; + const rte *rc = &nc->routes->rte; if (rc->attrs->source != RTS_BGP) return 0; @@ -2636,8 +2479,8 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i #endif /* CONFIG_BGP */ -static rte * -rt_flowspec_update_rte(rtable *tab, rte *r) +static struct rte_storage * +rt_flowspec_update_rte(rtable *tab, net *n, rte *r) { #ifdef CONFIG_BGP if (r->attrs->source != RTS_BGP) @@ -2647,9 +2490,8 @@ rt_flowspec_update_rte(rtable *tab, rte *r) if (!bc->base_table) return NULL; - const net_addr *n = r->net->n.addr; struct bgp_proto *p = (void *) r->src->proto; - int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior); + int valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior); int dest = valid ? RTD_NONE : RTD_UNREACHABLE; if (dest == r->attrs->dest) @@ -2660,11 +2502,11 @@ rt_flowspec_update_rte(rtable *tab, rte *r) a->dest = dest; a->cached = 0; - rte *new = sl_alloc(rte_slab); - memcpy(new, r, sizeof(rte)); - new->attrs = rta_lookup(a); + rte new; + memcpy(&new, r, sizeof(rte)); + new.attrs = a; - return new; + return rte_store(&new, n, tab); #else return NULL; #endif @@ -2674,7 +2516,7 @@ rt_flowspec_update_rte(rtable *tab, rte *r) static inline int rt_next_hop_update_net(rtable *tab, net *n) { - rte **k, *e, *new, *old_best, **new_best; + struct rte_storage **k, *e, *new, *old_best, **new_best; int count = 0; int free_old_best = 0; @@ -2685,24 +2527,25 @@ rt_next_hop_update_net(rtable *tab, net *n) for (k = &n->routes; e = *k; k = &e->next) { if (!net_is_flow(n->n.addr)) - new = rt_next_hop_update_rte(tab, e); + new = rt_next_hop_update_rte(tab, n, &e->rte); else - new = rt_flowspec_update_rte(tab, e); + new = rt_flowspec_update_rte(tab, n, &e->rte); if (new) { + new->next = e->next; *k = new; - rte_trace_in(D_ROUTES, new->sender, new, "updated"); + rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated"); rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL); /* Call a pre-comparison hook */ /* Not really an efficient way to compute this */ - if (e->src->proto->rte_recalculate) - e->src->proto->rte_recalculate(tab, n, new, e, NULL); + if (e->rte.src->proto->rte_recalculate) + e->rte.src->proto->rte_recalculate(tab, n, &new->rte, &e->rte, NULL); if (e != old_best) - rte_free_quick(e); + rte_free(e, tab); else /* Freeing of the old best rte is postponed */ free_old_best = 1; @@ -2718,7 +2561,7 @@ rt_next_hop_update_net(rtable *tab, net *n) new_best = NULL; for (k = &n->routes; e = *k; k = &e->next) { - if (!new_best || rte_better(e, *new_best)) + if (!new_best || rte_better(&e->rte, &(*new_best)->rte)) new_best = k; } @@ -2733,13 +2576,13 @@ rt_next_hop_update_net(rtable *tab, net *n) /* Announce the new best route */ if (new != old_best) - rte_trace_in(D_ROUTES, new->sender, new, "updated [best]"); + rte_trace_in(D_ROUTES, new->rte.sender, &new->rte, "updated [best]"); /* Propagate changes */ rte_announce_i(tab, RA_UNDEF, n, NULL, NULL, n->routes, old_best); if (free_old_best) - rte_free_quick(old_best); + rte_free(old_best, tab); return count; } @@ -2928,7 +2771,10 @@ do_feed_channel(struct channel *c, net *n, rte *e) else if (c->ra_mode == RA_MERGED) rt_notify_merged(c, n, NULL, NULL, e, e, c->refeeding); else /* RA_BASIC */ - rt_notify_basic(c, n, e, e, c->refeeding); + { + rte e0 = *e; + rt_notify_basic(c, n->n.addr, &e0, &e0, c->refeeding); + } rte_update_unlock(); } @@ -2957,7 +2803,7 @@ rt_feed_channel(struct channel *c) FIB_ITERATE_START(&c->table->fib, fit, net, n) { - rte *e = n->routes; + struct rte_storage *e = n->routes; if (max_feed <= 0) { FIB_ITERATE_PUT(fit); @@ -2973,7 +2819,7 @@ rt_feed_channel(struct channel *c) if (c->export_state != ES_FEEDING) goto done; - do_feed_channel(c, n, e); + do_feed_channel(c, n, &e->rte); max_feed--; } @@ -2987,7 +2833,7 @@ rt_feed_channel(struct channel *c) if (!rte_is_valid(e)) continue; - do_feed_channel(c, n, e); + do_feed_channel(c, n, &e->rte); max_feed--; } } @@ -3021,20 +2867,14 @@ rt_feed_channel_abort(struct channel *c) * Import table */ -int +static int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { struct rtable *tab = c->in_table; - rte *old, **pos; net *net; if (new) - { net = net_get(tab, n); - - if (!rta_is_cached(new->attrs)) - new->attrs = rta_lookup(new->attrs); - } else { net = net_find(tab, n); @@ -3044,9 +2884,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } /* Find the old rte */ - for (pos = &net->routes; old = *pos; pos = &old->next) - if (old->src == src) + struct rte_storage **pos = rte_find(net, src); + if (*pos) { + rte *old = &(*pos)->rte; if (new && rte_same(old, new)) { /* Refresh the old rte, continue with update to main rtable */ @@ -3060,22 +2901,20 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } /* Move iterator if needed */ - if (old == c->reload_next_rte) - c->reload_next_rte = old->next; + if (*pos == c->reload_next_rte) + c->reload_next_rte = (*pos)->next; /* Remove the old rte */ - *pos = old->next; - rte_free_quick(old); + struct rte_storage *del = *pos; + *pos = (*pos)->next; + rte_free(del, tab); tab->rt_count--; - - break; } + else if (!new) + goto drop_withdraw; if (!new) { - if (!old) - goto drop_withdraw; - if (!net->routes) fib_delete(&tab->fib, net); @@ -3083,7 +2922,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } struct channel_limit *l = &c->rx_limit; - if (l->action && !old) + if (l->action && !*pos) { if (tab->rt_count >= l->limit) channel_notify_limit(c, l, PLD_RX, tab->rt_count); @@ -3091,7 +2930,7 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr if (l->state == PLS_BLOCKED) { /* Required by rte_trace_in() */ - new->net = net; + new->net = n; rte_trace_in(D_FILTERS, c, new, "ignored [limit]"); goto drop_update; @@ -3099,11 +2938,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } /* Insert the new rte */ - rte *e = rte_do_cow(new); - e->flags |= REF_COW; - e->net = net; - e->sender = c; - e->lastmod = current_time(); + struct rte_storage *e = rte_store(new, net, tab); + e->rte.sender = c; + e->rte.lastmod = current_time(); e->next = *pos; *pos = e; tab->rt_count++; @@ -3112,7 +2949,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr drop_update: c->stats.imp_updates_received++; c->stats.imp_updates_ignored++; - rte_free(new); if (!net->routes) fib_delete(&tab->fib, net); @@ -3141,7 +2977,7 @@ rt_reload_channel(struct channel *c) } do { - for (rte *e = c->reload_next_rte; e; e = e->next) + for (struct rte_storage *e = c->reload_next_rte; e; e = e->next) { if (max_feed-- <= 0) { @@ -3150,7 +2986,8 @@ rt_reload_channel(struct channel *c) return 0; } - rte_update2(c, e->net->n.addr, rte_do_cow(e), e->src); + rte r = e->rte; + rte_update(c, r.net, &r, r.src); } c->reload_next_rte = NULL; @@ -3193,14 +3030,14 @@ rt_prune_sync(rtable *t, int all) again: FIB_ITERATE_START(&t->fib, &fit, net, n) { - rte *e, **ee = &n->routes; + struct rte_storage *e, **ee = &n->routes; while (e = *ee) { - if (all || (e->flags & (REF_STALE | REF_DISCARD))) + if (all || (e->rte.flags & (REF_STALE | REF_DISCARD))) { *ee = e->next; - rte_free_quick(e); + rte_free(e, t); t->rt_count--; } else @@ -3223,20 +3060,16 @@ again: */ int -rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **old_exported, int refeed) +rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, struct rte_storage **old_exported, int refeed) { struct rtable *tab = c->out_table; struct rte_src *src; - rte *old, **pos; net *net; if (new) { net = net_get(tab, n); src = new->src; - - if (!rta_is_cached(new->attrs)) - new->attrs = rta_lookup(new->attrs); } else { @@ -3248,30 +3081,19 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte ** } /* Find the old rte */ - for (pos = &net->routes; old = *pos; pos = &old->next) - if ((c->ra_mode != RA_ANY) || (old->src == src)) - { - if (new && rte_same(old, new)) - { - /* 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; - } - */ + struct rte_storage **pos = (c->ra_mode == RA_ANY) ? rte_find(net, src) : &net->routes; + struct rte_storage *old = NULL; - goto drop_update; - } + if (old = *pos) + { + if (new && rte_same(&(*pos)->rte, new)) + goto drop_update; - /* Remove the old rte */ - *pos = old->next; - *old_exported = old; - tab->rt_count--; - - break; - } + /* Remove the old rte */ + *pos = old->next; + *old_exported = old; + tab->rt_count--; + } if (!new) { @@ -3285,11 +3107,8 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte ** } /* Insert the new rte */ - rte *e = rte_do_cow(new); - e->flags |= REF_COW; - e->net = net; - e->sender = c; - e->lastmod = current_time(); + struct rte_storage *e = rte_store(new, net, tab); + e->rte.lastmod = current_time(); e->next = *pos; *pos = e; tab->rt_count++; @@ -3501,8 +3320,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) net *n = net_route(tab, &he_addr); if (n) { - rte *e = n->routes; - rta *a = e->attrs; + struct rte_storage *e = n->routes; + rta *a = e->rte.attrs; pxlen = n->n.addr->pxlen; if (a->hostentry) @@ -3533,7 +3352,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he) he->src = rta_clone(a); he->dest = a->dest; he->nexthop_linkable = !direct; - he->igp_metric = rt_get_igp_metric(e); + he->igp_metric = rt_get_igp_metric(&e->rte); } done: diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 30809000..c7d78b33 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -681,11 +681,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) if (!neigh_find(&p->p, r->next_hop, r->neigh->ifa->iface, 0)) a0.nh.flags = RNF_ONLINK; - rta *a = rta_lookup(&a0); - rte *rte = rte_get_temp(a, p->p.main_source); + rte e0 = { + .attrs = &a0, + .src = p->p.main_source, + }; e->unreachable = 0; - rte_update2(c, e->n.addr, rte, p->p.main_source); + rte_update(c, e->n.addr, &e0, p->p.main_source); } else if (e->valid && (e->router_id != p->router_id)) { @@ -697,18 +699,19 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) .pref = 1, }; - rta *a = rta_lookup(&a0); - rte *rte = rte_get_temp(a, p->p.main_source); - rte->pflags = 0; + rte e0 = { + .attrs = &a0, + .src = p->p.main_source, + }; e->unreachable = 1; - rte_update2(c, e->n.addr, rte, p->p.main_source); + rte_update(c, e->n.addr, &e0, p->p.main_source); } else { /* Retraction */ e->unreachable = 0; - rte_update2(c, e->n.addr, NULL, p->p.main_source); + rte_update(c, e->n.addr, NULL, p->p.main_source); } } @@ -718,7 +721,7 @@ babel_announce_retraction(struct babel_proto *p, struct babel_entry *e) { struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel; e->unreachable = 0; - rte_update2(c, e->n.addr, NULL, p->p.main_source); + rte_update(c, e->n.addr, NULL, p->p.main_source); } @@ -2257,11 +2260,11 @@ babel_kick_timer(struct babel_proto *p) static int -babel_preexport(struct proto *P, struct rte *new) +babel_preexport(struct channel *c, struct rte *new) { struct rta *a = new->attrs; /* Reject our own unreachable routes */ - if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P)) + if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto)) return -1; return 0; @@ -2272,8 +2275,8 @@ babel_preexport(struct proto *P, struct rte *new) * so store it into our data structures. */ static void -babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, - struct rte *new, struct rte *old UNUSED) +babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net, + struct rte *new, const struct rte *old UNUSED) { struct babel_proto *p = (void *) P; struct babel_entry *e; @@ -2301,11 +2304,11 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, if (rt_metric > BABEL_INFINITY) { log(L_WARN "%s: Invalid babel_metric value %u for route %N", - p->p.name, rt_metric, net->n.addr); + p->p.name, rt_metric, net); rt_metric = BABEL_INFINITY; } - e = babel_get_entry(p, net->n.addr); + e = babel_get_entry(p, net); /* Activate triggered updates */ if ((e->valid != BABEL_ENTRY_VALID) || @@ -2323,7 +2326,7 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net, else { /* Withdraw */ - e = babel_find_entry(p, net->n.addr); + e = babel_find_entry(p, net); if (!e || e->valid != BABEL_ENTRY_VALID) return; diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 65e87c96..1b36368f 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -336,26 +336,26 @@ bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric) } int -bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad) +bgp_total_aigp_metric_(struct rta *a, u64 *metric, const struct adata **ad) { - eattr *a = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP)); - if (!a) + eattr *ea = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP)); + if (!ea) return 0; - const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC); + const byte *b = bgp_aigp_get_tlv(ea->u.ptr, BGP_AIGP_METRIC); if (!b) return 0; u64 aigp = get_u64(b + 3); - u64 step = e->attrs->igp_metric; + u64 step = a->igp_metric; - if (!rte_resolvable(e) || (step >= IGP_METRIC_UNKNOWN)) + if (!rta_resolvable(a) || (step >= IGP_METRIC_UNKNOWN)) step = BGP_AIGP_MAX; if (!step) step = 1; - *ad = a->u.ptr; + *ad = ea->u.ptr; *metric = aigp + step; if (*metric < aigp) *metric = BGP_AIGP_MAX; @@ -377,7 +377,7 @@ bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad) u32 bgp_rte_igp_metric(struct rte *rt) { - u64 metric = bgp_total_aigp_metric(rt); + u64 metric = bgp_total_aigp_metric(rt->attrs); return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN); } @@ -906,7 +906,7 @@ bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint fla static void bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a) { - net_addr *n = s->route->net->n.addr; + const net_addr *n = s->route->net; u32 *labels = (u32 *) a->u.ptr->data; uint lnum = a->u.ptr->length / 4; @@ -1631,7 +1631,7 @@ bgp_free_prefix_table(struct bgp_channel *c) } static struct bgp_prefix * -bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id) +bgp_get_prefix(struct bgp_channel *c, const net_addr *net, u32 path_id) { u32 hash = net_hash(net) ^ u32_hash(path_id); struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash); @@ -1675,10 +1675,10 @@ bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px) */ int -bgp_preexport(struct proto *P, rte *e) +bgp_preexport(struct channel *c, rte *e) { struct proto *SRC = e->src->proto; - struct bgp_proto *p = (struct bgp_proto *) P; + struct bgp_proto *p = (struct bgp_proto *) (c->proto); struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL; /* Reject our routes */ @@ -1690,8 +1690,8 @@ bgp_preexport(struct proto *P, rte *e) return 0; /* Reject flowspec that failed validation */ - if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr)) - return -1; + if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net)) + return -1; /* IBGP route reflection, RFC 4456 */ if (p->is_internal && src->is_internal && (p->local_as == src->local_as)) @@ -1707,11 +1707,11 @@ bgp_preexport(struct proto *P, rte *e) } /* Handle well-known communities, RFC 1997 */ - struct eattr *c; + struct eattr *com; if (p->cf->interpret_communities && - (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)))) + (com = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)))) { - const struct adata *d = c->u.ptr; + const struct adata *d = com->u.ptr; /* Do not export anywhere */ if (int_set_contains(d, BGP_COMM_NO_ADVERTISE)) @@ -1791,7 +1791,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at /* AIGP attribute - accumulate local metric or originate new one */ u64 metric; if (s.local_next_hop && - (bgp_total_aigp_metric_(e, &metric, &ad) || + (bgp_total_aigp_metric_(e->attrs, &metric, &ad) || (c->cf->aigp_originate && bgp_init_aigp_metric(e, &metric, &ad)))) { ad = bgp_aigp_set_metric(pool, ad, metric); @@ -1850,7 +1850,7 @@ bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *at } void -bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) +bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old) { struct bgp_proto *p = (void *) P; struct bgp_channel *c = (void *) C; @@ -1864,7 +1864,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) /* Error during attribute processing */ if (!attrs) - log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n->n.addr); + log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n); /* If attributes are invalid, we fail back to withdraw */ buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c); @@ -1876,7 +1876,7 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old) path = old->src->global_id; } - px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0); + px = bgp_get_prefix(c, n, c->add_path_tx ? path : 0); add_tail(&buck->prefixes, &px->buck_node); bgp_schedule_packet(p->conn, c, PKT_UPDATE); @@ -1937,8 +1937,8 @@ bgp_rte_better(rte *new, rte *old) return 1; /* RFC 4271 9.1.2.1. Route resolvability test */ - n = rte_resolvable(new); - o = rte_resolvable(old); + n = rta_resolvable(new->attrs); + o = rta_resolvable(old->attrs); if (n > o) return 1; if (n < o) @@ -1963,8 +1963,8 @@ bgp_rte_better(rte *new, rte *old) return 0; /* RFC 7311 4.1 - Apply AIGP metric */ - u64 n2 = bgp_total_aigp_metric(new); - u64 o2 = bgp_total_aigp_metric(old); + u64 n2 = bgp_total_aigp_metric(new->attrs); + u64 o2 = bgp_total_aigp_metric(old->attrs); if (n2 < o2) return 1; if (n2 > o2) @@ -2079,7 +2079,7 @@ bgp_rte_mergable(rte *pri, rte *sec) return 0; /* RFC 4271 9.1.2.1. Route resolvability test */ - if (rte_resolvable(pri) != rte_resolvable(sec)) + if (rta_resolvable(pri->attrs) != rta_resolvable(sec->attrs)) return 0; /* Start with local preferences */ @@ -2148,16 +2148,15 @@ same_group(rte *r, u32 lpref, u32 lasn) } static inline int -use_deterministic_med(rte *r) +use_deterministic_med(struct rte_storage *r) { - struct proto *P = r->src->proto; + struct proto *P = r->rte.src->proto; return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med; } int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) { - rte *r, *s; rte *key = new ? new : old; u32 lpref = key->attrs->pref; u32 lasn = bgp_get_neighbor(key); @@ -2225,13 +2224,13 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) } /* The default case - find a new best-in-group route */ - r = new; /* new may not be in the list */ - for (s=net->routes; rte_is_valid(s); s=s->next) - if (use_deterministic_med(s) && same_group(s, lpref, lasn)) + rte *r = new; /* new may not be in the list */ + for (struct rte_storage *s = net->routes; rte_is_valid(s); s = s->next) + if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn)) { - s->pflags |= BGP_REF_SUPPRESSED; - if (!r || bgp_rte_better(s, r)) - r = s; + s->rte.pflags |= BGP_REF_SUPPRESSED; + if (!r || bgp_rte_better(&s->rte, r)) + r = &s->rte; } /* Simple case - the last route in group disappears */ @@ -2243,10 +2242,10 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) 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)) - s->pflags &= ~BGP_REF_SUPPRESSED; + for (struct rte_storage *s = net->routes; rte_is_valid(s); s = s->next) + if (use_deterministic_med(s) && same_group(&s->rte, lpref, lasn)) + if ((&s->rte != r) && bgp_rte_mergable(r, &s->rte)) + s->rte.pflags &= ~BGP_REF_SUPPRESSED; /* Found best-in-group */ r->pflags &= ~BGP_REF_SUPPRESSED; @@ -2281,12 +2280,12 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) return !old_suppressed; } -struct rte * +rte * bgp_rte_modify_stale(struct rte *r, struct linpool *pool) { - eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); - const struct adata *ad = a ? a->u.ptr : NULL; - uint flags = a ? a->flags : BAF_PARTIAL; + eattr *ea = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); + const struct adata *ad = ea ? ea->u.ptr : NULL; + uint flags = ea ? ea->flags : BAF_PARTIAL; if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR)) return NULL; @@ -2294,12 +2293,17 @@ bgp_rte_modify_stale(struct rte *r, struct linpool *pool) if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE)) return r; - r = rte_cow_rta(r, pool); - bgp_set_attr_ptr(&(r->attrs->eattrs), pool, BA_COMMUNITY, flags, - int_set_add(pool, ad, BGP_COMM_LLGR_STALE)); - r->pflags |= BGP_REF_STALE; + rta *a = rta_do_cow(r->attrs, pool); + + _Thread_local static rte e0; + e0 = *r; + e0.attrs = a; - return r; + bgp_set_attr_ptr(&(a->eattrs), pool, BA_COMMUNITY, flags, + int_set_add(pool, ad, BGP_COMM_LLGR_STALE)); + e0.pflags |= BGP_REF_STALE; + + return &e0; } @@ -2390,14 +2394,14 @@ bgp_get_route_info(rte *e, byte *buf) if (rte_stale(e)) buf += bsprintf(buf, "s"); - u64 metric = bgp_total_aigp_metric(e); + u64 metric = bgp_total_aigp_metric(e->attrs); if (metric < BGP_AIGP_MAX) { buf += bsprintf(buf, "/%lu", metric); } else if (e->attrs->igp_metric) { - if (!rte_resolvable(e)) + if (!rta_resolvable(e->attrs)) buf += bsprintf(buf, "/-"); else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN) buf += bsprintf(buf, "/?"); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index bff49c3a..655b2636 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -518,9 +518,9 @@ struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id); struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id); static inline int -rte_resolvable(rte *rt) +rta_resolvable(rta *a) { - return rt->attrs->dest != RTD_UNREACHABLE; + return a->dest != RTD_UNREACHABLE; } @@ -588,22 +588,22 @@ int bgp_rte_mergable(rte *pri, rte *sec); int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool); u32 bgp_rte_igp_metric(struct rte *); -void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); -int bgp_preexport(struct proto *, struct rte *); +void bgp_rt_notify(struct proto *P, struct channel *C, const net_addr *n, rte *new, const rte *old); +int bgp_preexport(struct channel *, struct rte *); int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); -void bgp_get_route_info(struct rte *, byte *buf); -int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); +void bgp_get_route_info(struct rte *, byte *); +int bgp_total_aigp_metric_(rta *a, u64 *metric, const struct adata **ad); #define BGP_AIGP_METRIC 1 #define BGP_AIGP_MAX U64(0xffffffffffffffff) static inline u64 -bgp_total_aigp_metric(rte *r) +bgp_total_aigp_metric(rta *a) { u64 metric = BGP_AIGP_MAX; const struct adata *ad; - bgp_total_aigp_metric_(r, &metric, &ad); + bgp_total_aigp_metric_(a, &metric, &ad); return metric; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 66f14150..7be34677 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1376,7 +1376,7 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a REPORT("Invalid route %N withdrawn", n); /* Route withdraw */ - rte_update3(&s->channel->c, n, NULL, s->last_src); + rte_update(&s->channel->c, n, NULL, s->last_src); return; } @@ -1389,11 +1389,12 @@ bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a a0->eattrs = ea; } - rta *a = rta_clone(s->cached_rta); - rte *e = rte_get_temp(a, s->last_src); + rte e0 = { + .attrs = s->cached_rta, + .src = s->last_src, + }; - e->pflags = 0; - rte_update3(&s->channel->c, n, e, s->last_src); + rte_update(&s->channel->c, n, &e0, s->last_src); } static void diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index e885611a..03f0d59e 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -460,7 +460,7 @@ mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r) return; fail: - mrt_log(s, "Attribute list too long for %N", r->net->n.addr); + mrt_log(s, "Attribute list too long for %N", r->net); } #endif @@ -512,24 +512,21 @@ mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path) mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype); mrt_rib_table_header(s, n->n.addr); - rte *rt, *rt0; - for (rt0 = n->routes; rt = rt0; rt0 = rt0->next) + for (struct rte_storage *rt, *rt0 = n->routes; rt = rt0; rt0 = rt0->next) { - if (rte_is_filtered(rt)) + if (rte_is_filtered(&rt->rte)) continue; /* Skip routes that should be reported in the other phase */ - if (!s->always_add_path && (!rt->src->private_id != !s->add_path)) + if (!s->always_add_path && (!rt->rte.src->private_id != !s->add_path)) { s->want_add_path = 1; continue; } - if (f_run(s->filter, &rt, s->linpool, 0) <= F_ACCEPT) - mrt_rib_table_entry(s, rt); - - if (rt != rt0) - rte_free(rt); + rte e = rt->rte; + if (f_run(s->filter, &e, s->linpool, 0) <= F_ACCEPT) + mrt_rib_table_entry(s, &e); lp_flush(s->linpool); } diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index f9aa6cd1..22150590 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -107,7 +107,7 @@ #include #include "ospf.h" -static int ospf_preexport(struct proto *P, rte *new); +static int ospf_preexport(struct channel *C, rte *new); static void ospf_reload_routes(struct channel *C); static int ospf_rte_better(struct rte *new, struct rte *old); static u32 ospf_rte_igp_metric(struct rte *rt); @@ -482,13 +482,13 @@ ospf_disp(timer * timer) * import to the filters. */ static int -ospf_preexport(struct proto *P, rte *e) +ospf_preexport(struct channel *c, rte *e) { - struct ospf_proto *p = (struct ospf_proto *) P; + struct ospf_proto *p = (struct ospf_proto *) c->proto; struct ospf_area *oa = ospf_main_area(p); /* Reject our own routes */ - if (e->src->proto == P) + if (e->src->proto == c->proto) return -1; /* Do not export routes to stub areas */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 471bb586..3e208023 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2096,15 +2096,18 @@ again1: .u.data = nf->n.rid, }; - rta *a = rta_lookup(&a0); - rte *e = rte_get_temp(a, p->p.main_source); - rta_free(nf->old_rta); - nf->old_rta = rta_clone(a); + nf->old_rta = rta_lookup(&a0); + + rte e0 = { + .attrs = nf->old_rta, + .src = p->p.main_source, + }; DBG("Mod rte type %d - %N via %I on iface %s, met %d\n", a0.source, nf->fn.addr, a0.gw, a0.iface ? a0.iface->name : "(none)", nf->n.metric1); - rte_update(&p->p, nf->fn.addr, e); + + rte_update(p->p.main_channel, nf->fn.addr, &e0, p->p.main_source); } } else if (nf->old_rta) @@ -2113,7 +2116,7 @@ again1: rta_free(nf->old_rta); nf->old_rta = NULL; - rte_update(&p->p, nf->fn.addr, NULL); + rte_update(p->p.main_channel, nf->fn.addr, NULL, p->p.main_source); } /* Remove unused rt entry, some special entries are persistent */ @@ -2129,7 +2132,6 @@ again1: } FIB_ITERATE_END; - WALK_LIST(oa, p->area_list) { /* Cleanup ASBR hash tables */ diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 52c2a0ce..bb88d20a 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -1300,7 +1300,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa) } void -ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED) +ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED) { struct ospf_proto *p = (struct ospf_proto *) P; struct ospf_area *oa = NULL; /* non-NULL for NSSA-LSA */ @@ -1319,7 +1319,7 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if (!new) { - nf = fib_find(&p->rtf, n->n.addr); + nf = fib_find(&p->rtf, n); if (!nf || !nf->external_rte) return; @@ -1346,14 +1346,14 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if (m1 > LSINFINITY) { log(L_WARN "%s: Invalid ospf_metric1 value %u for route %N", - p->p.name, m1, n->n.addr); + p->p.name, m1, n); m1 = LSINFINITY; } if (m2 > LSINFINITY) { log(L_WARN "%s: Invalid ospf_metric2 value %u for route %N", - p->p.name, m2, n->n.addr); + p->p.name, m2, n); m2 = LSINFINITY; } @@ -1377,12 +1377,12 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte if (ipa_zero(fwd)) { log(L_ERR "%s: Cannot find forwarding address for NSSA-LSA %N", - p->p.name, n->n.addr); + p->p.name, n); return; } } - nf = fib_get(&p->rtf, n->n.addr); + nf = fib_get(&p->rtf, n); ospf_originate_ext_lsa(p, oa, nf, LSA_M_EXPORT, metric, ebit, fwd, tag, 1, p->vpn_pe); nf->external_rte = 1; } diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 535d1f1b..c36d0b50 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -200,7 +200,7 @@ void ospf_originate_sum_rt_lsa(struct ospf_proto *p, struct ospf_area *oa, u32 d void ospf_originate_ext_lsa(struct ospf_proto *p, struct ospf_area *oa, ort *nf, u8 mode, u32 metric, u32 ebit, ip_addr fwaddr, u32 tag, int pbit, int dn); void ospf_originate_gr_lsa(struct ospf_proto *p, struct ospf_iface *ifa); -void ospf_rt_notify(struct proto *P, struct channel *ch, net *n, rte *new, rte *old); +void ospf_rt_notify(struct proto *P, struct channel *ch, const net_addr *n, rte *new, const rte *old); void ospf_update_topology(struct ospf_proto *p); struct top_hash_entry *ospf_hash_find(struct top_graph *, u32 domain, u32 lsa, u32 rtr, u32 type); diff --git a/proto/perf/perf.c b/proto/perf/perf.c index 52784c14..8b2cb69f 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -160,18 +160,17 @@ perf_loop(void *data) clock_gettime(CLOCK_MONOTONIC, &ts_generated); - for (uint i=0; idata[i].a, p->p.main_source); - e->pflags = 0; - - rte_update(P, &(p->data[i].net), e); + for (uint i=0; idata[i].a, .src = P->main_source, }; + rte_update(P->main_channel, &(p->data[i].net), &e0, P->main_source); } clock_gettime(CLOCK_MONOTONIC, &ts_update); if (!p->keep) for (uint i=0; idata[i].net), NULL); + rte_update(P->main_channel, &(p->data[i].net), NULL, P->main_source); clock_gettime(CLOCK_MONOTONIC, &ts_withdraw); @@ -204,7 +203,7 @@ perf_loop(void *data) } static void -perf_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net UNUSED, struct rte *new UNUSED, struct rte *old UNUSED) +perf_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net UNUSED, struct rte *new UNUSED, const struct rte *old UNUSED) { struct perf_proto *p = (struct perf_proto *) P; p->exp++; diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index 97862780..3caa85d0 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -48,14 +48,10 @@ #endif static void -pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old) +pipe_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *new, const rte *old) { struct pipe_proto *p = (void *) P; struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri; - struct rte_src *src; - - rte *e; - rta *a; if (!new && !old) return; @@ -63,45 +59,39 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o if (dst->table->pipe_busy) { log(L_ERR "Pipe loop detected when sending %N to table %s", - n->n.addr, dst->table->name); + n, dst->table->name); return; } + src_ch->table->pipe_busy = 1; + if (new) { - src = new->src; - - a = alloca(rta_size(new->attrs)); + rta *a = alloca(rta_size(new->attrs)); memcpy(a, new->attrs, rta_size(new->attrs)); a->cached = 0; a->hostentry = NULL; - e = rte_get_temp(a, src); - e->pflags = new->pflags; -#ifdef CONFIG_BGP - /* Hack to cleanup cached value */ - if (e->src->proto->proto == &proto_bgp) - e->pflags &= ~(BGP_REF_STALE | BGP_REF_NOT_STALE); -#endif + rte e0 = { + .attrs = a, + .src = new->src, + }; + + rte_update(dst, n, &e0, new->src); } else - { - e = NULL; - src = old->src; - } + rte_update(dst, n, NULL, old->src); - src_ch->table->pipe_busy = 1; - rte_update2(dst, n->n.addr, e, src); src_ch->table->pipe_busy = 0; } static int -pipe_preexport(struct proto *P, rte *e) +pipe_preexport(struct channel *c, rte *e) { struct proto *pp = e->sender->proto; - if (pp == P) + if (pp == c->proto) return -1; /* Avoid local loops automatically */ return 0; diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 540ff2a7..fa228c69 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -385,16 +385,16 @@ radv_trigger_valid(struct radv_config *cf) } static inline int -radv_net_match_trigger(struct radv_config *cf, net *n) +radv_net_match_trigger(struct radv_config *cf, const net_addr *n) { - return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger); + return radv_trigger_valid(cf) && net_equal(n, &cf->trigger); } int -radv_preexport(struct proto *P, rte *new) +radv_preexport(struct channel *c, rte *new) { // struct radv_proto *p = (struct radv_proto *) P; - struct radv_config *cf = (struct radv_config *) (P->cf); + struct radv_config *cf = (struct radv_config *) (c->proto->cf); if (radv_net_match_trigger(cf, new->net)) return RIC_PROCESS; @@ -406,7 +406,7 @@ radv_preexport(struct proto *P, rte *new) } static void -radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED) +radv_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rte *new, const rte *old UNUSED) { struct radv_proto *p = (struct radv_proto *) P; struct radv_config *cf = (struct radv_config *) (P->cf); @@ -457,14 +457,14 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte (preference != RA_PREF_HIGH)) { log(L_WARN "%s: Invalid ra_preference value %u on route %N", - p->p.name, preference, n->n.addr); + p->p.name, preference, n); preference = RA_PREF_MEDIUM; preference_set = 1; lifetime = 0; lifetime_set = 1; } - rt = fib_get(&p->routes, n->n.addr); + rt = fib_get(&p->routes, n); /* Ignore update if nothing changed */ if (rt->valid && @@ -487,7 +487,7 @@ radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte else { /* Withdraw */ - rt = fib_find(&p->routes, n->n.addr); + rt = fib_find(&p->routes, n); if (!rt || !rt->valid) return; @@ -555,7 +555,7 @@ radv_check_active(struct radv_proto *p) return 1; struct channel *c = p->p.main_channel; - return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter); + return rt_examine(c->table, &cf->trigger, c, c->out_filter); } static void diff --git a/proto/rip/rip.c b/proto/rip/rip.c index a501a784..0a9844f3 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -207,16 +207,15 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .u.data = (uintptr_t) a0.nh.iface, }; - rta *a = rta_lookup(&a0); - rte *e = rte_get_temp(a, p->p.main_source); + rte e0 = { + .attrs = &a0, + .src = p->p.main_source, + }; - rte_update(&p->p, en->n.addr, e); + rte_update(p->p.main_channel, en->n.addr, &e0, p->p.main_source); } else - { - /* Withdraw */ - rte_update(&p->p, en->n.addr, NULL); - } + rte_update(p->p.main_channel, en->n.addr, NULL, p->p.main_source); } /** @@ -311,8 +310,8 @@ rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from) * it into our data structures. */ static void -rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new, - struct rte *old UNUSED) +rip_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, struct rte *new, + const struct rte *old UNUSED) { struct rip_proto *p = (struct rip_proto *) P; struct rip_entry *en; @@ -328,14 +327,14 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s if (rt_metric > p->infinity) { log(L_WARN "%s: Invalid rip_metric value %u for route %N", - p->p.name, rt_metric, net->n.addr); + p->p.name, rt_metric, net); rt_metric = p->infinity; } if (rt_tag > 0xffff) { log(L_WARN "%s: Invalid rip_tag value %u for route %N", - p->p.name, rt_tag, net->n.addr); + p->p.name, rt_tag, net); rt_metric = p->infinity; rt_tag = 0; } @@ -347,7 +346,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s * collection. */ - en = fib_get(&p->rtable, net->n.addr); + en = fib_get(&p->rtable, net); old_metric = en->valid ? en->metric : -1; @@ -361,7 +360,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s else { /* Withdraw */ - en = fib_find(&p->rtable, net->n.addr); + en = fib_find(&p->rtable, net); if (!en || en->valid != RIP_ENTRY_VALID) return; diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index be3d19ab..72fbc967 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -127,19 +127,16 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_ .dest = RTD_NONE, }; - rta *a = rta_lookup(&a0); - rte *e = rte_get_temp(a, p->p.main_source); + rte e0 = { .attrs = &a0, .src = p->p.main_source, }; - e->pflags = 0; - - rte_update2(channel, &pfxr->n, e, e->src); + rte_update(channel, &pfxr->n, &e0, p->p.main_source); } void rpki_table_remove_roa(struct rpki_cache *cache, struct channel *channel, const net_addr_union *pfxr) { struct rpki_proto *p = cache->p; - rte_update2(channel, &pfxr->n, NULL, p->p.main_source); + rte_update(channel, &pfxr->n, NULL, p->p.main_source); } diff --git a/proto/static/static.c b/proto/static/static.c index 6d3871cc..6e258f6f 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -103,24 +103,13 @@ static_announce_rte(struct static_proto *p, struct static_route *r) return; /* We skip rta_lookup() here */ - rte *e = rte_get_temp(a, src); - e->pflags = 0; + rte e0 = { .attrs = a, .src = src, .net = r->net, }, *e = &e0; + /* Evaluate the filter */ if (r->cmds) - { - /* Create a temporary table node */ - e->net = alloca(sizeof(net) + r->net->length); - memset(e->net, 0, sizeof(net) + r->net->length); - net_copy(e->net->n.addr, r->net); + f_eval_rte(r->cmds, e, static_lp); - /* Evaluate the filter */ - f_eval_rte(r->cmds, &e, static_lp); - - /* Remove the temporary node */ - e->net = NULL; - } - - rte_update2(p->p.main_channel, r->net, e, src); + rte_update(p->p.main_channel, r->net, e, src); r->state = SRS_CLEAN; if (r->cmds) @@ -132,7 +121,7 @@ withdraw: if (r->state == SRS_DOWN) return; - rte_update2(p->p.main_channel, r->net, NULL, src); + rte_update(p->p.main_channel, r->net, NULL, src); r->state = SRS_DOWN; } @@ -298,7 +287,7 @@ static void static_remove_rte(struct static_proto *p, struct static_route *r) { if (r->state) - rte_update2(p->p.main_channel, r->net, NULL, static_get_source(p, r->index)); + rte_update(p->p.main_channel, r->net, NULL, static_get_source(p, r->index)); static_reset_rte(p, r); } diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index efdb18a3..a37e8786 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -398,7 +398,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) /* p is NULL iff KRT_SHARED_SOCKET and !scan */ int ipv6; - rte *e; net *net; sockaddr dst, gate, mask; ip_addr idst, igate, imask; @@ -519,7 +518,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) net = net_get(p->p.main_channel->table, &ndst); rta a = { - .src = p->p.main_source, .source = RTS_INHERIT, .scope = SCOPE_UNIVERSE, }; @@ -579,13 +577,12 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) } } - done: - e = rte_get_temp(&a); - e->net = net; + done:; + rte e0 = { .attrs = &a, .net = net, }; ea_list *ea = alloca(sizeof(ea_list) + 1 * sizeof(eattr)); - *ea = (ea_list) { .count = 1, .next = e->attrs->eattrs }; - e->attrs->eattrs = ea; + *ea = (ea_list) { .count = 1, .next = e0.attrs->eattrs }; + e0.attrs->eattrs = ea; ea->attrs[0] = (eattr) { .id = EA_KRT_SOURCE, @@ -594,9 +591,9 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) }; if (scan) - krt_got_route(p, e, src); + krt_got_route(p, &e0, src); else - krt_got_route_async(p, e, new, src); + krt_got_route_async(p, &e0, new, src); } static void diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index e103c8ef..35ba116c 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -109,7 +109,7 @@ struct nl_parse_state int scan; int merge; - net *net; + net_addr *net; rta *attrs; struct krt_proto *proto; s8 new; @@ -1325,10 +1325,9 @@ nh_bufsize(struct nexthop *nh) } static int -nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) +nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nexthop *nh) { eattr *ea; - net *net = e->net; rta *a = e->attrs; ea_list *eattrs = a->eattrs; int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh)); @@ -1343,7 +1342,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) int rsize = sizeof(*r) + bufsize; r = alloca(rsize); - DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op); + DBG("nl_send_route(%N,op=%x)\n", e->net, op); bzero(&r->h, sizeof(r->h)); bzero(&r->r, sizeof(r->r)); @@ -1352,7 +1351,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK; r->r.rtm_family = p->af; - r->r.rtm_dst_len = net_pxlen(net->n.addr); + r->r.rtm_dst_len = net_pxlen(e->net); r->r.rtm_protocol = RTPROT_BIRD; r->r.rtm_scope = RT_SCOPE_NOWHERE; #ifdef HAVE_MPLS_KERNEL @@ -1364,7 +1363,7 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) * 2) Never use RTA_PRIORITY */ - u32 label = net_mpls(net->n.addr); + u32 label = net_mpls(e->net); nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label); r->r.rtm_scope = RT_SCOPE_UNIVERSE; r->r.rtm_type = RTN_UNICAST; @@ -1372,12 +1371,12 @@ nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh) else #endif { - nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr)); + nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(e->net)); /* Add source address for IPv6 SADR routes */ - if (net->n.addr->type == NET_IP6_SADR) + if (e->net->type == NET_IP6_SADR) { - net_addr_ip6_sadr *a = (void *) &net->n.addr; + net_addr_ip6_sadr *a = (void *) &e->net; nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix); r->r.rtm_src_len = a->src_pxlen; } @@ -1498,7 +1497,7 @@ nl_add_rte(struct krt_proto *p, rte *e) } static inline int -nl_delete_rte(struct krt_proto *p, rte *e) +nl_delete_rte(struct krt_proto *p, const rte *e) { int err = 0; @@ -1519,7 +1518,7 @@ nl_replace_rte(struct krt_proto *p, rte *e) void -krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old) +krt_replace_rte(struct krt_proto *p, const net_addr *n UNUSED, rte *new, const rte *old) { int err = 0; @@ -1558,7 +1557,7 @@ krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old) } static int -nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family) +nl_mergable_route(struct nl_parse_state *s, const net_addr *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family) { /* Route merging is used for IPv6 scans */ if (!s->scan || (rtm_family != AF_INET6)) @@ -1578,12 +1577,14 @@ nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint static void nl_announce_route(struct nl_parse_state *s) { - rte *e = rte_get_temp(s->attrs, s->proto->p.main_source); - e->net = s->net; + rte e0 = { + .attrs = s->attrs, + .net = s->net, + }; ea_list *ea = alloca(sizeof(ea_list) + 2 * sizeof(eattr)); - *ea = (ea_list) { .count = 2, .next = e->attrs->eattrs }; - e->attrs->eattrs = ea; + *ea = (ea_list) { .count = 2, .next = e0.attrs->eattrs }; + e0.attrs->eattrs = ea; ea->attrs[0] = (eattr) { .id = EA_KRT_SOURCE, @@ -1597,9 +1598,9 @@ nl_announce_route(struct nl_parse_state *s) }; if (s->scan) - krt_got_route(s->proto, e, s->krt_src); + krt_got_route(s->proto, &e0, s->krt_src); else - krt_got_route_async(s->proto, e, s->new, s->krt_src); + krt_got_route_async(s->proto, &e0, s->new, s->krt_src); s->net = NULL; s->attrs = NULL; @@ -1749,16 +1750,14 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) krt_src = KRT_SRC_ALIEN; } - net_addr *n = &dst; + net_addr *net = &dst; if (p->p.net_type == NET_IP6_SADR) { - n = alloca(sizeof(net_addr_ip6_sadr)); - net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst), + net = alloca(sizeof(net_addr_ip6_sadr)); + net_fill_ip6_sadr(net, net6_prefix(&dst), net6_pxlen(&dst), net6_prefix(&src), net6_pxlen(&src)); } - net *net = net_get(p->p.main_channel->table, n); - if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type, i->rtm_family)) nl_announce_route(s); @@ -1778,7 +1777,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (a[RTA_MULTIPATH]) { - struct nexthop *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src); + struct nexthop *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src); if (!nh) SKIP("strange RTA_MULTIPATH\n"); @@ -1792,7 +1791,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) ra->nh.iface = if_find_by_index(oif); if (!ra->nh.iface) { - log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif); + log(L_ERR "KRT: Received route %N with unknown ifindex %u", net, oif); return; } @@ -1819,8 +1818,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0); if (!nbr || (nbr->scope == SCOPE_HOST)) { - log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr, - ra->nh.gw); + log(L_ERR "KRT: Received route %N with strange next-hop %I", net, ra->nh.gw); return; } } @@ -1919,7 +1917,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0) { - log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr); + log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net); return; } @@ -1953,7 +1951,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) if (!s->net) { /* Store the new route */ - s->net = net; + s->net = lp_alloc(s->pool, net->length); + net_copy(s->net, net); + s->attrs = ra; s->proto = p; s->new = new; diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index 7d7ec7e6..0a746631 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -251,14 +251,14 @@ static inline void krt_trace_in(struct krt_proto *p, rte *e, char *msg) { if (p->p.debug & D_PACKETS) - log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg); + log(L_TRACE "%s: %N: %s", p->p.name, e->net, msg); } static inline void krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg) { if (p->p.debug & D_PACKETS) - log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg); + log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net, msg); } /* @@ -299,54 +299,56 @@ krt_uptodate(rte *a, rte *b) static void krt_learn_announce_update(struct krt_proto *p, rte *e) { - net *n = e->net; - rta *aa = rta_clone(e->attrs); - rte *ee = rte_get_temp(aa, p->p.main_source); - rte_update(&p->p, n->n.addr, ee); + rte e0 = { + .attrs = rta_clone(e->attrs), + .src = p->p.main_source, + }; + + rte_update(p->p.main_channel, e->net, &e0, p->p.main_source); } static void -krt_learn_announce_delete(struct krt_proto *p, net *n) +krt_learn_announce_delete(struct krt_proto *p, net_addr *n) { - rte_update(&p->p, n->n.addr, NULL); + rte_update(p->p.main_channel, n, NULL, p->p.main_source); } /* Called when alien route is discovered during scan */ static void krt_learn_scan(struct krt_proto *p, rte *e) { - net *n0 = e->net; - net *n = net_get(p->krt_table, n0->n.addr); - rte *m, **mm; + net *n = net_get(p->krt_table, e->net); + struct rte_storage *m, **mm; - e->attrs = rta_lookup(e->attrs); + struct rte_storage *ee = rte_store(e, n, p->krt_table); - for(mm=&n->routes; m = *mm; mm=&m->next) - if (krt_same_key(m, e)) + for(mm = &n->routes; m = *mm; mm = &m->next) + if (krt_same_key(&m->rte, e)) break; if (m) { - if (krt_uptodate(m, e)) + if (krt_uptodate(&m->rte, e)) { krt_trace_in_rl(&rl_alien, p, e, "[alien] seen"); - rte_free(e); - m->pflags |= KRT_REF_SEEN; + rte_free(ee, p->krt_table); + m->rte.pflags |= KRT_REF_SEEN; } else { krt_trace_in(p, e, "[alien] updated"); *mm = m->next; - rte_free(m); + rte_free(m, p->krt_table); m = NULL; } } else krt_trace_in(p, e, "[alien] created"); + if (!m) { - e->next = n->routes; - n->routes = e; - e->pflags |= KRT_REF_SEEN; + ee->next = n->routes; + n->routes = ee; + ee->rte.pflags |= KRT_REF_SEEN; } } @@ -362,7 +364,7 @@ krt_learn_prune(struct krt_proto *p) again: FIB_ITERATE_START(fib, &fit, net, n) { - rte *e, **ee, *best, **pbest, *old_best; + struct rte_storage *e, **ee, *best, **pbest, *old_best; /* * Note that old_best may be NULL even if there was an old best route in @@ -376,48 +378,48 @@ again: ee = &n->routes; while (e = *ee) { - if (e->pflags & KRT_REF_BEST) + if (e->rte.pflags & KRT_REF_BEST) old_best = e; - if (!(e->pflags & KRT_REF_SEEN)) + if (!(e->rte.pflags & KRT_REF_SEEN)) { *ee = e->next; - rte_free(e); + rte_free(e, p->krt_table); continue; } - if (!best || krt_metric(best) > krt_metric(e)) + if (!best || krt_metric(&best->rte) > krt_metric(&e->rte)) { best = e; pbest = ee; } - e->pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST); + e->rte.pflags &= ~(KRT_REF_SEEN | KRT_REF_BEST); ee = &e->next; } if (!n->routes) { DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen); if (old_best) - krt_learn_announce_delete(p, n); + krt_learn_announce_delete(p, n->n.addr); FIB_ITERATE_PUT(&fit); fib_delete(fib, n); goto again; } - best->pflags |= KRT_REF_BEST; + best->rte.pflags |= KRT_REF_BEST; *pbest = best->next; best->next = n->routes; n->routes = best; if ((best != old_best) || p->reload) { - DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best)); - krt_learn_announce_update(p, best); + DBG("%I/%d: announcing (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(&best->rte)); + krt_learn_announce_update(p, &best->rte); } else - DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(best)); + DBG("%I/%d: uptodate (metric=%d)\n", n->n.prefix, n->n.pxlen, krt_metric(&best->rte)); } FIB_ITERATE_END; @@ -427,68 +429,67 @@ again: static void krt_learn_async(struct krt_proto *p, rte *e, int new) { - net *n0 = e->net; - net *n = net_get(p->krt_table, n0->n.addr); - rte *g, **gg, *best, **bestp, *old_best; + net *n = net_get(p->krt_table, e->net); + struct rte_storage *g, **gg, *best, **bestp, *old_best; ASSERT(!e->attrs->cached); e->attrs->pref = p->p.main_channel->preference; - e->attrs = rta_lookup(e->attrs); + struct rte_storage *ee = rte_store(e, n, p->krt_table); old_best = n->routes; for(gg=&n->routes; g = *gg; gg = &g->next) - if (krt_same_key(g, e)) + if (krt_same_key(&g->rte, e)) break; if (new) { if (g) { - if (krt_uptodate(g, e)) + if (krt_uptodate(&g->rte, e)) { krt_trace_in(p, e, "[alien async] same"); - rte_free(e); + rte_free(ee, p->krt_table); return; } krt_trace_in(p, e, "[alien async] updated"); *gg = g->next; - rte_free(g); + rte_free(g, p->krt_table); } else krt_trace_in(p, e, "[alien async] created"); - e->next = n->routes; - n->routes = e; + ee->next = n->routes; + n->routes = ee; } else if (!g) { krt_trace_in(p, e, "[alien async] delete failed"); - rte_free(e); + rte_free(ee, p->krt_table); return; } else { krt_trace_in(p, e, "[alien async] removed"); *gg = g->next; - rte_free(e); - rte_free(g); + rte_free(ee, p->krt_table); + rte_free(g, p->krt_table); } best = n->routes; bestp = &n->routes; for(gg=&n->routes; g=*gg; gg=&g->next) { - if (krt_metric(best) > krt_metric(g)) + if (krt_metric(&best->rte) > krt_metric(&g->rte)) { best = g; bestp = gg; } - g->pflags &= ~KRT_REF_BEST; + g->rte.pflags &= ~KRT_REF_BEST; } if (best) { - best->pflags |= KRT_REF_BEST; + best->rte.pflags |= KRT_REF_BEST; *bestp = best->next; best->next = n->routes; n->routes = best; @@ -498,9 +499,9 @@ krt_learn_async(struct krt_proto *p, rte *e, int new) { DBG("krt_learn_async: distributing change\n"); if (best) - krt_learn_announce_update(p, best); + krt_learn_announce_update(p, &best->rte); else - krt_learn_announce_delete(p, n); + krt_learn_announce_delete(p, n->n.addr); } } @@ -538,7 +539,7 @@ krt_dump(struct proto *P) 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); + return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->rte.id); } static void @@ -552,26 +553,25 @@ krt_flush_routes(struct krt_proto *p) if (krt_is_installed(p, n)) { /* FIXME: this does not work if gw is changed in export filter */ - krt_replace_rte(p, n, NULL, n->routes); + krt_replace_rte(p, n->n.addr, NULL, &n->routes->rte); } } FIB_WALK_END; } static struct rte * -krt_export_net(struct krt_proto *p, net *net, rte **rt_free) +krt_export_net(struct krt_proto *p, net *net) { struct channel *c = p->p.main_channel; const struct filter *filter = c->out_filter; - rte *rt; if (c->ra_mode == RA_MERGED) - return rt_export_merged(c, net, rt_free, krt_filter_lp, 1); + return rt_export_merged(c, net, krt_filter_lp, 1); - rt = net->routes; - *rt_free = NULL; + static _Thread_local rte rt; + rt = net->routes->rte; - if (!rte_is_valid(rt)) + if (!rte_is_valid(&rt)) return NULL; if (filter == FILTER_REJECT) @@ -587,13 +587,9 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free) accept: - if (rt != net->routes) - *rt_free = rt; - return rt; + return &rt; reject: - if (rt != net->routes) - rte_free(rt); return NULL; } @@ -619,8 +615,7 @@ krt_same_dest(rte *k, rte *e) void krt_got_route(struct krt_proto *p, rte *e, s8 src) { - rte *new = NULL, *rt_free = NULL; - net *n = e->net; + rte *new = NULL; e->pflags = 0; #ifdef KRT_ALLOW_LEARN @@ -636,10 +631,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src) if (KRT_CF->learn) krt_learn_scan(p, e); else - { - krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored"); - rte_free(e); - } + krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored"); return; } #endif @@ -650,10 +642,11 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src) if (!p->ready) goto ignore; - if (!krt_is_installed(p, n)) + net *net = net_find(p->p.main_channel->table, e->net); + if (!net || !krt_is_installed(p, net)) goto delete; - new = krt_export_net(p, n, &rt_free); + new = krt_export_net(p, net); /* Rejected by filters */ if (!new) @@ -686,20 +679,15 @@ ignore: update: krt_trace_in(p, new, "updating"); - krt_replace_rte(p, n, new, e); + krt_replace_rte(p, e->net, new, e); goto done; delete: krt_trace_in(p, e, "deleting"); - krt_replace_rte(p, n, NULL, e); + krt_replace_rte(p, e->net, NULL, e); goto done; done: - rte_free(e); - - if (rt_free) - rte_free(rt_free); - lp_flush(krt_filter_lp); } @@ -717,20 +705,16 @@ krt_prune(struct krt_proto *p) 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)) + if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->rte.id)) { - rte *rt_free = NULL; - rte *new = krt_export_net(p, n, &rt_free); + rte *new = krt_export_net(p, n); if (new) { krt_trace_in(p, new, "installing"); - krt_replace_rte(p, n, new, NULL); + krt_replace_rte(p, n->n.addr, new, NULL); } - if (rt_free) - rte_free(rt_free); - lp_flush(krt_filter_lp); } } @@ -748,7 +732,6 @@ krt_prune(struct krt_proto *p) void krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src) { - net *net = e->net; e->pflags = 0; switch (src) @@ -761,7 +744,7 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src) if (new) { krt_trace_in(p, e, "[redirect] deleting"); - krt_replace_rte(p, net, NULL, e); + krt_replace_rte(p, e->net, NULL, e); } /* If !new, it is probably echo of our deletion */ break; @@ -775,7 +758,6 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src) } #endif } - rte_free(e); } /* @@ -882,10 +864,9 @@ krt_scan_timer_kick(struct krt_proto *p) */ static int -krt_preexport(struct proto *P, rte *e) +krt_preexport(struct channel *c, rte *e) { - // struct krt_proto *p = (struct krt_proto *) P; - if (e->src->proto == P) + if (e->src->proto == c->proto) return -1; if (!krt_capable(e)) @@ -895,8 +876,8 @@ krt_preexport(struct proto *P, rte *e) } static void -krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net, - rte *new, rte *old) +krt_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net, + rte *new, const rte *old) { struct krt_proto *p = (struct krt_proto *) P; diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index 20858cd7..cd4bd07d 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -143,7 +143,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *); int krt_capable(rte *e); void krt_do_scan(struct krt_proto *); -void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old); +void krt_replace_rte(struct krt_proto *p, const net_addr *n, rte *new, const rte *old); int krt_sys_get_attr(const eattr *a, byte *buf, int buflen);