static void rt_notify_hostcache(rtable *tab, net *net);
static void rt_update_hostcache(rtable *tab);
static void rt_next_hop_update(rtable *tab);
++static inline void rt_next_hop_resolve_rte(rte *r);
static inline void rt_prune_table(rtable *tab);
static inline void rt_schedule_notify(rtable *tab);
static void rt_flowspec_notify(rtable *tab, net *net);
-static inline rte *rt_next_hop_update_rte(rtable *tab, rte *old);
+static void rt_feed_channel(void *);
+
+const char *rt_import_state_name_array[TIS_MAX] = {
+ [TIS_DOWN] = "DOWN",
+ [TIS_UP] = "UP",
+ [TIS_STOP] = "STOP",
+ [TIS_FLUSHING] = "FLUSHING",
+ [TIS_WAITING] = "WAITING",
+ [TIS_CLEARED] = "CLEARED",
+};
+
+const char *rt_export_state_name_array[TES_MAX] = {
+ [TES_DOWN] = "DOWN",
+ [TES_HUNGRY] = "HUNGRY",
+ [TES_FEEDING] = "FEEDING",
+ [TES_READY] = "READY",
+ [TES_STOP] = "STOP"
+};
+
+const char *rt_import_state_name(u8 state)
+{
+ if (state >= TIS_MAX)
+ return "!! INVALID !!";
+ else
+ return rt_import_state_name_array[state];
+}
+
+const char *rt_export_state_name(u8 state)
+{
+ if (state >= TES_MAX)
+ return "!! INVALID !!";
+ else
+ return rt_export_state_name_array[state];
+}
+
-
++static inline struct rte_storage *rt_next_hop_update_rte(rtable *tab, net *n, rte *old);
+ static struct hostentry *rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep);
static void
net_init_with_trie(struct fib *f, void *N)
rte_update_lock();
if (new)
{
- /* Create a temporary table node */
- nn = alloca(sizeof(net) + n->length);
- memset(nn, 0, sizeof(net) + n->length);
- net_copy(nn->n.addr, n);
-
- new->net = nn;
- new->sender = c;
-
- stats->imp_updates_received++;
- if (filter == FILTER_REJECT)
- {
- stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, c, new, "filtered out");
+ new->net = n;
- if (! c->in_keep_filtered)
- goto drop;
+ int fr;
- /* new is a private copy, i could modify it */
- new->flags |= REF_FILTERED;
- }
- else if (filter)
+ stats->updates_received++;
- if (!rte_validate(c, new))
- {
- channel_rte_trace_in(D_FILTERS, c, new, "invalid");
- stats->updates_invalid++;
- new = NULL;
- }
- else if ((filter == FILTER_REJECT) ||
++ if ((filter == FILTER_REJECT) ||
+ ((fr = f_run(filter, new, 0)) > F_ACCEPT))
{
- int fr = f_run(filter, &new, 0);
- if (fr > F_ACCEPT)
- {
- stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, c, new, "filtered out");
-
- if (! c->in_keep_filtered)
- goto drop;
+ stats->updates_filtered++;
+ channel_rte_trace_in(D_FILTERS, c, new, "filtered out");
+ if (c->in_keep_filtered)
new->flags |= REF_FILTERED;
- }
+ else
+ new = NULL;
}
- rte *new_resolved = rt_next_hop_update_rte(c->table, new);
- if (new_resolved)
- {
- rte_free(new);
- new = new_resolved;
- }
+
- /* After all checks, updates and filters have been done,
- * validate the route */
- if (!rte_validate(new))
++ if (new)
++ rt_next_hop_resolve_rte(new);
+
- rte_trace_in(D_FILTERS, c, new, "invalid");
- stats->imp_updates_invalid++;
- goto drop;
++ if (new && !rte_validate(c, new))
+ {
- if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
- new->attrs = rta_lookup(new->attrs);
- new->flags |= REF_COW;
-
- /* Use the actual struct network, not the dummy one */
- nn = net_get(c->table, n);
- new->net = nn;
++ channel_rte_trace_in(D_FILTERS, c, new, "invalid");
++ stats->updates_invalid++;
++ new = NULL;
+ }
+
}
else
- {
- stats->imp_withdraws_received++;
-
- if (!(nn = net_find(c->table, n)) || !src)
- {
- stats->imp_withdraws_ignored++;
- rte_update_unlock();
- return;
- }
- }
+ stats->withdraws_received++;
- recalc:
- /* And recalculate the best route */
- rte_recalculate(c, nn, new, src);
+ rte_import(&c->in_req, n, new, src);
rte_update_unlock();
- return;
+}
- drop:
- rte_free(new);
- new = NULL;
- if (nn = net_find(c->table, n))
- goto recalc;
+void
+rte_import(struct rt_import_request *req, const net_addr *n, rte *new, struct rte_src *src)
+{
+ struct rt_import_hook *hook = req->hook;
+ if (!hook)
+ return;
- rte_update_unlock();
+ net *nn;
+ if (new)
+ {
+ /* Use the actual struct network, not the dummy one */
+ nn = net_get(hook->table, n);
+ new->net = nn->n.addr;
+ new->sender = hook;
+ }
+ else if (!(nn = net_find(hook->table, n)))
+ {
+ req->hook->stats.withdraws_ignored++;
+ return;
+ }
+
+ /* And recalculate the best route */
+ rte_recalculate(hook, nn, new, src);
}
/* Independent call to rte_announce(), used from next hop
&ea_gen_nexthop, 0, &new->ad));
}
- static inline int
+ static inline struct hostentry_adata *
rta_next_hop_outdated(rta *a)
{
- struct hostentry *he = a->hostentry;
+ eattr *heea = ea_find(a->eattrs, &ea_gen_hostentry);
+ if (!heea)
+ return NULL;
- if (!he)
- return 0;
+ struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr;
- if (!he->src)
- return a->dest != RTD_UNREACHABLE;
+ if (!head->he->src)
+ return (a->dest != RTD_UNREACHABLE) ? head : NULL;
- eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
+ eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
- return (a->dest != he->dest) ||
- (ea_get_int(a->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN) != he->igp_metric) ||
- (!he->nexthop_linkable) ||
- (!he_nh_ea != !a_nh_ea) ||
- (he_nh_ea && a_nh_ea && !adata_same(he_nh_ea->u.ptr, a_nh_ea->u.ptr));
+ return ((a->dest != head->he->dest) ||
+ (ea_get_int(a->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN) != head->he->igp_metric) ||
+ (!head->he->nexthop_linkable) ||
+ (!he_nh_ea != !a_nh_ea) ||
+ (he_nh_ea && a_nh_ea && !adata_same(he_nh_ea->u.ptr, a_nh_ea->u.ptr)))
+ ? head : NULL;
}
-static inline rte *
-rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
+static inline struct rte_storage *
+rt_next_hop_update_rte(rtable *tab, net *n, rte *old)
{
- if (!rta_next_hop_outdated(old->attrs))
+ struct hostentry_adata *head = rta_next_hop_outdated(old->attrs);
+ if (!head)
return NULL;
- rta *a = alloca(RTA_MAX_SIZE);
- memcpy(a, old->attrs, rta_size(old->attrs));
-
- rta_apply_hostentry(a, old->attrs->hostentry);
- a->cached = 0;
+ rta a = *old->attrs;
+ a.cached = 0;
+ rta_apply_hostentry(&a, head);
- rte *e = sl_alloc(rte_slab);
- memcpy(e, old, sizeof(rte));
- e->attrs = rta_lookup(&a);
- rt_lock_source(e->src);
+ rte e0 = *old;
- e0.attrs = a;
++ e0.attrs = &a;
- 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);
++ 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);
++}
#ifdef CONFIG_BGP
net *n = net_route(tab, &he_addr);
if (n)
{
- rte *e = n->routes;
- rta *a = e->attrs;
+ struct rte_storage *e = n->routes;
+ rta *a = e->rte.attrs;
pxlen = n->n.addr->pxlen;
- if (a->hostentry)
+ if (ea_find(a->eattrs, &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",