summaryrefslogtreecommitdiff
path: root/nest/rt-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r--nest/rt-table.c885
1 files changed, 485 insertions, 400 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index c6e48c38..4260e493 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -55,9 +55,7 @@ static void rt_free_hostcache(rtable *tab);
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 int rt_prune_table(rtable *tab);
-static inline void rt_schedule_gc(rtable *tab);
-static inline void rt_schedule_prune(rtable *tab);
+static inline void rt_prune_table(rtable *tab);
static inline struct ea_list *
@@ -68,31 +66,152 @@ make_tmp_attrs(struct rte *rt, struct linpool *pool)
return mta ? mta(rt, pool) : NULL;
}
+
/* Like fib_route(), but skips empty net entries */
-static net *
-net_route(rtable *tab, ip_addr a, int len)
+static inline void *
+net_route_ip4(struct fib *f, net_addr_ip4 *n)
{
- ip_addr a0;
- net *n;
+ net *r;
+
+ while (r = fib_find(f, (net_addr *) n),
+ !(r && rte_is_valid(r->routes)) && (n->pxlen > 0))
+ {
+ n->pxlen--;
+ ip4_clrbit(&n->prefix, n->pxlen);
+ }
+
+ return r;
+}
+
+static inline void *
+net_route_ip6(struct fib *f, net_addr_ip6 *n)
+{
+ net *r;
+
+ while (r = fib_find(f, (net_addr *) n),
+ !(r && rte_is_valid(r->routes)) && (n->pxlen > 0))
+ {
+ n->pxlen--;
+ ip6_clrbit(&n->prefix, n->pxlen);
+ }
+
+ return r;
+}
+
+void *
+net_route(rtable *tab, const net_addr *n)
+{
+ ASSERT(tab->addr_type == n->type);
+
+ net_addr *n0 = alloca(n->length);
+ net_copy(n0, n);
+
+ switch (n->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return net_route_ip4(&tab->fib, (net_addr_ip4 *) n0);
- while (len >= 0)
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return net_route_ip6(&tab->fib, (net_addr_ip6 *) n0);
+
+ default:
+ return NULL;
+ }
+}
+
+
+static int
+net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn)
+{
+ struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0);
+ struct fib_node *fn;
+ int anything = 0;
+
+ while (1)
+ {
+ for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next)
{
- a0 = ipa_and(a, ipa_mkmask(len));
- n = fib_find(&tab->fib, &a0, len);
- if (n && rte_is_valid(n->routes))
- return n;
- len--;
+ net_addr_roa4 *roa = (void *) fn->addr;
+ net *r = fib_node_to_user(&tab->fib, fn);
+
+ if (net_equal_prefix_roa4(roa, &n) && rte_is_valid(r->routes))
+ {
+ anything = 1;
+ if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+ return ROA_VALID;
+ }
}
- return NULL;
+
+ if (n.pxlen == 0)
+ break;
+
+ n.pxlen--;
+ ip4_clrbit(&n.prefix, n.pxlen);
+ }
+
+ return anything ? ROA_INVALID : ROA_UNKNOWN;
}
-static void
-rte_init(struct fib_node *N)
+static int
+net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn)
{
- net *n = (net *) N;
+ struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0);
+ struct fib_node *fn;
+ int anything = 0;
+
+ while (1)
+ {
+ for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next)
+ {
+ net_addr_roa6 *roa = (void *) fn->addr;
+ net *r = fib_node_to_user(&tab->fib, fn);
- N->flags = 0;
- n->routes = NULL;
+ if (net_equal_prefix_roa6(roa, &n) && rte_is_valid(r->routes))
+ {
+ anything = 1;
+ if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+ return ROA_VALID;
+ }
+ }
+
+ if (n.pxlen == 0)
+ break;
+
+ n.pxlen--;
+ ip6_clrbit(&n.prefix, n.pxlen);
+ }
+
+ return anything ? ROA_INVALID : ROA_UNKNOWN;
+}
+
+/**
+ * roa_check - check validity of route origination in a ROA table
+ * @tab: ROA table
+ * @n: network prefix to check
+ * @asn: AS number of network prefix
+ *
+ * Implements RFC 6483 route validation for the given network prefix. The
+ * procedure is to find all candidate ROAs - ROAs whose prefixes cover the given
+ * network prefix. If there is no candidate ROA, return ROA_UNKNOWN. If there is
+ * a candidate ROA with matching ASN and maxlen field greater than or equal to
+ * the given prefix length, return ROA_VALID. Otherwise, return ROA_INVALID. If
+ * caller cannot determine origin AS, 0 could be used (in that case ROA_VALID
+ * cannot happen). Table @tab must have type NET_ROA4 or NET_ROA6, network @n
+ * must have type NET_IP4 or NET_IP6, respectively.
+ */
+int
+net_roa_check(rtable *tab, const net_addr *n, u32 asn)
+{
+ if ((tab->addr_type == NET_ROA4) && (n->type == NET_IP4))
+ return net_roa_check_ip4(tab, (const net_addr_ip4 *) n, asn);
+ else if ((tab->addr_type == NET_ROA6) && (n->type == NET_IP6))
+ return net_roa_check_ip6(tab, (const net_addr_ip6 *) n, asn);
+ else
+ return ROA_UNKNOWN; /* Should not happen */
}
/**
@@ -129,7 +248,7 @@ rte_get_temp(rta *a)
e->attrs = a;
e->flags = 0;
- e->pref = a->src->proto->preference;
+ e->pref = 0;
return e;
}
@@ -227,7 +346,7 @@ rte_mergable(rte *pri, rte *sec)
static void
rte_trace(struct proto *p, rte *e, int dir, char *msg)
{
- log(L_TRACE "%s %c %s %I/%d %s", p->name, dir, msg, e->net->n.prefix, e->net->n.pxlen, rt_format_via(e));
+ log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rt_format_via(e));
}
static inline void
@@ -245,11 +364,11 @@ rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
}
static rte *
-export_filter_(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
+export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
{
- struct proto *p = ah->proto;
- struct filter *filter = ah->out_filter;
- struct proto_stats *stats = ah->stats;
+ struct proto *p = c->proto;
+ struct filter *filter = c->out_filter;
+ struct proto_stats *stats = &c->stats;
ea_list *tmpb = NULL;
rte *rt;
int v;
@@ -305,16 +424,16 @@ export_filter_(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa
}
static inline rte *
-export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
+export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
{
- return export_filter_(ah, rt0, rt_free, tmpa, rte_update_pool, silent);
+ return export_filter_(c, rt0, rt_free, tmpa, rte_update_pool, silent);
}
static void
-do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
+do_rt_notify(struct channel *c, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
{
- struct proto *p = ah->proto;
- struct proto_stats *stats = ah->stats;
+ struct proto *p = c->proto;
+ struct proto_stats *stats = &c->stats;
/*
@@ -344,11 +463,11 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
* also non-new updates (contrary to import blocking).
*/
- struct proto_limit *l = ah->out_limit;
- if (l && new)
+ struct channel_limit *l = &c->out_limit;
+ if (l->action && new)
{
if ((!old || refeed) && (stats->exp_routes >= l->limit))
- proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
+ channel_notify_limit(c, l, PLD_OUT, stats->exp_routes);
if (l->state == PLS_BLOCKED)
{
@@ -385,25 +504,24 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
rte_trace_out(D_ROUTES, p, old, "removed");
}
if (!new)
- p->rt_notify(p, ah->table, net, NULL, old, NULL);
+ p->rt_notify(p, c, net, NULL, old, NULL);
else if (tmpa)
{
ea_list *t = tmpa;
while (t->next)
t = t->next;
t->next = new->attrs->eattrs;
- p->rt_notify(p, ah->table, net, new, old, tmpa);
+ p->rt_notify(p, c, net, new, old, tmpa);
t->next = NULL;
}
else
- p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
+ p->rt_notify(p, c, net, new, old, new->attrs->eattrs);
}
static void
-rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int refeed)
+rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
{
- struct proto *p = ah->proto;
- struct proto_stats *stats = ah->stats;
+ struct proto *p = c->proto;
rte *new = new0;
rte *old = old0;
@@ -412,9 +530,9 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
ea_list *tmpa = NULL;
if (new)
- stats->exp_updates_received++;
+ c->stats.exp_updates_received++;
else
- stats->exp_withdraws_received++;
+ c->stats.exp_withdraws_received++;
/*
* This is a tricky part - we don't know whether route 'old' was
@@ -437,10 +555,10 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
*/
if (new)
- new = export_filter(ah, new, &new_free, &tmpa, 0);
+ new = export_filter(c, new, &new_free, &tmpa, 0);
if (old && !refeed)
- old = export_filter(ah, old, &old_free, NULL, 1);
+ old = export_filter(c, old, &old_free, NULL, 1);
if (!new && !old)
{
@@ -457,13 +575,13 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
#ifdef CONFIG_PIPE
if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto))
- p->rt_notify(p, ah->table, net, NULL, old0, NULL);
+ p->rt_notify(p, c, net, NULL, old0, NULL);
#endif
return;
}
- do_rt_notify(ah, net, new, old, tmpa, refeed);
+ do_rt_notify(c, net, new, old, tmpa, refeed);
/* Discard temporary rte's */
if (new_free)
@@ -473,10 +591,9 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
}
static void
-rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
+rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
{
- // struct proto *p = ah->proto;
- struct proto_stats *stats = ah->stats;
+ // struct proto *p = c->proto;
rte *r;
rte *new_best = NULL;
@@ -494,14 +611,14 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol
was not valid, caller must use NULL for both old_changed and before_old. */
if (new_changed)
- stats->exp_updates_received++;
+ c->stats.exp_updates_received++;
else
- stats->exp_withdraws_received++;
+ c->stats.exp_withdraws_received++;
/* First, find the new_best route - first accepted by filters */
for (r=net->routes; rte_is_valid(r); r=r->next)
{
- if (new_best = export_filter(ah, r, &new_free, &tmpa, 0))
+ if (new_best = export_filter(c, r, &new_free, &tmpa, 0))
break;
/* Note if we walked around the position of old_changed route */
@@ -552,7 +669,7 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol
/* First case */
if (old_meet)
- if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
+ if (old_best = export_filter(c, old_changed, &old_free, NULL, 1))
goto found;
/* Second case */
@@ -570,18 +687,18 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol
/* Fourth case */
for (r=r->next; rte_is_valid(r); r=r->next)
{
- if (old_best = export_filter(ah, r, &old_free, NULL, 1))
+ if (old_best = export_filter(c, r, &old_free, NULL, 1))
goto found;
if (r == before_old)
- if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
+ if (old_best = export_filter(c, old_changed, &old_free, NULL, 1))
goto found;
}
/* Implicitly, old_best is NULL and new_best is non-NULL */
found:
- do_rt_notify(ah, net, new_best, old_best, tmpa, (feed == 2));
+ do_rt_notify(c, net, new_best, old_best, tmpa, (feed == 2));
/* Discard temporary rte's */
if (new_free)
@@ -600,9 +717,9 @@ mpnh_merge_rta(struct mpnh *nhs, rta *a, linpool *pool, int max)
}
rte *
-rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
+rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
{
- // struct proto *p = ah->proto;
+ // struct proto *p = c->proto;
struct mpnh *nhs = NULL;
rte *best0, *best, *rt0, *rt, *tmp;
@@ -612,7 +729,7 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
if (!rte_is_valid(best0))
return NULL;
- best = export_filter_(ah, best0, rt_free, tmpa, pool, silent);
+ best = export_filter_(c, best0, rt_free, tmpa, pool, silent);
if (!best || !rte_is_reachable(best))
return best;
@@ -622,13 +739,13 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
if (!rte_mergable(best0, rt0))
continue;
- rt = export_filter_(ah, rt0, &tmp, NULL, pool, 1);
+ rt = export_filter_(c, rt0, &tmp, NULL, pool, 1);
if (!rt)
continue;
if (rte_is_reachable(rt))
- nhs = mpnh_merge_rta(nhs, rt->attrs, pool, ah->proto->merge_limit);
+ nhs = mpnh_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
if (tmp)
rte_free(tmp);
@@ -636,7 +753,7 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
if (nhs)
{
- nhs = mpnh_merge_rta(nhs, best->attrs, pool, ah->proto->merge_limit);
+ nhs = mpnh_merge_rta(nhs, best->attrs, pool, c->merge_limit);
if (nhs->next)
{
@@ -654,10 +771,10 @@ rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tm
static void
-rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed,
+rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
rte *new_best, rte*old_best, int refeed)
{
- // struct proto *p = ah->proto;
+ // struct proto *p = c->proto;
rte *new_best_free = NULL;
rte *old_best_free = NULL;
@@ -675,31 +792,31 @@ rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_
if ((new_best == old_best) && !refeed)
{
new_changed = rte_mergable(new_best, new_changed) ?
- export_filter(ah, new_changed, &new_changed_free, NULL, 1) : NULL;
+ export_filter(c, new_changed, &new_changed_free, NULL, 1) : NULL;
old_changed = rte_mergable(old_best, old_changed) ?
- export_filter(ah, old_changed, &old_changed_free, NULL, 1) : NULL;
+ export_filter(c, old_changed, &old_changed_free, NULL, 1) : NULL;
if (!new_changed && !old_changed)
return;
}
if (new_best)
- ah->stats->exp_updates_received++;
+ c->stats.exp_updates_received++;
else
- ah->stats->exp_withdraws_received++;
+ c->stats.exp_withdraws_received++;
/* Prepare new merged route */
if (new_best)
- new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, rte_update_pool, 0);
+ new_best = rt_export_merged(c, net, &new_best_free, &tmpa, rte_update_pool, 0);
/* Prepare old merged route (without proper merged next hops) */
/* There are some issues with running filter on old route - see rt_notify_basic() */
if (old_best && !refeed)
- old_best = export_filter(ah, old_best, &old_best_free, NULL, 1);
+ old_best = export_filter(c, old_best, &old_best_free, NULL, 1);
if (new_best || old_best)
- do_rt_notify(ah, net, new_best, old_best, tmpa, refeed);
+ do_rt_notify(c, net, new_best, old_best, tmpa, refeed);
/* Discard temporary rte's */
if (new_best_free)
@@ -764,28 +881,22 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
if (!old && !new)
return;
- if (type == RA_OPTIMAL)
- {
- if (new)
- new->attrs->src->proto->stats.pref_routes++;
- if (old)
- old->attrs->src->proto->stats.pref_routes--;
-
- if (tab->hostcache)
- rt_notify_hostcache(tab, net);
- }
+ if ((type == RA_OPTIMAL) && tab->hostcache)
+ rt_notify_hostcache(tab, net);
- struct announce_hook *a;
- WALK_LIST(a, tab->hooks)
+ struct channel *c; node *n;
+ WALK_LIST2(c, n, tab->channels, table_node)
{
- ASSERT(a->proto->export_state != ES_DOWN);
- if (a->proto->accept_ra_types == type)
+ if (c->export_state == ES_DOWN)
+ continue;
+
+ if (c->ra_mode == type)
if (type == RA_ACCEPTED)
- rt_notify_accepted(a, net, new, old, before_old, 0);
+ rt_notify_accepted(c, net, new, old, before_old, 0);
else if (type == RA_MERGED)
- rt_notify_merged(a, net, new, old, new_best, old_best, 0);
+ rt_notify_merged(c, net, new, old, new_best, old_best, 0);
else
- rt_notify_basic(a, net, new, old, 0);
+ rt_notify_basic(c, net, new, old, 0);
}
}
@@ -795,25 +906,26 @@ rte_validate(rte *e)
int c;
net *n = e->net;
- if ((n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
- {
- log(L_WARN "Ignoring bogus prefix %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->sender->proto->name);
- return 0;
- }
+ // (n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
+ if (!net_validate(n->n.addr))
+ {
+ log(L_WARN "Ignoring bogus prefix %N received via %s",
+ n->n.addr, e->sender->proto->name);
+ return 0;
+ }
- c = ipa_classify_net(n->n.prefix);
+ c = net_classify(n->n.addr);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
- {
- log(L_WARN "Ignoring bogus route %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->sender->proto->name);
- return 0;
- }
+ {
+ log(L_WARN "Ignoring bogus route %N received via %s",
+ n->n.addr, e->sender->proto->name);
+ return 0;
+ }
if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops))
{
- log(L_WARN "Ignoring unsorted multipath route %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->sender->proto->name);
+ log(L_WARN "Ignoring unsorted multipath route %N received via %s",
+ n->n.addr, e->sender->proto->name);
return 0;
}
@@ -855,11 +967,11 @@ rte_same(rte *x, rte *y)
static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
static void
-rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
+rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
{
- struct proto *p = ah->proto;
- struct rtable *table = ah->table;
- struct proto_stats *stats = ah->stats;
+ struct proto *p = c->proto;
+ struct rtable *table = c->table;
+ struct proto_stats *stats = &c->stats;
static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
rte *before_old = NULL;
rte *old_best = net->routes;
@@ -884,8 +996,8 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
{
if (new)
{
- log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %I/%d to table %s",
- net->n.prefix, net->n.pxlen, table->name);
+ log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %N to table %s",
+ net->n.addr, table->name);
rte_free_quick(new);
}
return;
@@ -923,13 +1035,13 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
int new_ok = rte_is_ok(new);
int old_ok = rte_is_ok(old);
- struct proto_limit *l = ah->rx_limit;
- if (l && !old && new)
+ struct channel_limit *l = &c->rx_limit;
+ if (l->action && !old && new)
{
u32 all_routes = stats->imp_routes + stats->filt_routes;
if (all_routes >= l->limit)
- proto_notify_limit(ah, l, PLD_RX, all_routes);
+ channel_notify_limit(c, l, PLD_RX, all_routes);
if (l->state == PLS_BLOCKED)
{
@@ -943,11 +1055,11 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
}
}
- l = ah->in_limit;
- if (l && !old_ok && new_ok)
+ l = &c->in_limit;
+ if (l->action && !old_ok && new_ok)
{
if (stats->imp_routes >= l->limit)
- proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
+ channel_notify_limit(c, l, PLD_IN, stats->imp_routes);
if (l->state == PLS_BLOCKED)
{
@@ -961,13 +1073,13 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
stats->imp_updates_ignored++;
rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
- if (ah->in_keep_filtered)
+ if (c->in_keep_filtered)
new->flags |= REF_FILTERED;
else
{ rte_free_quick(new); new = NULL; }
/* Note that old && !new could be possible when
- ah->in_keep_filtered changed in the recent past. */
+ c->in_keep_filtered changed in the recent past. */
if (!old && !new)
return;
@@ -1100,7 +1212,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) &&
(table->gc_time + table->config->gc_min_time <= now))
- rt_schedule_gc(table);
+ rt_schedule_prune(table);
if (old_ok && p->rte_remove)
p->rte_remove(net, old);
@@ -1149,7 +1261,7 @@ rte_unhide_dummy_routes(net *net, rte **dummy)
/**
* rte_update - enter a new update to a routing table
* @table: table to be updated
- * @ah: pointer to table announce hook
+ * @c: channel doing the update
* @net: network node
* @p: protocol submitting the update
* @src: protocol originating the update
@@ -1189,18 +1301,27 @@ rte_unhide_dummy_routes(net *net, rte **dummy)
*/
void
-rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
+rte_update2(struct channel *c, net_addr *n, rte *new, struct rte_src *src)
{
- struct proto *p = ah->proto;
- struct proto_stats *stats = ah->stats;
- struct filter *filter = ah->in_filter;
+ struct proto *p = c->proto;
+ struct proto_stats *stats = &c->stats;
+ struct filter *filter = c->in_filter;
ea_list *tmpa = NULL;
rte *dummy = NULL;
+ net *nn;
+
+ ASSERT(c->channel_state == CS_UP);
rte_update_lock();
if (new)
{
- new->sender = ah;
+ nn = net_get(c->table, n);
+
+ new->net = nn;
+ new->sender = c;
+
+ if (!new->pref)
+ new->pref = c->preference;
stats->imp_updates_received++;
if (!rte_validate(new))
@@ -1215,7 +1336,7 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out");
- if (! ah->in_keep_filtered)
+ if (! c->in_keep_filtered)
goto drop;
/* new is a private copy, i could modify it */
@@ -1233,7 +1354,7 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
stats->imp_updates_filtered++;
rte_trace_in(D_FILTERS, p, new, "filtered out");
- if (! ah->in_keep_filtered)
+ if (! c->in_keep_filtered)
goto drop;
new->flags |= REF_FILTERED;
@@ -1250,7 +1371,7 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
{
stats->imp_withdraws_received++;
- if (!net || !src)
+ if (!(nn = net_find(c->table, n)) || !src)
{
stats->imp_withdraws_ignored++;
rte_update_unlock();
@@ -1259,9 +1380,9 @@ rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
}
recalc:
- rte_hide_dummy_routes(net, &dummy);
- rte_recalculate(ah, net, new, src);
- rte_unhide_dummy_routes(net, &dummy);
+ rte_hide_dummy_routes(nn, &dummy);
+ rte_recalculate(c, nn, new, src);
+ rte_unhide_dummy_routes(nn, &dummy);
rte_update_unlock();
return;
@@ -1292,9 +1413,9 @@ rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collec
/* Check rtable for best route to given net whether it would be exported do p */
int
-rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter)
+rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
{
- net *n = net_find(t, prefix, pxlen);
+ net *n = net_find(t, a);
rte *rt = n ? n->routes : NULL;
if (!rte_is_valid(rt))
@@ -1321,28 +1442,25 @@ rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter
/**
* rt_refresh_begin - start a refresh cycle
* @t: related routing table
- * @ah: related announce hook
+ * @c related channel
*
* This function starts a refresh cycle for given routing table and announce
* hook. The refresh cycle is a sequence where the protocol sends all its valid
* routes to the routing table (by rte_update()). After that, all protocol
- * routes (more precisely routes with @ah as @sender) not sent during the
+ * routes (more precisely routes with @c as @sender) not sent during the
* refresh cycle but still in the table from the past are pruned. This is
* implemented by marking all related routes as stale by REF_STALE flag in
* rt_refresh_begin(), then marking all related stale routes with REF_DISCARD
* flag in rt_refresh_end() and then removing such routes in the prune loop.
*/
void
-rt_refresh_begin(rtable *t, struct announce_hook *ah)
+rt_refresh_begin(rtable *t, struct channel *c)
{
- net *n;
- rte *e;
-
- FIB_WALK(&t->fib, fn)
+ FIB_WALK(&t->fib, net, n)
{
- n = (net *) fn;
+ rte *e;
for (e = n->routes; e; e = e->next)
- if (e->sender == ah)
+ if (e->sender == c)
e->flags |= REF_STALE;
}
FIB_WALK_END;
@@ -1351,23 +1469,21 @@ rt_refresh_begin(rtable *t, struct announce_hook *ah)
/**
* rt_refresh_end - end a refresh cycle
* @t: related routing table
- * @ah: related announce hook
+ * @c: related channel
*
- * This function starts a refresh cycle for given routing table and announce
+ * This function ends a refresh cycle for given routing table and announce
* hook. See rt_refresh_begin() for description of refresh cycles.
*/
void
-rt_refresh_end(rtable *t, struct announce_hook *ah)
+rt_refresh_end(rtable *t, struct channel *c)
{
int prune = 0;
- net *n;
- rte *e;
- FIB_WALK(&t->fib, fn)
+ FIB_WALK(&t->fib, net, n)
{
- n = (net *) fn;
+ rte *e;
for (e = n->routes; e; e = e->next)
- if ((e->sender == ah) && (e->flags & REF_STALE))
+ if ((e->sender == c) && (e->flags & REF_STALE))
{
e->flags |= REF_DISCARD;
prune = 1;
@@ -1390,7 +1506,7 @@ void
rte_dump(rte *e)
{
net *n = e->net;
- debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
+ debug("%-1N ", n->n.addr);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs)
@@ -1407,23 +1523,17 @@ rte_dump(rte *e)
void
rt_dump(rtable *t)
{
- rte *e;
- net *n;
- struct announce_hook *a;
-
debug("Dump of routing table <%s>\n", t->name);
#ifdef DEBUGGING
fib_check(&t->fib);
#endif
- FIB_WALK(&t->fib, fn)
+ FIB_WALK(&t->fib, net, n)
{
- n = (net *) fn;
+ rte *e;
for(e=n->routes; e; e=e->next)
rte_dump(e);
}
FIB_WALK_END;
- WALK_LIST(a, t->hooks)
- debug("\tAnnounces routes to protocol %s\n", a->proto->name);
debug("\n");
}
@@ -1442,23 +1552,6 @@ rt_dump_all(void)
}
static inline void
-rt_schedule_prune(rtable *tab)
-{
- rt_mark_for_prune(tab);
- ev_schedule(tab->rt_event);
-}
-
-static inline void
-rt_schedule_gc(rtable *tab)
-{
- if (tab->gc_scheduled)
- return;
-
- tab->gc_scheduled = 1;
- ev_schedule(tab->rt_event);
-}
-
-static inline void
rt_schedule_hcu(rtable *tab)
{
if (tab->hcu_scheduled)
@@ -1478,44 +1571,24 @@ rt_schedule_nhu(rtable *tab)
tab->nhu_state |= 1;
}
-
-static void
-rt_prune_nets(rtable *tab)
+void
+rt_schedule_prune(rtable *tab)
{
- struct fib_iterator fit;
- int ncnt = 0, ndel = 0;
-
-#ifdef DEBUGGING
- fib_check(&tab->fib);
-#endif
-
- FIB_ITERATE_INIT(&fit, &tab->fib);
-again:
- FIB_ITERATE_START(&tab->fib, &fit, f)
- {
- net *n = (net *) f;
- ncnt++;
- if (!n->routes) /* Orphaned FIB entry */
- {
- FIB_ITERATE_PUT(&fit, f);
- fib_delete(&tab->fib, f);
- ndel++;
- goto again;
- }
- }
- FIB_ITERATE_END(f);
- DBG("Pruned %d of %d networks\n", ndel, ncnt);
+ if (tab->prune_state == 0)
+ ev_schedule(tab->rt_event);
- tab->gc_counter = 0;
- tab->gc_time = now;
- tab->gc_scheduled = 0;
+ /* state change 0->1, 2->3 */
+ tab->prune_state |= 1;
}
+
static void
rt_event(void *ptr)
{
rtable *tab = ptr;
+ rt_lock_table(tab);
+
if (tab->hcu_scheduled)
rt_update_hostcache(tab);
@@ -1523,28 +1596,21 @@ rt_event(void *ptr)
rt_next_hop_update(tab);
if (tab->prune_state)
- if (!rt_prune_table(tab))
- {
- /* Table prune unfinished */
- ev_schedule(tab->rt_event);
- return;
- }
+ rt_prune_table(tab);
- if (tab->gc_scheduled)
- {
- rt_prune_nets(tab);
- rt_prune_sources(); // FIXME this should be moved to independent event
- }
+ rt_unlock_table(tab);
}
void
rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
{
bzero(t, sizeof(*t));
- fib_init(&t->fib, p, sizeof(net), 0, rte_init);
t->name = name;
t->config = cf;
- init_list(&t->hooks);
+ t->addr_type = cf ? cf->addr_type : NET_IP4;
+ fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
+ init_list(&t->channels);
+
if (cf)
{
t->rt_event = ev_new(p);
@@ -1571,115 +1637,117 @@ rt_init(void)
}
-static int
-rt_prune_step(rtable *tab, int *limit)
+/**
+ * rt_prune_table - prune a routing table
+ *
+ * The prune loop scans routing tables and removes routes belonging to flushing
+ * protocols, discarded routes and also stale network entries. It is called from
+ * rt_event(). The event is rescheduled if the current iteration do not finish
+ * the table. The pruning is directed by the prune state (@prune_state),
+ * specifying whether the prune cycle is scheduled or running, and there
+ * is also a persistent pruning iterator (@prune_fit).
+ *
+ * The prune loop is used also for channel flushing. For this purpose, the
+ * channels to flush are marked before the iteration and notified after the
+ * iteration.
+ */
+static void
+rt_prune_table(rtable *tab)
{
struct fib_iterator *fit = &tab->prune_fit;
+ int limit = 512;
+
+ struct channel *c;
+ node *n, *x;
DBG("Pruning route table %s\n", tab->name);
#ifdef DEBUGGING
fib_check(&tab->fib);
#endif
- if (tab->prune_state == RPS_NONE)
- return 1;
+ if (tab->prune_state == 0)
+ return;
- if (tab->prune_state == RPS_SCHEDULED)
- {
- FIB_ITERATE_INIT(fit, &tab->fib);
- tab->prune_state = RPS_RUNNING;
- }
+ if (tab->prune_state == 1)
+ {
+ /* Mark channels to flush */
+ WALK_LIST2(c, n, tab->channels, table_node)
+ if (c->channel_state == CS_FLUSHING)
+ c->flush_active = 1;
+
+ FIB_ITERATE_INIT(fit, &tab->fib);
+ tab->prune_state = 2;
+ }
again:
- FIB_ITERATE_START(&tab->fib, fit, fn)
+ FIB_ITERATE_START(&tab->fib, fit, net, n)
{
- net *n = (net *) fn;
rte *e;
rescan:
for (e=n->routes; e; e=e->next)
- if (e->sender->proto->flushing || (e->flags & REF_DISCARD))
+ if (e->sender->flush_active || (e->flags & REF_DISCARD))
{
- if (*limit <= 0)
+ if (limit <= 0)
{
- FIB_ITERATE_PUT(fit, fn);
- return 0;
+ FIB_ITERATE_PUT(fit);
+ ev_schedule(tab->rt_event);
+ return;
}
rte_discard(e);
- (*limit)--;
+ limit--;
goto rescan;
}
+
if (!n->routes) /* Orphaned FIB entry */
{
- FIB_ITERATE_PUT(fit, fn);
- fib_delete(&tab->fib, fn);
+ FIB_ITERATE_PUT(fit);
+ fib_delete(&tab->fib, n);
goto again;
}
}
- FIB_ITERATE_END(fn);
+ FIB_ITERATE_END;
#ifdef DEBUGGING
fib_check(&tab->fib);
#endif
- tab->prune_state = RPS_NONE;
- return 1;
-}
+ tab->gc_counter = 0;
+ tab->gc_time = now;
-/**
- * rt_prune_table - prune a routing table
- * @tab: a routing table for pruning
- *
- * This function scans the routing table @tab and removes routes belonging to
- * flushing protocols, discarded routes and also stale network entries, in a
- * similar fashion like rt_prune_loop(). Returns 1 when all such routes are
- * pruned. Contrary to rt_prune_loop(), this function is not a part of the
- * protocol flushing loop, but it is called from rt_event() for just one routing
- * table.
- *
- * Note that rt_prune_table() and rt_prune_loop() share (for each table) the
- * prune state (@prune_state) and also the pruning iterator (@prune_fit).
- */
-static inline int
-rt_prune_table(rtable *tab)
-{
- int limit = 512;
- return rt_prune_step(tab, &limit);
-}
+ /* state change 2->0, 3->1 */
+ tab->prune_state &= 1;
-/**
- * rt_prune_loop - prune routing tables
- *
- * The prune loop scans routing tables and removes routes belonging to flushing
- * protocols, discarded routes and also stale network entries. Returns 1 when
- * all such routes are pruned. It is a part of the protocol flushing loop.
- */
-int
-rt_prune_loop(void)
-{
- int limit = 512;
- rtable *t;
+ if (tab->prune_state > 0)
+ ev_schedule(tab->rt_event);
- WALK_LIST(t, routing_tables)
- if (! rt_prune_step(t, &limit))
- return 0;
+ /* FIXME: This should be handled in a better way */
+ rt_prune_sources();
- return 1;
+ /* Close flushed channels */
+ WALK_LIST2_DELSAFE(c, n, x, tab->channels, table_node)
+ if (c->flush_active)
+ {
+ c->flush_active = 0;
+ channel_set_state(c, CS_DOWN);
+ }
+
+ return;
}
void
rt_preconfig(struct config *c)
{
- struct symbol *s = cf_get_symbol("master");
-
init_list(&c->tables);
- c->master_rtc = rt_new_table(s);
+
+ rt_new_table(cf_get_symbol("master4"), NET_IP4);
+ rt_new_table(cf_get_symbol("master6"), NET_IP6);
}
-/*
+/*
* Some functions for handing internal next hop updates
* triggered by rt_schedule_nhu().
*/
@@ -1811,17 +1879,17 @@ rt_next_hop_update(rtable *tab)
tab->nhu_state = 2;
}
- FIB_ITERATE_START(&tab->fib, fit, fn)
+ FIB_ITERATE_START(&tab->fib, fit, net, n)
{
if (max_feed <= 0)
{
- FIB_ITERATE_PUT(fit, fn);
+ FIB_ITERATE_PUT(fit);
ev_schedule(tab->rt_event);
return;
}
- max_feed -= rt_next_hop_update_net(tab, (net *) fn);
+ max_feed -= rt_next_hop_update_net(tab, n);
}
- FIB_ITERATE_END(fn);
+ FIB_ITERATE_END;
/* state change 2->0, 3->1 */
tab->nhu_state &= 1;
@@ -1832,19 +1900,28 @@ rt_next_hop_update(rtable *tab)
struct rtable_config *
-rt_new_table(struct symbol *s)
+rt_new_table(struct symbol *s, uint addr_type)
{
/* Hack that allows to 'redefine' the master table */
- if ((s->class == SYM_TABLE) && (s->def == new_config->master_rtc))
+ if ((s->class == SYM_TABLE) &&
+ (s->def == new_config->def_tables[addr_type]) &&
+ ((addr_type == NET_IP4) || (addr_type == NET_IP6)))
return s->def;
struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
cf_define_symbol(s, SYM_TABLE, c);
c->name = s->name;
- add_tail(&new_config->tables, &c->n);
+ c->addr_type = addr_type;
c->gc_max_ops = 1000;
c->gc_min_time = 5;
+
+ add_tail(&new_config->tables, &c->n);
+
+ /* First table of each type is kept as default */
+ if (! new_config->def_tables[addr_type])
+ new_config->def_tables[addr_type] = c;
+
return c;
}
@@ -1949,119 +2026,104 @@ rt_commit(struct config *new, struct config *old)
}
static inline void
-do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
+do_feed_channel(struct channel *c, net *n, rte *e)
{
rte_update_lock();
- if (type == RA_ACCEPTED)
- rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1);
- else if (type == RA_MERGED)
- rt_notify_merged(h, n, NULL, NULL, e, p->refeeding ? e : NULL, p->refeeding);
- else
- rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding);
+ if (c->ra_mode == RA_ACCEPTED)
+ rt_notify_accepted(c, n, e, NULL, NULL, c->refeeding ? 2 : 1);
+ else if (c->ra_mode == RA_MERGED)
+ rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, c->refeeding);
+ else /* RA_BASIC */
+ rt_notify_basic(c, n, e, c->refeeding ? e : NULL, c->refeeding);
rte_update_unlock();
}
/**
- * rt_feed_baby - advertise routes to a new protocol
- * @p: protocol to be fed
+ * rt_feed_channel - advertise all routes to a channel
+ * @c: channel to be fed
*
- * This function performs one pass of advertisement of routes to a newly
- * initialized protocol. It's called by the protocol code as long as it
- * has something to do. (We avoid transferring all the routes in single
- * pass in order not to monopolize CPU time.)
+ * This function performs one pass of advertisement of routes to a channel that
+ * is in the ES_FEEDING state. It is called by the protocol code as long as it
+ * has something to do. (We avoid transferring all the routes in single pass in
+ * order not to monopolize CPU time.)
*/
int
-rt_feed_baby(struct proto *p)
+rt_feed_channel(struct channel *c)
{
- struct announce_hook *h;
- struct fib_iterator *fit;
+ struct fib_iterator *fit = &c->feed_fit;
int max_feed = 256;
- if (!p->feed_ahook) /* Need to initialize first */
+ ASSERT(c->export_state == ES_FEEDING);
+
+ if (!c->feed_active)
{
- if (!p->ahooks)
- return 1;
- DBG("Announcing routes to new protocol %s\n", p->name);
- p->feed_ahook = p->ahooks;
- fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator));
- goto next_hook;
+ FIB_ITERATE_INIT(fit, &c->table->fib);
+ c->feed_active = 1;
}
- fit = p->feed_iterator;
-again:
- h = p->feed_ahook;
- FIB_ITERATE_START(&h->table->fib, fit, fn)
+ FIB_ITERATE_START(&c->table->fib, fit, net, n)
{
- net *n = (net *) fn;
rte *e = n->routes;
if (max_feed <= 0)
{
- FIB_ITERATE_PUT(fit, fn);
+ FIB_ITERATE_PUT(fit);
return 0;
}
- /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */
+ /* FIXME: perhaps we should change feed for RA_ACCEPTED to not use 'new' */
- if ((p->accept_ra_types == RA_OPTIMAL) ||
- (p->accept_ra_types == RA_ACCEPTED) ||
- (p->accept_ra_types == RA_MERGED))
+ if ((c->ra_mode == RA_OPTIMAL) ||
+ (c->ra_mode == RA_ACCEPTED) ||
+ (c->ra_mode == RA_MERGED))
if (rte_is_valid(e))
{
- if (p->export_state != ES_FEEDING)
- return 1; /* In the meantime, the protocol fell down. */
+ /* In the meantime, the protocol may fell down */
+ if (c->export_state != ES_FEEDING)
+ goto done;
- do_feed_baby(p, p->accept_ra_types, h, n, e);
+ do_feed_channel(c, n, e);
max_feed--;
}
- if (p->accept_ra_types == RA_ANY)
+ if (c->ra_mode == RA_ANY)
for(e = n->routes; e; e = e->next)
{
- if (p->export_state != ES_FEEDING)
- return 1; /* In the meantime, the protocol fell down. */
+ /* In the meantime, the protocol may fell down */
+ if (c->export_state != ES_FEEDING)
+ goto done;
if (!rte_is_valid(e))
continue;
- do_feed_baby(p, RA_ANY, h, n, e);
+ do_feed_channel(c, n, e);
max_feed--;
}
}
- FIB_ITERATE_END(fn);
- p->feed_ahook = h->next;
- if (!p->feed_ahook)
- {
- mb_free(p->feed_iterator);
- p->feed_iterator = NULL;
- return 1;
- }
+ FIB_ITERATE_END;
-next_hook:
- h = p->feed_ahook;
- FIB_ITERATE_INIT(fit, &h->table->fib);
- goto again;
+done:
+ c->feed_active = 0;
+ return 1;
}
/**
* rt_feed_baby_abort - abort protocol feeding
- * @p: protocol
+ * @c: channel
*
- * This function is called by the protocol code when the protocol
- * stops or ceases to exist before the last iteration of rt_feed_baby()
- * has finished.
+ * This function is called by the protocol code when the protocol stops or
+ * ceases to exist during the feeding.
*/
void
-rt_feed_baby_abort(struct proto *p)
+rt_feed_channel_abort(struct channel *c)
{
- if (p->feed_ahook)
+ if (c->feed_active)
{
- /* Unlink the iterator and exit */
- fit_get(&p->feed_ahook->table->fib, p->feed_iterator);
- p->feed_ahook = NULL;
+ /* Unlink the iterator */
+ fit_get(&c->table->fib, &c->feed_fit);
+ c->feed_active = 0;
}
}
-
static inline unsigned
ptr_hash(void *ptr)
{
@@ -2069,10 +2131,10 @@ ptr_hash(void *ptr)
return p ^ (p << 8) ^ (p >> 16);
}
-static inline unsigned
+static inline u32
hc_hash(ip_addr a, rtable *dep)
{
- return (ipa_hash(a) ^ ptr_hash(dep)) & 0xffff;
+ return ipa_hash(a) ^ ptr_hash(dep);
}
static inline void
@@ -2106,7 +2168,7 @@ hc_alloc_table(struct hostcache *hc, unsigned order)
{
uint hsize = 1 << order;
hc->hash_order = order;
- hc->hash_shift = 16 - order;
+ hc->hash_shift = 32 - order;
hc->hash_max = (order >= HC_HI_ORDER) ? ~0U : (hsize HC_HI_MARK);
hc->hash_min = (order <= HC_LO_ORDER) ? 0U : (hsize HC_LO_MARK);
@@ -2207,12 +2269,10 @@ rt_free_hostcache(rtable *tab)
static void
rt_notify_hostcache(rtable *tab, net *net)
{
- struct hostcache *hc = tab->hostcache;
-
if (tab->hcu_scheduled)
return;
- if (trie_match_prefix(hc->trie, net->n.prefix, net->n.pxlen))
+ if (trie_match_net(tab->hostcache->trie, net->n.addr))
rt_schedule_hcu(tab);
}
@@ -2263,24 +2323,26 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
rta *old_src = he->src;
int pxlen = 0;
- /* Reset the hostentry */
+ /* Reset the hostentry */
he->src = NULL;
he->gw = IPA_NONE;
he->dest = RTD_UNREACHABLE;
he->igp_metric = 0;
- net *n = net_route(tab, he->addr, MAX_PREFIX_LENGTH);
+ net_addr he_addr;
+ net_fill_ip_host(&he_addr, he->addr);
+ net *n = net_route(tab, &he_addr);
if (n)
{
rte *e = n->routes;
rta *a = e->attrs;
- pxlen = n->n.pxlen;
+ pxlen = n->n.addr->pxlen;
if (a->hostentry)
{
/* Recursive route should not depend on another recursive route */
- log(L_WARN "Next hop address %I resolvable through recursive route for %I/%d",
- he->addr, n->n.prefix, pxlen);
+ log(L_WARN "Next hop address %I resolvable through recursive route for %N",
+ he->addr, n->n.addr);
goto done;
}
@@ -2311,7 +2373,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
done:
/* Add a prefix range to the trie */
- trie_add_prefix(tab->hostcache->trie, he->addr, MAX_PREFIX_LENGTH, pxlen, MAX_PREFIX_LENGTH);
+ trie_add_prefix(tab->hostcache->trie, &he_addr, pxlen, he_addr.pxlen);
rta_free(old_src);
return old_src != he->src;
@@ -2352,7 +2414,7 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
if (!tab->hostcache)
rt_init_hostcache(tab);
- uint k = hc_hash(a, dep);
+ u32 k = hc_hash(a, dep);
struct hostcache *hc = tab->hostcache;
for (he = hc->hash_table[k >> hc->hash_shift]; he != NULL; he = he->next)
if (ipa_equal(he->addr, a) && (he->tab == dep))
@@ -2380,7 +2442,7 @@ rt_format_via(rte *e)
rta *a = e->attrs;
/* Max text length w/o IP addr and interface name is 16 */
- static byte via[STD_ADDRESS_P_LENGTH+sizeof(a->iface->name)+16];
+ static byte via[IPA_MAX_TEXT_LENGTH+sizeof(a->iface->name)+16];
switch (a->dest)
{
@@ -2398,7 +2460,7 @@ rt_format_via(rte *e)
static void
rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
{
- byte from[STD_ADDRESS_P_LENGTH+8];
+ byte from[IPA_MAX_TEXT_LENGTH+8];
byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
rta *a = e->attrs;
int primary = (e->net->routes == e);
@@ -2438,23 +2500,14 @@ static void
rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
{
rte *e, *ee;
- byte ia[STD_ADDRESS_P_LENGTH+8];
+ byte ia[NET_MAX_TEXT_LENGTH+1];
struct ea_list *tmpa;
- struct announce_hook *a = NULL;
+ struct channel *ec = d->export_channel;
int first = 1;
int pass = 0;
- bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen);
-
- if (d->export_mode)
- {
- if (! d->export_protocol->rt_notify)
- return;
+ bsprintf(ia, "%N", n->n.addr);
- a = proto_find_announce_hook(d->export_protocol, d->table);
- if (!a)
- return;
- }
for (e = n->routes; e; e = e->next)
{
@@ -2473,10 +2526,10 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
tmpa = make_tmp_attrs(e, rte_update_pool);
/* Special case for merged export */
- if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
+ if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
{
rte *rt_free;
- e = rt_export_merged(a, n, &rt_free, &tmpa, rte_update_pool, 1);
+ e = rt_export_merged(ec, n, &rt_free, &tmpa, rte_update_pool, 1);
pass = 1;
if (!e)
@@ -2487,7 +2540,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
struct proto *ep = d->export_protocol;
int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0;
- if (ep->accept_ra_types == RA_OPTIMAL || ep->accept_ra_types == RA_MERGED)
+ if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
pass = 1;
if (ic < 0)
@@ -2501,12 +2554,12 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
* command may change the export filter and do not update routes.
*/
int do_export = (ic > 0) ||
- (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
+ (f_run(ec->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
if (do_export != (d->export_mode == RSEM_EXPORT))
goto skip;
- if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED))
+ if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_ACCEPTED))
pass = 1;
}
}
@@ -2535,6 +2588,15 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
}
}
+static struct channel *
+rt_show_export_channel(struct rt_show_data *d)
+{
+ if (! d->export_protocol->rt_notify)
+ return NULL;
+
+ return proto_find_channel_by_table(d->export_protocol, d->table);
+}
+
static void
rt_show_cont(struct cli *c)
{
@@ -2547,27 +2609,27 @@ rt_show_cont(struct cli *c)
struct fib *fib = &d->table->fib;
struct fib_iterator *it = &d->fit;
- FIB_ITERATE_START(fib, it, f)
+ if (d->export_mode)
{
- net *n = (net *) f;
- if (d->running_on_config && d->running_on_config != config)
- {
- cli_printf(c, 8004, "Stopped due to reconfiguration");
- goto done;
- }
- if (d->export_protocol && (d->export_protocol->export_state == ES_DOWN))
- {
- cli_printf(c, 8005, "Protocol is down");
+ /* Ensure we have current export channel */
+ d->export_channel = rt_show_export_channel(d);
+ if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
+ {
+ cli_printf(c, 8005, "Channel is down");
goto done;
}
+ }
+
+ FIB_ITERATE_START(fib, it, net, n)
+ {
if (!max--)
{
- FIB_ITERATE_PUT(it, f);
+ FIB_ITERATE_PUT(it);
return;
}
rt_show_net(c, n, d);
}
- FIB_ITERATE_END(f);
+ FIB_ITERATE_END;
if (d->stats)
cli_printf(c, 14, "%d of %d routes for %d networks", d->show_counter, d->rt_counter, d->net_counter);
else
@@ -2585,21 +2647,35 @@ rt_show_cleanup(struct cli *c)
fit_get(&d->table->fib, &d->fit);
}
+static inline rtable *
+rt_show_get_table(struct proto *p)
+{
+ /* FIXME: Use a better way to handle multi-channel protocols */
+
+ if (p->main_channel)
+ return p->main_channel->table;
+
+ if (!EMPTY_LIST(p->channels))
+ return ((struct channel *) HEAD(p->channels))->table;
+
+ return NULL;
+}
+
void
rt_show(struct rt_show_data *d)
{
net *n;
/* Default is either a master table or a table related to a respective protocol */
- if (!d->table && d->export_protocol) d->table = d->export_protocol->table;
- if (!d->table && d->show_protocol) d->table = d->show_protocol->table;
- if (!d->table) d->table = config->master_rtc->table;
+ if (!d->table && d->export_protocol) d->table = rt_show_get_table(d->export_protocol);
+ if (!d->table && d->show_protocol) d->table = rt_show_get_table(d->show_protocol);
+ if (!d->table) d->table = config->def_tables[NET_IP4]->table; /* FIXME: iterate through all tables ? */
/* Filtered routes are neither exported nor have sensible ordering */
if (d->filtered && (d->export_mode || d->primary_only))
cli_msg(0, "");
- if (d->pxlen == 256)
+ if (!d->addr)
{
FIB_ITERATE_INIT(&d->fit, &d->table->fib);
this_cli->cont = rt_show_cont;
@@ -2608,10 +2684,21 @@ rt_show(struct rt_show_data *d)
}
else
{
+ if (d->export_mode)
+ {
+ /* Find channel associated with the export protocol */
+ d->export_channel = rt_show_export_channel(d);
+ if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
+ {
+ cli_msg(8005, "Channel is down");
+ return;
+ }
+ }
+
if (d->show_for)
- n = net_route(d->table, d->prefix, d->pxlen);
+ n = net_route(d->table, d->addr);
else
- n = net_find(d->table, d->prefix, d->pxlen);
+ n = net_find(d->table, d->addr);
if (n)
rt_show_net(this_cli, n, d);
@@ -2632,26 +2719,24 @@ rt_show(struct rt_show_data *d)
* net_find - find a network entry
* @tab: a routing table
* @addr: address of the network
- * @len: length of the network prefix
*
* net_find() looks up the given network in routing table @tab and
* returns a pointer to its &net entry or %NULL if no such network
* exists.
*/
-static inline net *net_find(rtable *tab, ip_addr addr, unsigned len)
+static inline net *net_find(rtable *tab, net_addr *addr)
{ DUMMY; }
/**
* net_get - obtain a network entry
* @tab: a routing table
* @addr: address of the network
- * @len: length of the network prefix
*
* net_get() looks up the given network in routing table @tab and
* returns a pointer to its &net entry. If no such entry exists, it's
* created.
*/
-static inline net *net_get(rtable *tab, ip_addr addr, unsigned len)
+static inline net *net_get(rtable *tab, net_addr *addr)
{ DUMMY; }
/**