* 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.
ARG_ANY(1);
STATIC_ATTR;
ARG_TYPE(1, sa.type);
--
- f_rta_cow(fs);
- f_rte_cow(fs);
{
union {
struct nexthop_adata nha;
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:
ACCESS_RTE;
ACCESS_EATTRS;
- f_rta_cow(fs);
- f_rte_cow(fs);
ea_unset_attr(fs->eattrs, 1, da);
}
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;
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 */
/* 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;
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);
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]])
.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;
.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);
}
}
{
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
}
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)
{
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;
}
/**
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));
}
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;
}
* 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");
}
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);
}
- eattr *heea = ea_find(r->attrs->eattrs, &ea_gen_hostentry);
+static inline void
+rt_next_hop_resolve_rte(rte *r)
+{
- 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);
++ eattr *heea = ea_find(r->attrs, &ea_gen_hostentry);
+ if (!heea)
+ return;
+
+ struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr;
+
++ rta_apply_hostentry(&r->attrs, head);
+}
#ifdef CONFIG_BGP
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));
/* 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 */
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
}
- if (r->attrs->cached)
- {
- rta *a = tmp_alloc(RTA_MAX_SIZE);
- *a = *r->attrs;
- a->cached = 0;
- r->attrs = a;
- }
-
+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;
+
- ea_unset_attr(&r->attrs->eattrs, 0, &ea_gen_flowspec_valid);
+ if (valid == FLOWSPEC_UNKNOWN)
- ea_set_attr_u32(&r->attrs->eattrs, &ea_gen_flowspec_valid, 0, valid);
++ ea_unset_attr(&r->attrs, 0, &ea_gen_flowspec_valid);
+ else
++ 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)
}
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;
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",
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
}
};
- 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
{
}
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);
}
}
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;
}
/* 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))
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;
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;
}
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, ") [");
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);
}
}
/* 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
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 */
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))
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
.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);
}
/**
}
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
{
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
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;
int scan;
int merge;
- net *net;
+ net_addr *net;
- rta *attrs;
+ ea_list *attrs;
struct krt_proto *proto;
s8 new;
s8 krt_src;
}
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;
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;
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;
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
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)
// XXXX tm_dump_all();
if_dump_all();
neigh_dump_all();
-- rta_dump_all();
++ ea_dump_all();
rt_dump_all();
protos_dump_all();