From 69d1ffde4c724882398b3b630ea1199f12c0c288 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 28 Jan 2020 11:42:46 +0100 Subject: Split route data structure to storage (ro) / manipulation (rw) structures. Routes are now allocated only when they are just to be inserted to the table. Updating a route needs a locally allocated route structure. Ownership of the attributes is also now not transfered from protocols to tables and vice versa but just borrowed which should be easier to handle in a multithreaded environment. --- nest/route.h | 78 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 22 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index bb23152b..ade14857 100644 --- a/nest/route.h +++ b/nest/route.h @@ -157,6 +157,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; char *name; /* Name of this table */ list channels; /* List of attached channels (struct channel) */ @@ -202,7 +203,7 @@ struct rt_subscription { #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; @@ -234,18 +235,24 @@ 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 */ @@ -271,6 +278,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; @@ -286,34 +327,27 @@ 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); } void *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); @@ -634,7 +668,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); -- cgit v1.2.3 From 1b9189d5fdab672f91600b7e72a1deeab277eafc Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Wed, 9 Mar 2022 12:30:05 +0100 Subject: Route validity check converted to generic macro dispatch --- nest/route.h | 5 ++++- nest/rt-table.c | 27 ++++++++++++--------------- proto/bgp/attrs.c | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'nest/route.h') diff --git a/nest/route.h b/nest/route.h index ade14857..4944a854 100644 --- a/nest/route.h +++ b/nest/route.h @@ -259,7 +259,10 @@ struct rte_storage { #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); } diff --git a/nest/rt-table.c b/nest/rt-table.c index ee69d7c4..c49400b7 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -170,7 +170,7 @@ net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn) net_addr_roa4 *roa = (void *) fn->addr; net *r = fib_node_to_user(&tab->fib, fn); - if (net_equal_prefix_roa4(roa, &n) && r->routes && rte_is_valid(&r->routes->rte)) + if (net_equal_prefix_roa4(roa, &n) && rte_is_valid(r->routes)) { anything = 1; if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) @@ -202,7 +202,7 @@ net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn) net_addr_roa6 *roa = (void *) fn->addr; net *r = fib_node_to_user(&tab->fib, fn); - if (net_equal_prefix_roa6(roa, &n) && r->routes && rte_is_valid(&r->routes->rte)) + if (net_equal_prefix_roa6(roa, &n) && rte_is_valid(r->routes)) { anything = 1; if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen)) @@ -543,7 +543,7 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang old_best = old_changed; else { - for (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next) + for (struct rte_storage *r = net->routes; rte_is_valid(r); r = r->next) { if (bmap_test(&c->export_map, r->rte.id)) { @@ -561,7 +561,7 @@ 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 (struct rte_storage *r = net->routes; r && rte_is_valid(&r->rte); r = r->next) + 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; } @@ -596,7 +596,7 @@ rt_export_merged(struct channel *c, net *net, linpool *pool, int silent) struct rte_storage *best0 = net->routes; rte *best; - if (!best0 || !rte_is_valid(&best0->rte)) + if (!rte_is_valid(best0)) return NULL; best = export_filter_(c, ((rme = best0->rte), &rme), pool, silent); @@ -714,16 +714,16 @@ static void 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 (!new || !rte_is_valid(&new->rte)) + if (!rte_is_valid(new)) new = NULL; - if (!old || !rte_is_valid(&old->rte)) + if (!rte_is_valid(old)) old = NULL; - if (!new_best || !rte_is_valid(&new_best->rte)) + if (!rte_is_valid(new_best)) new_best = NULL; - if (!old_best || !rte_is_valid(&old_best->rte)) + if (!rte_is_valid(old_best)) old_best = NULL; if (!new && !old && !new_best && !old_best) @@ -1246,14 +1246,11 @@ rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filte { net *n = net_find(t, a); - if (!n || !n->routes) + if (!n || !rte_is_valid(n->routes)) return 0; rte rt = n->routes->rte; - if (!rte_is_valid(&rt)) - return 0; - rte_update_lock(); /* Rest is stripped down export_filter() */ @@ -2151,7 +2148,7 @@ rt_feed_channel(struct channel *c) if ((c->ra_mode == RA_OPTIMAL) || (c->ra_mode == RA_ACCEPTED) || (c->ra_mode == RA_MERGED)) - if (e && rte_is_valid(&e->rte)) + if (rte_is_valid(e)) { /* In the meantime, the protocol may fell down */ if (c->export_state != ES_FEEDING) @@ -2168,7 +2165,7 @@ rt_feed_channel(struct channel *c) if (c->export_state != ES_FEEDING) goto done; - if (!rte_is_valid(&e->rte)) + if (!rte_is_valid(e)) continue; do_feed_channel(c, n, &e->rte); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 90490b4f..1d9b3630 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -2212,7 +2212,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best) /* The default case - find a new best-in-group route */ rte *r = new; /* new may not be in the list */ - for (struct rte_storage *s = net->routes; rte_is_valid(&s->rte); s = s->next) + 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->rte.pflags |= BGP_REF_SUPPRESSED; @@ -2229,7 +2229,7 @@ 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 (struct rte_storage *s = net->routes; rte_is_valid(&s->rte); s = s->next) + 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; -- cgit v1.2.3