diff options
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r-- | nest/rt-table.c | 378 |
1 files changed, 72 insertions, 306 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c index a10979e6..fbfdb1e6 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -548,7 +548,7 @@ rte_find(net *net, struct rte_src *src) { rte *e = net->routes; - while (e && e->attrs->src != src) + while (e && e->src != src) e = e->next; return e; } @@ -563,14 +563,14 @@ rte_find(net *net, struct rte_src *src) * the protocol. */ rte * -rte_get_temp(rta *a) +rte_get_temp(rta *a, struct rte_src *src) { rte *e = sl_alloc(rte_slab); e->attrs = a; e->id = 0; e->flags = 0; - e->pref = 0; + rt_lock_source(e->src = src); return e; } @@ -580,6 +580,8 @@ 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; @@ -617,176 +619,29 @@ rte_cow_rta(rte *r, linpool *lp) return r; } - -/** - * rte_init_tmp_attrs - initialize temporary ea_list for route - * @r: route entry to be modified - * @lp: linpool from which to allocate attributes - * @max: maximum number of added temporary attribus - * - * This function is supposed to be called from make_tmp_attrs() and - * store_tmp_attrs() hooks before rte_make_tmp_attr() / rte_store_tmp_attr() - * functions. It allocates &ea_list with length for @max items for temporary - * attributes and puts it on top of eattrs stack. - */ -void -rte_init_tmp_attrs(rte *r, linpool *lp, uint max) -{ - struct ea_list *e = lp_alloc(lp, sizeof(struct ea_list) + max * sizeof(eattr)); - - e->next = r->attrs->eattrs; - e->flags = EALF_SORTED | EALF_TEMP; - e->count = 0; - - r->attrs->eattrs = e; -} - -/** - * rte_make_tmp_attr - make temporary eattr from private route fields - * @r: route entry to be modified - * @id: attribute ID - * @type: attribute type - * @val: attribute value (u32 or adata ptr) - * - * This function is supposed to be called from make_tmp_attrs() hook for - * each temporary attribute, after temporary &ea_list was initialized by - * rte_init_tmp_attrs(). It checks whether temporary attribute is supposed to - * be defined (based on route pflags) and if so then it fills &eattr field in - * preallocated temporary &ea_list on top of route @r eattrs stack. - * - * Note that it may require free &eattr in temporary &ea_list, so it must not be - * called more times than @max argument of rte_init_tmp_attrs(). - */ -void -rte_make_tmp_attr(rte *r, uint id, uint type, uintptr_t val) -{ - if (r->pflags & EA_ID_FLAG(id)) - { - ea_list *e = r->attrs->eattrs; - eattr *a = &e->attrs[e->count++]; - a->id = id; - a->type = type; - a->flags = 0; - - if (type & EAF_EMBEDDED) - a->u.data = (u32) val; - else - a->u.ptr = (struct adata *) val; - } -} - -/** - * rte_store_tmp_attr - store temporary eattr to private route fields - * @r: route entry to be modified - * @id: attribute ID - * - * This function is supposed to be called from store_tmp_attrs() hook for - * each temporary attribute, after temporary &ea_list was initialized by - * rte_init_tmp_attrs(). It checks whether temporary attribute is defined in - * route @r eattrs stack, updates route pflags accordingly, undefines it by - * filling &eattr field in preallocated temporary &ea_list on top of the eattrs - * stack, and returns the value. Caller is supposed to store it in the - * appropriate private field. - * - * Note that it may require free &eattr in temporary &ea_list, so it must not be - * called more times than @max argument of rte_init_tmp_attrs() - */ -uintptr_t -rte_store_tmp_attr(rte *r, uint id) -{ - ea_list *e = r->attrs->eattrs; - eattr *a = ea_find(e->next, id); - - if (a) - { - e->attrs[e->count++] = (struct eattr) { .id = id, .type = EAF_TYPE_UNDEF }; - r->pflags |= EA_ID_FLAG(id); - return (a->type & EAF_EMBEDDED) ? a->u.data : (uintptr_t) a->u.ptr; - } - else - { - r->pflags &= ~EA_ID_FLAG(id); - return 0; - } -} - /** - * rte_make_tmp_attrs - prepare route by adding all relevant temporary route attributes - * @r: route entry to be modified (may be replaced if COW) - * @lp: linpool from which to allocate attributes - * @old_attrs: temporary ref to old &rta (may be NULL) - * - * This function expands privately stored protocol-dependent route attributes - * to a uniform &eattr / &ea_list representation. It is essentially a wrapper - * around protocol make_tmp_attrs() hook, which does some additional work like - * ensuring that route @r is writable. - * - * The route @r may be read-only (with %REF_COW flag), in that case rw copy is - * obtained by rte_cow() and @r is replaced. If @rte is originally rw, it may be - * directly modified (and it is never copied). - * - * If the @old_attrs ptr is supplied, the function obtains another reference of - * old cached &rta, that is necessary in some cases (see rte_cow_rta() for - * details). It is freed by rte_store_tmp_attrs(), or manually by rta_free(). + * rte_free - delete a &rte + * @e: &rte to be deleted * - * Generally, if caller ensures that @r is read-only (e.g. in route export) then - * it may ignore @old_attrs (and set it to NULL), but must handle replacement of - * @r. If caller ensures that @r is writable (e.g. in route import) then it may - * ignore replacement of @r, but it must handle @old_attrs. + * rte_free() deletes the given &rte from the routing table it's linked to. */ void -rte_make_tmp_attrs(rte **r, linpool *lp, rta **old_attrs) +rte_free(rte *e) { - void (*make_tmp_attrs)(rte *r, linpool *lp); - make_tmp_attrs = (*r)->attrs->src->proto->make_tmp_attrs; - - if (!make_tmp_attrs) - return; - - /* We may need to keep ref to old attributes, will be freed in rte_store_tmp_attrs() */ - if (old_attrs) - *old_attrs = rta_is_cached((*r)->attrs) ? rta_clone((*r)->attrs) : NULL; - - *r = rte_cow_rta(*r, lp); - make_tmp_attrs(*r, lp); + rt_unlock_source(e->src); + if (rta_is_cached(e->attrs)) + rta_free(e->attrs); + sl_free(e); } -/** - * rte_store_tmp_attrs - store temporary route attributes back to private route fields - * @r: route entry to be modified - * @lp: linpool from which to allocate attributes - * @old_attrs: temporary ref to old &rta - * - * This function stores temporary route attributes that were expanded by - * rte_make_tmp_attrs() back to private route fields and also undefines them. - * It is essentially a wrapper around protocol store_tmp_attrs() hook, which - * does some additional work like shortcut if there is no change and cleanup - * of @old_attrs reference obtained by rte_make_tmp_attrs(). - */ -static void -rte_store_tmp_attrs(rte *r, linpool *lp, rta *old_attrs) +static inline void +rte_free_quick(rte *e) { - void (*store_tmp_attrs)(rte *rt, linpool *lp); - store_tmp_attrs = r->attrs->src->proto->store_tmp_attrs; - - if (!store_tmp_attrs) - return; - - ASSERT(!rta_is_cached(r->attrs)); - - /* If there is no new ea_list, we just skip the temporary ea_list */ - ea_list *ea = r->attrs->eattrs; - if (ea && (ea->flags & EALF_TEMP)) - r->attrs->eattrs = ea->next; - else - store_tmp_attrs(r, lp); - - /* Free ref we got in rte_make_tmp_attrs(), have to do rta_lookup() first */ - r->attrs = rta_lookup(r->attrs); - rta_free(old_attrs); + rt_unlock_source(e->src); + rta_free(e->attrs); + sl_free(e); } - static int /* Actually better or at least as good as */ rte_better(rte *new, rte *old) { @@ -797,20 +652,20 @@ rte_better(rte *new, rte *old) if (!rte_is_valid(new)) return 0; - if (new->pref > old->pref) + if (new->attrs->pref > old->attrs->pref) return 1; - if (new->pref < old->pref) + if (new->attrs->pref < old->attrs->pref) return 0; - if (new->attrs->src->proto->proto != old->attrs->src->proto->proto) + if (new->src->proto->proto != old->src->proto->proto) { /* * If the user has configured protocol preferences, so that two different protocols * have the same preference, try to break the tie by comparing addresses. Not too * useful, but keeps the ordering of routes unambiguous. */ - return new->attrs->src->proto->proto > old->attrs->src->proto->proto; + return new->src->proto->proto > old->src->proto->proto; } - if (better = new->attrs->src->proto->rte_better) + if (better = new->src->proto->rte_better) return better(new, old); return 0; } @@ -823,13 +678,13 @@ rte_mergable(rte *pri, rte *sec) if (!rte_is_valid(pri) || !rte_is_valid(sec)) return 0; - if (pri->pref != sec->pref) + if (pri->attrs->pref != sec->attrs->pref) return 0; - if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto) + if (pri->src->proto->proto != sec->src->proto->proto) return 0; - if (mergable = pri->attrs->src->proto->rte_mergable) + if (mergable = pri->src->proto->rte_mergable) return mergable(pri, sec); return 0; @@ -838,8 +693,8 @@ rte_mergable(rte *pri, rte *sec) static void rte_trace(struct channel *c, rte *e, int dir, char *msg) { - log(L_TRACE "%s.%s %c %s %N %s", - c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, + 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, rta_dest_name(e->attrs->dest)); } @@ -869,7 +724,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si rt = rt0; *rt_free = NULL; - v = p->preexport ? p->preexport(p, &rt, pool) : 0; + v = p->preexport ? p->preexport(p, rt) : 0; if (v < 0) { if (silent) @@ -887,8 +742,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si goto accept; } - rte_make_tmp_attrs(&rt, pool, NULL); - v = filter && ((filter == FILTER_REJECT) || (f_run(filter, &rt, pool, (silent ? FF_SILENT : 0)) > F_ACCEPT)); @@ -902,12 +755,6 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si goto reject; } -#ifdef CONFIG_PIPE - /* Pipes need rte with stored tmpattrs, remaining protocols need expanded tmpattrs */ - if (p->proto == &proto_pipe) - rte_store_tmp_attrs(rt, pool, NULL); -#endif - accept: if (rt != rt0) *rt_free = rt; @@ -951,8 +798,14 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) } /* Apply export table */ - if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed)) - return; + struct rte *old_exported = NULL; + if (c->out_table) + { + if (!rte_update_out(c, net->n.addr, new, old, &old_exported, refeed)) + return; + } + else if (c->out_filter == FILTER_ACCEPT) + old_exported = old; if (new) stats->exp_updates_accepted++; @@ -982,6 +835,9 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed) } p->rt_notify(p, c, net, new, old); + + if (c->out_table && old_exported) + rte_free_quick(old_exported); } static void @@ -1341,27 +1197,6 @@ rte_validate(rte *e) return 1; } -/** - * rte_free - delete a &rte - * @e: &rte to be deleted - * - * rte_free() deletes the given &rte from the routing table it's linked to. - */ -void -rte_free(rte *e) -{ - if (rta_is_cached(e->attrs)) - rta_free(e->attrs); - sl_free(rte_slab, e); -} - -static inline void -rte_free_quick(rte *e) -{ - rta_free(e->attrs); - sl_free(rte_slab, e); -} - static int rte_same(rte *x, rte *y) { @@ -1369,8 +1204,7 @@ rte_same(rte *x, rte *y) return x->attrs == y->attrs && x->pflags == y->pflags && - x->pref == y->pref && - (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)) && + x->src == y->src && rte_is_filtered(x) == rte_is_filtered(y); } @@ -1391,7 +1225,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src) k = &net->routes; /* Find and remove original route from the same protocol */ while (old = *k) { - if (old->attrs->src == src) + if (old->src == src) { /* If there is the same route in the routing table but from * a different sender, then there are two paths from the @@ -1674,26 +1508,6 @@ rte_update_unlock(void) lp_flush(rte_update_pool); } -static inline void -rte_hide_dummy_routes(net *net, rte **dummy) -{ - if (net->routes && net->routes->attrs->source == RTS_DUMMY) - { - *dummy = net->routes; - net->routes = (*dummy)->next; - } -} - -static inline void -rte_unhide_dummy_routes(net *net, rte **dummy) -{ - if (*dummy) - { - (*dummy)->next = net->routes; - net->routes = *dummy; - } -} - /** * rte_update - enter a new update to a routing table * @table: table to be updated @@ -1742,7 +1556,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) // struct proto *p = c->proto; struct proto_stats *stats = &c->stats; const struct filter *filter = c->in_filter; - rte *dummy = NULL; net *nn; ASSERT(c->channel_state == CS_UP); @@ -1758,9 +1571,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) new->net = nn; new->sender = c; - if (!new->pref) - new->pref = c->preference; - stats->imp_updates_received++; if (!rte_validate(new)) { @@ -1782,9 +1592,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) } else if (filter) { - rta *old_attrs = NULL; - rte_make_tmp_attrs(&new, rte_update_pool, &old_attrs); - int fr = f_run(filter, &new, rte_update_pool, 0); if (fr > F_ACCEPT) { @@ -1792,15 +1599,10 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) rte_trace_in(D_FILTERS, c, new, "filtered out"); if (! c->in_keep_filtered) - { - rta_free(old_attrs); goto drop; - } new->flags |= REF_FILTERED; } - - rte_store_tmp_attrs(new, rte_update_pool, old_attrs); } if (!rta_is_cached(new->attrs)) /* Need to copy attributes */ new->attrs = rta_lookup(new->attrs); @@ -1824,9 +1626,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) recalc: /* And recalculate the best route */ - rte_hide_dummy_routes(nn, &dummy); rte_recalculate(c, nn, new, src); - rte_unhide_dummy_routes(nn, &dummy); rte_update_unlock(); return; @@ -1855,7 +1655,7 @@ static inline void rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */ { rte_update_lock(); - rte_recalculate(old->sender, old->net, NULL, old->attrs->src); + rte_recalculate(old->sender, old->net, NULL, old->src); rte_update_unlock(); } @@ -1875,7 +1675,7 @@ rte_modify(rte *old) new->flags = (old->flags & ~REF_MODIFY) | REF_COW; } - rte_recalculate(old->sender, old->net, new, old->attrs->src); + rte_recalculate(old->sender, old->net, new, old->src); } rte_update_unlock(); @@ -1894,12 +1694,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter) rte_update_lock(); /* Rest is stripped down export_filter() */ - int v = p->preexport ? p->preexport(p, &rt, rte_update_pool) : 0; + int v = p->preexport ? p->preexport(p, rt) : 0; if (v == RIC_PROCESS) - { - rte_make_tmp_attrs(&rt, rte_update_pool, NULL); v = (f_run(filter, &rt, rte_update_pool, FF_SILENT) <= F_ACCEPT); - } /* Discard temporary rte */ if (rt != n->routes) @@ -1999,10 +1796,8 @@ rte_dump(rte *e) { net *n = e->net; debug("%-1N ", n->n.addr); - debug("PF=%02x pref=%d ", e->pflags, e->pref); + debug("PF=%02x ", e->pflags); rta_dump(e->attrs); - if (e->attrs->src->proto->proto->dump_attrs) - e->attrs->src->proto->proto->dump_attrs(e); debug("\n"); } @@ -2299,12 +2094,7 @@ static struct resclass rt_class = { rtable * rt_setup(pool *pp, struct rtable_config *cf) { - int ns = strlen("Routing table ") + strlen(cf->name) + 1; - void *nb = mb_alloc(pp, ns); - ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name)); - - pool *p = rp_new(pp, nb); - mb_move(nb, p); + pool *p = rp_newf(pp, "Routing table %s", cf->name); rtable *t = ralloc(p, &rt_class); t->rp = p; @@ -2716,11 +2506,12 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32)); rta_apply_hostentry(a, old->attrs->hostentry, &mls); - a->aflags = 0; + a->cached = 0; rte *e = sl_alloc(rte_slab); memcpy(e, old, sizeof(rte)); e->attrs = rta_lookup(a); + rt_lock_source(e->src); return e; } @@ -2844,12 +2635,16 @@ static rte * rt_flowspec_update_rte(rtable *tab, rte *r) { #ifdef CONFIG_BGP - if ((r->attrs->source != RTS_BGP) || !r->u.bgp.base_table) + if (r->attrs->source != RTS_BGP) + return NULL; + + struct bgp_channel *bc = (struct bgp_channel *) r->sender; + if (!bc->base_table) return NULL; const net_addr *n = r->net->n.addr; - struct bgp_proto *p = (void *) r->attrs->src->proto; - int valid = rt_flowspec_check(r->u.bgp.base_table, tab, n, r->attrs, p->is_interior); + struct bgp_proto *p = (void *) r->src->proto; + int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior); int dest = valid ? RTD_NONE : RTD_UNREACHABLE; if (dest == r->attrs->dest) @@ -2858,7 +2653,7 @@ rt_flowspec_update_rte(rtable *tab, rte *r) rta *a = alloca(RTA_MAX_SIZE); memcpy(a, r->attrs, rta_size(r->attrs)); a->dest = dest; - a->aflags = 0; + a->cached = 0; rte *new = sl_alloc(rte_slab); memcpy(new, r, sizeof(rte)); @@ -2898,8 +2693,8 @@ rt_next_hop_update_net(rtable *tab, net *n) /* Call a pre-comparison hook */ /* Not really an efficient way to compute this */ - if (e->attrs->src->proto->rte_recalculate) - e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL); + if (e->src->proto->rte_recalculate) + e->src->proto->rte_recalculate(tab, n, new, e, NULL); if (e != old_best) rte_free_quick(e); @@ -3232,9 +3027,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr { net = net_get(tab, n); - if (!new->pref) - new->pref = c->preference; - if (!rta_is_cached(new->attrs)) new->attrs = rta_lookup(new->attrs); } @@ -3248,7 +3040,7 @@ 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->attrs->src == src) + if (old->src == src) { if (new && rte_same(old, new)) { @@ -3353,7 +3145,7 @@ rt_reload_channel(struct channel *c) return 0; } - rte_update2(c, e->net->n.addr, rte_do_cow(e), e->attrs->src); + rte_update2(c, e->net->n.addr, rte_do_cow(e), e->src); } c->reload_next_rte = NULL; @@ -3426,7 +3218,7 @@ again: */ int -rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed) +rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, rte **old_exported, int refeed) { struct rtable *tab = c->out_table; struct rte_src *src; @@ -3436,9 +3228,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re if (new) { net = net_get(tab, n); - src = new->attrs->src; - - rte_store_tmp_attrs(new, rte_update_pool, NULL); + src = new->src; if (!rta_is_cached(new->attrs)) new->attrs = rta_lookup(new->attrs); @@ -3446,7 +3236,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re else { net = net_find(tab, n); - src = old0->attrs->src; + src = old0->src; if (!net) goto drop_withdraw; @@ -3454,7 +3244,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re /* Find the old rte */ for (pos = &net->routes; old = *pos; pos = &old->next) - if ((c->ra_mode != RA_ANY) || (old->attrs->src == src)) + if ((c->ra_mode != RA_ANY) || (old->src == src)) { if (new && rte_same(old, new)) { @@ -3472,7 +3262,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re /* Remove the old rte */ *pos = old->next; - rte_free_quick(old); + *old_exported = old; tab->rt_count--; break; @@ -3603,7 +3393,7 @@ hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he) rem_node(&he->ln); hc_remove(hc, he); - sl_free(hc->slab, he); + sl_free(he); hc->hash_items--; if (hc->hash_items < hc->hash_min) @@ -3620,7 +3410,7 @@ rt_init_hostcache(rtable *tab) hc_alloc_table(hc, tab->rp, HC_DEF_ORDER); hc->slab = sl_new(tab->rp, sizeof(struct hostentry)); - hc->lp = lp_new(tab->rp, LP_GOOD_SIZE(1024)); + hc->lp = lp_new(tab->rp); hc->trie = f_new_trie(hc->lp, 0); tab->hostcache = hc; @@ -3679,36 +3469,12 @@ rt_get_igp_metric(rte *rt) if (ea) return ea->u.data; - rta *a = rt->attrs; - -#ifdef CONFIG_OSPF - if ((a->source == RTS_OSPF) || - (a->source == RTS_OSPF_IA) || - (a->source == RTS_OSPF_EXT1)) - return rt->u.ospf.metric1; -#endif - -#ifdef CONFIG_RIP - if (a->source == RTS_RIP) - return rt->u.rip.metric; -#endif - -#ifdef CONFIG_BGP - if (a->source == RTS_BGP) - { - u64 metric = bgp_total_aigp_metric(rt); - return (u32) MIN(metric, (u64) IGP_METRIC_UNKNOWN); - } -#endif - -#ifdef CONFIG_BABEL - if (a->source == RTS_BABEL) - return rt->u.babel.metric; -#endif - - if (a->source == RTS_DEVICE) + if (rt->attrs->source == RTS_DEVICE) return 0; + if (rt->src->proto->rte_igp_metric) + return rt->src->proto->rte_igp_metric(rt); + return IGP_METRIC_UNKNOWN; } |