From: Maria Matejka Date: Wed, 8 Jun 2022 13:31:28 +0000 (+0200) Subject: Merge commit '938742decc6e1d6d3a0375dd012b75172e747bbc' into haugesund X-Git-Tag: v3.0-alpha1~107^2~1^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4364ee9b6f3764c971ab111bf7dc87477fd7272c;p=thirdparty%2Fbird.git Merge commit '938742decc6e1d6d3a0375dd012b75172e747bbc' into haugesund --- 4364ee9b6f3764c971ab111bf7dc87477fd7272c diff --cc filter/f-inst.c index 1690c9f64,65a0b011c..9ff5f79ab --- a/filter/f-inst.c +++ b/filter/f-inst.c @@@ -212,7 -212,7 +212,6 @@@ * m4_dnl NEVER_CONSTANT-> don't generate pre-interpretation code at all * m4_dnl ACCESS_RTE -> check that route is available, also NEVER_CONSTANT * m4_dnl ACCESS_EATTRS -> pre-cache the eattrs; use only with ACCESS_RTE - * m4_dnl f_rta_cow(fs) -> function to call before any change to route should be done - * m4_dnl f_rte_cow(fs) -> function to call before any change to route should be done * * m4_dnl If you are stymied, see FI_CALL or FI_CONSTANT or just search for * m4_dnl the mentioned macros in this file to see what is happening there in wild. @@@ -577,8 -577,8 +576,6 @@@ ARG_ANY(1); STATIC_ATTR; ARG_TYPE(1, sa.type); -- - f_rta_cow(fs); - f_rte_cow(fs); { union { struct nexthop_adata nha; @@@ -741,8 -741,8 +738,6 @@@ if (da->type >= EAF_TYPE__MAX) bug("Unsupported attribute type"); - f_rta_cow(fs); - f_rte_cow(fs); -- switch (da->type) { case T_OPAQUE: case T_IFACE: @@@ -770,7 -770,7 +765,6 @@@ ACCESS_RTE; ACCESS_EATTRS; - f_rta_cow(fs); - f_rte_cow(fs); ea_unset_attr(fs->eattrs, 1, da); } diff --cc filter/filter.c index 124c99324,ff6a34199..ad2fafe21 --- a/filter/filter.c +++ b/filter/filter.c @@@ -96,28 -96,15 +96,7 @@@ void (*bt_assert_hook)(int result, cons static inline void f_cache_eattrs(struct filter_state *fs) { - fs->eattrs = &(fs->rte->attrs->eattrs); - fs->eattrs = &((*fs->rte)->attrs); --} -- - /* - * rta_cow - prepare rta for modification by filter - */ - static void - f_rta_cow(struct filter_state *fs) -static inline void f_rte_cow(struct filter_state *fs) --{ - if (!rta_is_cached(fs->rte->attrs)) - if (!((*fs->rte)->flags & REF_COW)) -- return; - - /* - * 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, tmp_linpool); -- - /* Re-cache the ea_list */ - f_cache_eattrs(fs); - *fs->rte = rte_cow(*fs->rte); ++ fs->eattrs = &(fs->rte->attrs); } static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; diff --cc lib/route.h index 283a3760d,3f6fc5a9c..1b2f4de6e --- a/lib/route.h +++ b/lib/route.h @@@ -16,21 -16,19 +16,21 @@@ struct network struct proto; struct cli; + typedef struct rte { - struct rta *attrs; /* Attributes of this route */ - struct rte *next; - struct network *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 ea_list *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 rt_import_hook *sender; /* Import hook used to send the route to the routing table */ + 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 */ + u8 generation; /* If this route import is based on other previously exported route, + this value should be 1 + MAX(generation of the parent routes). + Otherwise the route is independent and this value is zero. */ } rte; -#define REF_COW 1 /* Copy this rte on write */ #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 */ @@@ -333,24 -327,17 +329,24 @@@ extern struct ea_class ea_gen_from /* Source: An old method to devise the route source protocol and kind. * To be superseded in a near future by something more informative. */ extern struct ea_class ea_gen_source; -static inline u32 rt_get_source_attr(rte *rt) +static inline u32 rt_get_source_attr(const rte *rt) - { return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); } + { return ea_get_int(rt->attrs, &ea_gen_source, 0); } /* Flowspec validation result */ -#define FLOWSPEC_UNKNOWN 0 -#define FLOWSPEC_VALID 1 -#define FLOWSPEC_INVALID 2 +enum flowspec_valid { + FLOWSPEC_UNKNOWN = 0, + FLOWSPEC_VALID = 1, + FLOWSPEC_INVALID = 2, + FLOWSPEC__MAX, +}; + +extern const char * flowspec_valid_names[FLOWSPEC__MAX]; +static inline const char *flowspec_valid_name(enum flowspec_valid v) +{ return (v < FLOWSPEC__MAX) ? flowspec_valid_names[v] : "???"; } extern struct ea_class ea_gen_flowspec_valid; -static inline u32 rt_get_flowspec_valid(rte *rt) +static inline enum flowspec_valid rt_get_flowspec_valid(rte *rt) - { return ea_get_int(rt->attrs->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN); } + { return ea_get_int(rt->attrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN); } /* Next hop: For now, stored as adata */ extern struct ea_class ea_gen_nexthop; @@@ -411,9 -398,9 +407,9 @@@ static inline int nhea_dest(eattr *nhea return nhad->dest; } -static inline int rte_dest(rte *r) +static inline int rte_dest(const rte *r) { - return nhea_dest(ea_find(r->attrs->eattrs, &ea_gen_nexthop)); + return nhea_dest(ea_find(r->attrs, &ea_gen_nexthop)); } void rta_init(void); diff --cc nest/config.Y index 7c68a09ad,773673e89..2d73b4c73 --- a/nest/config.Y +++ b/nest/config.Y @@@ -850,11 -849,9 +850,11 @@@ CF_CLI(DUMP INTERFACES,,, [[Dump interf CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]]) { neigh_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]]) - { rta_dump_all(); cli_msg(0, ""); } ; + { ea_dump_all(); cli_msg(0, ""); } ; -CF_CLI(DUMP ROUTES,,, [[Dump routing table]]) +CF_CLI(DUMP ROUTES,,, [[Dump routes]]) { rt_dump_all(); cli_msg(0, ""); } ; +CF_CLI(DUMP TABLES,,, [[Dump table connections]]) +{ rt_dump_hooks_all(); cli_msg(0, ""); } ; CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { protos_dump_all(); cli_msg(0, ""); } ; CF_CLI(DUMP FILTER ALL,,, [[Dump all filters in linearized form]]) diff --cc nest/rt-attr.c index f548a575b,6927751fe..31e2057e2 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@@ -172,15 -172,8 +172,14 @@@ struct ea_class ea_gen_flowspec_valid .readonly = 1, }; +const char * flowspec_valid_names[FLOWSPEC__MAX] = { + [FLOWSPEC_UNKNOWN] = "unknown", + [FLOWSPEC_VALID] = "", + [FLOWSPEC_INVALID] = "invalid", +}; + pool *rta_pool; - static slab *rta_slab; static slab *rte_src_slab; static struct idm src_ids; diff --cc nest/rt-dev.c index fa224f9a2,63f8a26b1..7f45985ff --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@@ -85,16 -87,13 +85,16 @@@ dev_ifa_notify(struct proto *P, uint fl .ad = { .length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data, }, }; - ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, c->preference); - ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_DEVICE); - ea_set_attr_data(&a0.eattrs, &ea_gen_nexthop, 0, nhad.ad.data, nhad.ad.length); + ea_set_attr_u32(&ea, &ea_gen_preference, 0, c->preference); + ea_set_attr_u32(&ea, &ea_gen_source, 0, RTS_DEVICE); + ea_set_attr_data(&ea, &ea_gen_nexthop, 0, nhad.ad.data, nhad.ad.length); - e = rte_get_temp(rta_lookup(ea), src); - e->pflags = 0; - rte_update2(c, net, e, src); + rte e0 = { - .attrs = rta_lookup(&a0), ++ .attrs = ea, + .src = src, + }; + + rte_update(c, net, &e0, src); } } diff --cc nest/rt-show.c index cc5a9a101,2cbc500ac..f3852d170 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@@ -42,17 -42,15 +42,17 @@@ rt_show_rte(struct cli *c, byte *ia, rt { byte from[IPA_MAX_TEXT_LENGTH+8]; byte tm[TM_DATETIME_BUFFER_SIZE], info[256]; - rta *a = e->attrs; + ea_list *a = e->attrs; int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0; void (*get_route_info)(struct rte *, byte *buf); - eattr *nhea = ea_find(a, &ea_gen_nexthop); + eattr *nhea = net_type_match(e->net, NB_DEST) ? - ea_find(a->eattrs, &ea_gen_nexthop) : NULL; ++ ea_find(a, &ea_gen_nexthop) : NULL; struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL; - int dest = NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest; + int dest = nhad ? (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest) : RTD_NONE; + int flowspec_valid = net_is_flow(e->net) ? rt_get_flowspec_valid(e) : FLOWSPEC_UNKNOWN; tm_format_time(tm, &config->tf_route, e->lastmod); - ip_addr a_from = ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE); + ip_addr a_from = ea_get_ip(a, &ea_gen_from, IPA_NONE); if (ipa_nonzero(a_from) && (!nhad || !ipa_equal(a_from, nhad->nh.gw))) bsprintf(from, " from %I", a_from); else @@@ -102,32 -99,9 +102,32 @@@ } if (d->verbose) - rta_show(c, a); + ea_show_list(c, a); } +static uint +rte_feed_count(net *n) +{ + uint count = 0; + for (struct rte_storage *e = n->routes; e; e = e->next) + if (rte_is_valid(RTE_OR_NULL(e))) + count++; + return count; +} + +static void +rte_feed_obtain(net *n, rte **feed, uint count) +{ + uint i = 0; + for (struct rte_storage *e = n->routes; e; e = e->next) + if (rte_is_valid(RTE_OR_NULL(e))) + { + ASSERT_DIE(i < count); + feed[i++] = &e->rte; + } + ASSERT_DIE(i == count); +} + static void rt_show_net(struct cli *c, net *n, struct rt_show_data *d) { diff --cc nest/rt-table.c index 946f4021c,e3dab120c..1631e00f5 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@@ -592,23 -571,53 +592,23 @@@ rte_find(net *net, struct rte_src *src return e; } -rte * -rte_do_cow(rte *r) -{ - rte *e = sl_alloc(rte_slab); - memcpy(e, r, sizeof(rte)); +struct rte_storage * +rte_store(const rte *r, net *net, rtable *tab) +{ + struct rte_storage *e = sl_alloc(tab->rte_slab); - rt_lock_source(e->src); - e->attrs = rta_clone(r->attrs); - e->flags = 0; - return e; -} + e->rte = *r; + e->rte.net = net->n.addr; -/** - * 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) -{ - if (!rta_is_cached(r->attrs)) - return r; + rt_lock_source(e->rte.src); - if (e->rte.attrs->cached) - r = rte_cow(r); ++ if (ea_is_cached(e->rte.attrs)) + e->rte.attrs = rta_clone(e->rte.attrs); + else + e->rte.attrs = rta_lookup(e->rte.attrs); - /* This looks stupid but should DWIW. */ - rta_free(r->attrs); - return r; + return e; } /** @@@ -960,50 -954,46 +960,49 @@@ rt_export_merged(struct channel *c, str if (!rte_is_valid(best0)) return NULL; - best = export_filter(c, best0, rt_free, silent); + /* Already rejected, no need to re-run the filter */ + if (!c->refeeding && bmap_test(&c->export_reject_map, best0->id)) + return NULL; + + rloc = *best0; + best = export_filter(c, &rloc, silent); - if (!best || !rte_is_reachable(best)) + if (!best) + /* Best route doesn't pass the filter */ + return NULL; + + if (!rte_is_reachable(best)) + /* Unreachable routes can't be merged */ return best; - for (rt0 = best0->next; rt0; rt0 = rt0->next) + for (uint i = 1; i < count; i++) { - if (!rte_mergable(best0, rt0)) + if (!rte_mergable(best0, feed[i])) continue; - rt = export_filter(c, rt0, &tmp, 1); + rte tmp0 = *feed[i]; + rte *tmp = export_filter(c, &tmp0, 1); - if (!rt) + if (!tmp || !rte_is_reachable(tmp)) continue; - eattr *nhea = ea_find(tmp->attrs->eattrs, &ea_gen_nexthop); - if (rte_is_reachable(rt)) - { - eattr *nhea = ea_find(rt->attrs, &ea_gen_nexthop); - ASSERT_DIE(nhea); - - if (nhs) - nhs = nexthop_merge(nhs, (struct nexthop_adata *) nhea->u.ptr, c->merge_limit, pool); - else - nhs = (struct nexthop_adata *) nhea->u.ptr; - } ++ eattr *nhea = ea_find(tmp->attrs, &ea_gen_nexthop); + ASSERT_DIE(nhea); - if (tmp) - rte_free(tmp); + if (nhs) + nhs = nexthop_merge(nhs, (struct nexthop_adata *) nhea->u.ptr, c->merge_limit, pool); + else + nhs = (struct nexthop_adata *) nhea->u.ptr; } - if (nhs) { - eattr *nhea = ea_find(best->attrs->eattrs, &ea_gen_nexthop); + eattr *nhea = ea_find(best->attrs, &ea_gen_nexthop); ASSERT_DIE(nhea); nhs = nexthop_merge(nhs, (struct nexthop_adata *) nhea->u.ptr, c->merge_limit, pool); - best->attrs = rta_cow(best->attrs, pool); - ea_set_attr(&best->attrs->eattrs, - best = rte_cow_rta(best); + ea_set_attr(&best->attrs, EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, &nhs->ad)); } @@@ -1226,30 -1177,21 +1225,30 @@@ rte_validate(struct channel *ch, rte *e return 0; } - eattr *nhea = ea_find(e->attrs, &ea_gen_nexthop); - int dest = nhea_dest(nhea); - - if (net_type_match(n->n.addr, NB_DEST) == !dest) + if (net_type_match(n, NB_DEST)) { - eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop); - log(L_WARN "Ignoring route %N with invalid dest %d received via %s", - n->n.addr, dest, e->sender->proto->name); - return 0; - } ++ eattr *nhea = ea_find(e->attrs, &ea_gen_nexthop); + int dest = nhea_dest(nhea); + + if (dest == RTD_NONE) + { + log(L_WARN "Ignoring route %N with no destination received via %s", + n, ch->proto->name); + return 0; + } - if ((dest == RTD_UNICAST) && - !nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr)) + if ((dest == RTD_UNICAST) && + !nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr)) + { + log(L_WARN "Ignoring unsorted multipath route %N received via %s", + n, ch->proto->name); + return 0; + } + } - else if (ea_find(e->attrs->eattrs, &ea_gen_nexthop)) ++ else if (ea_find(e->attrs, &ea_gen_nexthop)) { - log(L_WARN "Ignoring unsorted multipath route %N received via %s", - n->n.addr, e->sender->proto->name); + log(L_WARN "Ignoring route %N having a nexthop attribute received via %s", + n, ch->proto->name); return 0; } @@@ -1880,11 -1803,12 +1879,11 @@@ rt_modify_stale(rtable *t, struct rt_im * 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); - ea_dump(e->attrs); + debug("%-1N ", e->rte.net); + debug("PF=%02x ", e->rte.pflags); - rta_dump(e->rte.attrs); ++ ea_dump(e->rte.attrs); debug("\n"); } @@@ -2668,35 -2543,17 +2667,23 @@@ rt_next_hop_update_rte(rtable *tab, ne if (!head) return NULL; - rta a = *old->attrs; - a.cached = 0; - rta_apply_hostentry(&a, head); - - ea_list *ea = old->attrs; - rta_apply_hostentry(&ea, head); + rte e0 = *old; - e0.attrs = &a; ++ rta_apply_hostentry(&e0.attrs, head); - rte *e = sl_alloc(rte_slab); - memcpy(e, old, sizeof(rte)); - e->attrs = rta_lookup(ea); - rt_lock_source(e->src); - - return e; + return rte_store(&e0, n, tab); } +static inline void +rt_next_hop_resolve_rte(rte *r) +{ - eattr *heea = ea_find(r->attrs->eattrs, &ea_gen_hostentry); ++ eattr *heea = ea_find(r->attrs, &ea_gen_hostentry); + if (!heea) + return; + + struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr; + - if (r->attrs->cached) - { - rta *a = tmp_alloc(RTA_MAX_SIZE); - *a = *r->attrs; - a->cached = 0; - r->attrs = a; - } - - rta_apply_hostentry(r->attrs, head); ++ rta_apply_hostentry(&r->attrs, head); +} #ifdef CONFIG_BGP @@@ -2736,8 -2593,8 +2723,8 @@@ rta_get_first_asn(ea_list *a return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0; } -int +static inline enum flowspec_valid - rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior) + rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, ea_list *a, int interior) { ASSERT(rt_is_ip(tab_ip)); ASSERT(rt_is_flow(tab_flow)); @@@ -2771,18 -2628,18 +2758,18 @@@ /* No best-match BGP route -> no flowspec */ if (!rb || (rt_get_source_attr(rb) != RTS_BGP)) - return 0; + return FLOWSPEC_INVALID; /* Find ORIGINATOR_ID values */ - u32 orig_a = ea_get_int(a->eattrs, "bgp_originator_id", 0); - u32 orig_b = ea_get_int(rb->attrs->eattrs, "bgp_originator_id", 0); + u32 orig_a = ea_get_int(a, "bgp_originator_id", 0); + u32 orig_b = ea_get_int(rb->attrs, "bgp_originator_id", 0); /* Originator is either ORIGINATOR_ID (if present), or BGP neighbor address (if not) */ if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal( - ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE), - ea_get_ip(rb->attrs->eattrs, &ea_gen_from, IPA_NONE) + ea_get_ip(a, &ea_gen_from, IPA_NONE), + ea_get_ip(rb->attrs, &ea_gen_from, IPA_NONE) ))) - return 0; + return FLOWSPEC_INVALID; /* Find ASN of the best-match route, for use in next checks */ @@@ -2834,59 -2690,19 +2821,44 @@@ rt_flowspec_update_rte(rtable *tab, ne if (old == valid) return NULL; - rta *a = alloca(RTA_MAX_SIZE); - *a = *r->attrs; - a->cached = 0; - - ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid); - ea_list *a = r->attrs; - ea_set_attr_u32(&a, &ea_gen_flowspec_valid, 0, valid); -- - rte new; - memcpy(&new, r, sizeof(rte)); - new.attrs = a; - rte *new = sl_alloc(rte_slab); - memcpy(new, r, sizeof(rte)); - new->attrs = ea_lookup(a); ++ rte new = *r; ++ ea_set_attr_u32(&new.attrs, &ea_gen_flowspec_valid, 0, valid); - return new; + return rte_store(&new, n, tab); #else return NULL; #endif } +static inline void +rt_flowspec_resolve_rte(rte *r, struct channel *c) +{ +#ifdef CONFIG_BGP + enum flowspec_valid valid, old = rt_get_flowspec_valid(r); + struct bgp_channel *bc = (struct bgp_channel *) c; + + if ( (rt_get_source_attr(r) == RTS_BGP) + && (c->channel == &channel_bgp) + && (bc->base_table)) + { + struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, bc->c.proto); + valid = rt_flowspec_check( + bc->base_table, + c->in_req.hook->table, + r->net, r->attrs, p->is_interior); + } + else + valid = FLOWSPEC_UNKNOWN; + + if (valid == old) + return; + - if (r->attrs->cached) - { - rta *a = tmp_alloc(RTA_MAX_SIZE); - *a = *r->attrs; - a->cached = 0; - r->attrs = a; - } - + if (valid == FLOWSPEC_UNKNOWN) - ea_unset_attr(&r->attrs->eattrs, 0, &ea_gen_flowspec_valid); ++ ea_unset_attr(&r->attrs, 0, &ea_gen_flowspec_valid); + else - ea_set_attr_u32(&r->attrs->eattrs, &ea_gen_flowspec_valid, 0, valid); ++ ea_set_attr_u32(&r->attrs, &ea_gen_flowspec_valid, 0, valid); +#endif +} static inline int rt_next_hop_update_net(rtable *tab, net *n) @@@ -3650,9 -3500,9 +3622,9 @@@ if_local_addr(ip_addr a, struct iface * } u32 -rt_get_igp_metric(rte *rt) +rt_get_igp_metric(const rte *rt) { - eattr *ea = ea_find(rt->attrs->eattrs, "igp_metric"); + eattr *ea = ea_find(rt->attrs, "igp_metric"); if (ea) return ea->u.data; @@@ -3683,11 -3533,11 +3655,11 @@@ rt_update_hostentry(rtable *tab, struc net *n = net_route(tab, &he_addr); if (n) { - rte *e = n->routes; - ea_list *a = e->attrs; + struct rte_storage *e = n->routes; - rta *a = e->rte.attrs; ++ ea_list *a = e->rte.attrs; pxlen = n->n.addr->pxlen; - if (ea_find(a->eattrs, &ea_gen_hostentry)) + if (ea_find(a, &ea_gen_hostentry)) { /* Recursive route should not depend on another recursive route */ log(L_WARN "Next hop address %I resolvable through recursive route for %N", diff --cc nest/rt.h index eb868aa76,f7cc164df..32bba6a6c --- a/nest/rt.h +++ b/nest/rt.h @@@ -448,16 -290,8 +448,6 @@@ struct hostentry_adata void ea_set_hostentry(ea_list **to, struct rtable *dep, struct rtable *tab, ip_addr gw, ip_addr ll, u32 lnum, u32 labels[lnum]); - /* - struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep); - void rta_apply_hostentry(rta *a, struct hostentry *he, u32 lnum, u32 labels[lnum]); -int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, ea_list *a, int interior); -- - static inline void - rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, u32 lnum, u32 labels[lnum]) - { - rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ll, dep), lnum, labels); - } - */ /* * Default protocol preferences diff --cc proto/babel/babel.c index 65d2567e6,e3903c679..4939619f9 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@@ -677,32 -677,25 +677,30 @@@ babel_announce_rte(struct babel_proto * } }; - rta a0 = { .eattrs = &eattrs.l, }; - - rte *rte = rte_get_temp(rta_lookup(&eattrs.l), p->p.main_source); + rte e0 = { - .attrs = &a0, ++ .attrs = &eattrs.l, + .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)) { /* Unreachable */ - rta a0 = {}; + ea_list *ea = NULL; - ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1); - ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_BABEL); - ea_set_dest(&a0.eattrs, 0, RTD_UNREACHABLE); + ea_set_attr_u32(&ea, &ea_gen_preference, 0, 1); + ea_set_attr_u32(&ea, &ea_gen_source, 0, RTS_BABEL); + ea_set_dest(&ea, 0, RTD_UNREACHABLE); - rte *rte = rte_get_temp(rta_lookup(ea), p->p.main_source); - rte->pflags = 0; + rte e0 = { - .attrs = &a0, ++ .attrs = ea, + .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 { @@@ -2353,9 -2346,9 +2351,9 @@@ babel_rte_better(struct rte *new, struc } static u32 -babel_rte_igp_metric(struct rte *rt) +babel_rte_igp_metric(const rte *rt) { - return ea_get_int(rt->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY); + return ea_get_int(rt->attrs, &ea_babel_metric, BABEL_INFINITY); } diff --cc proto/bgp/attrs.c index 0b715eaa6,c605bb076..6d33ef2e4 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@@ -372,15 -372,13 +372,13 @@@ bgp_aigp_set_metric(struct linpool *poo } int -bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad) +bgp_total_aigp_metric_(const rte *e, u64 *metric, const struct adata **ad) { - rta *a = e->attrs; - - eattr *ea = ea_find(a->eattrs, BGP_EA_ID(BA_AIGP)); - if (!ea) + eattr *a = ea_find(e->attrs, BGP_EA_ID(BA_AIGP)); + if (!a) return 0; - const byte *b = bgp_aigp_get_tlv(ea->u.ptr, BGP_AIGP_METRIC); + const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC); if (!b) return 0; @@@ -1744,11 -1740,11 +1742,11 @@@ bgp_preexport(struct channel *c, rte *e } /* Handle well-known communities, RFC 1997 */ - struct eattr *c; + struct eattr *com; if (p->cf->interpret_communities && - (com = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY)))) - (c = ea_find(e->attrs, BGP_EA_ID(BA_COMMUNITY)))) ++ (com = ea_find(e->attrs, BGP_EA_ID(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)) @@@ -2320,12 -2317,12 +2318,12 @@@ bgp_rte_recalculate(rtable *table, net return !old_suppressed; } -struct rte * +rte * bgp_rte_modify_stale(struct rte *r, struct linpool *pool) { - eattr *ea = ea_find(r->attrs->eattrs, BGP_EA_ID(BA_COMMUNITY)); - eattr *a = ea_find(r->attrs, BGP_EA_ID(BA_COMMUNITY)); - const struct adata *ad = a ? a->u.ptr : NULL; - uint flags = a ? a->flags : BAF_PARTIAL; ++ eattr *ea = ea_find(r->attrs, BGP_EA_ID(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; @@@ -2333,17 -2330,12 +2331,14 @@@ if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE)) return r; - rta *a = rta_do_cow(r->attrs, pool); - - r = rte_cow_rta(r); - bgp_set_attr_ptr(&(r->attrs), BA_COMMUNITY, flags, + _Thread_local static rte e0; + e0 = *r; - e0.attrs = a; + - bgp_set_attr_ptr(&(a->eattrs), BA_COMMUNITY, flags, ++ bgp_set_attr_ptr(&e0.attrs, BA_COMMUNITY, flags, int_set_add(pool, ad, BGP_COMM_LLGR_STALE)); - r->pflags |= BGP_REF_STALE; + e0.pflags |= BGP_REF_STALE; - return r; + return &e0; } @@@ -2402,28 -2394,25 +2397,28 @@@ bgp_get_route_info(rte *e, byte *buf buf += bsprintf(buf, " (%d", rt_get_preference(e)); - if (e->pflags & BGP_REF_SUPPRESSED) - buf += bsprintf(buf, "-"); + if (!net_is_flow(e->net)) + { + if (e->pflags & BGP_REF_SUPPRESSED) + buf += bsprintf(buf, "-"); - if (rte_stale(e)) - buf += bsprintf(buf, "s"); + if (rte_stale(e)) + buf += bsprintf(buf, "s"); - u64 metric = bgp_total_aigp_metric(e); - if (metric < BGP_AIGP_MAX) - { - buf += bsprintf(buf, "/%lu", metric); - } - else if (metric = rt_get_igp_metric(e)) - { - if (!rte_resolvable(e)) - buf += bsprintf(buf, "/-"); - else if (metric >= IGP_METRIC_UNKNOWN) - buf += bsprintf(buf, "/?"); - else - buf += bsprintf(buf, "/%d", metric); + u64 metric = bgp_total_aigp_metric(e); + if (metric < BGP_AIGP_MAX) + { + buf += bsprintf(buf, "/%lu", metric); + } + else if (metric = rt_get_igp_metric(e)) + { - if (!rta_resolvable(e->attrs)) ++ if (!rte_resolvable(e)) + buf += bsprintf(buf, "/-"); + else if (metric >= IGP_METRIC_UNKNOWN) + buf += bsprintf(buf, "/?"); + else + buf += bsprintf(buf, "/%d", metric); + } } buf += bsprintf(buf, ") ["); diff --cc proto/bgp/bgp.h index 662d9d48a,376b463f5..b3966bc3d --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@@ -517,9 -517,9 +517,9 @@@ struct rte_source *bgp_find_source(stru struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id); static inline int - rta_resolvable(rta *a) -rte_resolvable(rte *rt) ++rte_resolvable(const rte *rt) { - eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop); + eattr *nhea = ea_find(rt->attrs, &ea_gen_nexthop); struct nexthop_adata *nhad = (void *) nhea->u.ptr; return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE); } diff --cc proto/bgp/packets.c index 9911738d3,e72ec2221..45ee4ed23 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@@ -1391,20 -1412,13 +1391,15 @@@ bgp_rte_update(struct bgp_parse_state * } /* Prepare cached route attributes */ - if (s->cached_rta == NULL) - { - /* Workaround for rta_lookup() breaking eattrs */ - ea_list *ea = a0->eattrs; - s->cached_rta = rta_lookup(a0); - a0->eattrs = ea; - } + if (s->cached_ea == NULL) + s->cached_ea = ea_lookup(a0); - rte *e = rte_get_temp(rta_clone(s->cached_ea), s->last_src); + rte e0 = { - .attrs = s->cached_rta, ++ .attrs = s->cached_ea, + .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 --cc proto/ospf/rt.c index 1c76aee78,3889d6349..aedf3df6f --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@@ -2088,29 -2085,27 +2085,31 @@@ again1 EA_LITERAL_EMBEDDED(&ea_ospf_router_id, 0, nf->n.rid); ASSERT_DIE(ARRAY_SIZE(eattrs.a) >= eattrs.l.count); - a0.eattrs = &eattrs.l; - rta_free(nf->old_rta); - nf->old_rta = rta_lookup(&a0); - ea_list *a = rta_lookup(&eattrs.l); - rte *e = rte_get_temp(a, p->p.main_source); ++ ea_list *eal = ea_lookup(&eattrs.l); ++ ea_free(nf->old_ea); ++ nf->old_ea = eal; - rta_free(nf->old_ea); - nf->old_ea = rta_clone(a); + rte e0 = { - .attrs = nf->old_rta, ++ .attrs = eal, + .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) + else if (nf->old_ea) { /* Remove the route */ - rta_free(nf->old_rta); - nf->old_rta = NULL; + rta_free(nf->old_ea); + nf->old_ea = 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 */ diff --cc proto/ospf/topology.c index 6ff6a7457,e3dd08859..85bce03dd --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@@ -1363,14 -1363,16 +1363,14 @@@ ospf_rt_notify(struct proto *P, struct uint ebit = m2a || !m1a; uint metric = ebit ? m2 : m1; - uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0); + uint tag = ea_get_int(a, &ea_ospf_tag, 0); ip_addr fwd = IPA_NONE; - eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop); + eattr *nhea = ea_find(a, &ea_gen_nexthop); - if (nhea) - { - struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr; + struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr; + if (NEXTHOP_IS_REACHABLE(nhad)) if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface)) fwd = nhad->nh.gw; - } /* NSSA-LSA with P-bit set must have non-zero forwarding address */ if (oa && ipa_zero(fwd)) diff --cc proto/pipe/pipe.c index e122d7715,bdffed3be..99d4b737e --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@@ -56,25 -59,38 +56,20 @@@ pipe_rt_notify(struct proto *P, struct if (!new && !old) return; - if (dst->table->pipe_busy) - { - log(L_ERR "Pipe loop detected when sending %N to table %s", - n->n.addr, dst->table->name); - return; - } - if (new) { - rta *a = alloca(rta_size(new->attrs)); - memcpy(a, new->attrs, rta_size(new->attrs)); - - a->cached = 0; - ea_unset_attr(&a->eattrs, 0, &ea_gen_hostentry); - - src = new->src; -- - ea_list *a = new->attrs; - ea_unset_attr(&a, 0, &ea_gen_hostentry); + rte e0 = { - .attrs = a, ++ .attrs = new->attrs, + .src = new->src, + .generation = new->generation + 1, + }; - e = rte_get_temp(a, src); - e->pflags = new->pflags; ++ ea_unset_attr(&e0.attrs, 0, &ea_gen_hostentry); + -#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_update(dst, n, &e0, new->src); } else - { - e = NULL; - src = old->src; - } - - src_ch->table->pipe_busy = 1; - rte_update2(dst, n->n.addr, e, src); - src_ch->table->pipe_busy = 0; + rte_update(dst, n, NULL, old->src); } static int diff --cc proto/rip/rip.c index cc8b57ebb,ce452ac70..d6edac148 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@@ -228,18 -227,18 +227,18 @@@ rip_announce_rte(struct rip_proto *p, s .ad = { .length = sizeof(struct rip_iface_adata) - sizeof(struct adata) }, .iface = rt_from, }; - ea_set_attr(&a0.eattrs, + ea_set_attr(&ea, EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &riad.ad)); - rte *e = rte_get_temp(rta_lookup(ea), p->p.main_source); + rte e0 = { - .attrs = &a0, ++ .attrs = ea, + .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); } /** @@@ -1126,9 -1125,9 +1125,9 @@@ rip_rte_better(struct rte *new, struct } static u32 -rip_rte_igp_metric(struct rte *rt) +rip_rte_igp_metric(const rte *rt) { - return ea_get_int(rt->attrs->eattrs, &ea_rip_metric, IGP_METRIC_UNKNOWN); + return ea_get_int(rt->attrs, &ea_rip_metric, IGP_METRIC_UNKNOWN); } static void diff --cc proto/rpki/rpki.c index c8b0ff67d,2d36f1fb0..56615e36b --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@@ -120,14 -120,15 +120,13 @@@ rpki_table_add_roa(struct rpki_cache *c { struct rpki_proto *p = cache->p; - rta a0 = {}; + ea_list *ea = NULL; + ea_set_attr_u32(&ea, &ea_gen_preference, 0, channel->preference); + ea_set_attr_u32(&ea, &ea_gen_source, 0, RTS_RPKI); - ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference); - ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_RPKI); - - rte e0 = { .attrs = &a0, .src = p->p.main_source, }; - rte *e = rte_get_temp(rta_lookup(ea), p->p.main_source); ++ rte e0 = { .attrs = ea, .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 diff --cc proto/static/static.c index 6369fea53,29285d371..d1d5b92ba --- a/proto/static/static.c +++ b/proto/static/static.c @@@ -114,13 -114,24 +114,13 @@@ static_announce_rte(struct static_prot return; /* We skip rta_lookup() here */ - rte e0 = { .attrs = a, .src = src, .net = r->net, }, *e = &e0; - rte *e = rte_get_temp(ea, src); - e->pflags = 0; ++ rte e0 = { .attrs = ea, .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); - - /* Evaluate the filter */ - f_eval_rte(r->cmds, &e); - - /* Remove the temporary node */ - e->net = NULL; - } + f_eval_rte(r->cmds, e); - rte_update2(p->p.main_channel, r->net, e, src); + rte_update(p->p.main_channel, r->net, e, src); r->state = SRS_CLEAN; return; diff --cc sysdep/linux/netlink.c index a4172a6d4,4cfd7c800..d802d3e07 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@@ -110,8 -110,8 +110,8 @@@ struct nl_parse_stat int scan; int merge; - net *net; + net_addr *net; - rta *attrs; + ea_list *attrs; struct krt_proto *proto; s8 new; s8 krt_src; @@@ -1437,11 -1437,11 +1437,10 @@@ nh_bufsize(struct nexthop_adata *nhad } static int -nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop_adata *nh) +nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nexthop_adata *nh) { eattr *ea; - rta *a = e->attrs; - ea_list *eattrs = a->eattrs; - net *net = e->net; + ea_list *eattrs = e->attrs; int bufsize = 128 + KRT_METRICS_MAX*8 + (nh ? nh_bufsize(nh) : 0); u32 priority = 0; @@@ -1708,25 -1707,23 +1706,25 @@@ nl_mergable_route(struct nl_parse_stat 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_LOCAL_LIST(2) ea = { - .l = { .count = 2, .next = e0.attrs->eattrs }, - .l = { .count = 2, .next = e->attrs }, ++ .l = { .count = 2, .next = e0.attrs }, .a = { EA_LITERAL_EMBEDDED(&ea_krt_source, 0, s->krt_proto), EA_LITERAL_EMBEDDED(&ea_krt_metric, 0, s->krt_metric), }, }; - e0.attrs->eattrs = &ea.l; - e->attrs = &ea.l; ++ e0.attrs = &ea.l; 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; @@@ -2041,12 -2040,10 +2039,12 @@@ nl_parse_route(struct nl_parse_state *s 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; - ea_set_attr_data(&ra->eattrs, &ea_gen_nexthop, 0, + ea_set_attr_data(&ra, &ea_gen_nexthop, 0, nhad.ad.data, nhad.ad.length); s->proto = p; diff --cc sysdep/unix/krt.c index 6e55d8f5e,3edbdfa2f..a37d31866 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@@ -305,12 -305,9 +305,12 @@@ krt_uptodate(rte *a, rte *b static void krt_learn_announce_update(struct krt_proto *p, rte *e) { - net *n = e->net; - rte *ee = rte_get_temp(ea_clone(e->attrs), p->p.main_source); - rte_update(&p->p, n->n.addr, ee); + rte e0 = { - .attrs = rta_clone(e->attrs), ++ .attrs = ea_clone(e->attrs), + .src = p->p.main_source, + }; + + rte_update(p->p.main_channel, e->net, &e0, p->p.main_source); } static void @@@ -435,13 -432,13 +435,11 @@@ 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); - ea_set_attr_u32(&e->attrs->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference); - - ea_list *ea = e->attrs; - ea_set_attr_u32(&ea, &ea_gen_preference, 0, p->p.main_channel->preference); - e->attrs = rta_lookup(ea); ++ ea_set_attr_u32(&e->attrs, &ea_gen_preference, 0, p->p.main_channel->preference); + struct rte_storage *ee = rte_store(e, n, p->krt_table); old_best = n->routes; for(gg=&n->routes; g = *gg; gg = &g->next) diff --cc sysdep/unix/main.c index 8fdad4e6f,8fdad4e6f..fd4934d99 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@@ -56,7 -56,7 +56,7 @@@ async_dump(void // XXXX tm_dump_all(); if_dump_all(); neigh_dump_all(); -- rta_dump_all(); ++ ea_dump_all(); rt_dump_all(); protos_dump_all();