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.c115
1 files changed, 71 insertions, 44 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 6f948ada..d98f33e4 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -124,7 +124,8 @@ static void rt_next_hop_update(rtable *tab);
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 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)
@@ -1581,13 +1582,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
new->sender = c;
stats->imp_updates_received++;
- if (!rte_validate(new))
- {
- rte_trace_in(D_FILTERS, c, new, "invalid");
- stats->imp_updates_invalid++;
- goto drop;
- }
-
if (filter == FILTER_REJECT)
{
stats->imp_updates_filtered++;
@@ -1613,6 +1607,23 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
new->flags |= REF_FILTERED;
}
}
+
+ 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))
+ {
+ rte_trace_in(D_FILTERS, c, new, "invalid");
+ stats->imp_updates_invalid++;
+ goto drop;
+ }
+
if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
new->flags |= REF_COW;
@@ -2397,9 +2408,29 @@ rt_preconfig(struct config *c)
*/
void
-rta_apply_hostentry(rta *a, struct hostentry *he)
+ea_set_hostentry(ea_list **to, struct rtable *dep, struct rtable *tab, ip_addr gw, ip_addr ll, u32 lnum, u32 labels[lnum])
{
- a->hostentry = he;
+ struct {
+ struct adata ad;
+ struct hostentry *he;
+ u32 labels[lnum];
+ } *head = (void *) tmp_alloc_adata(sizeof *head - sizeof(struct adata));
+
+ head->he = rt_get_hostentry(tab, gw, ll, dep);
+ memcpy(head->labels, labels, lnum * sizeof(u32));
+
+ ea_set_attr(to, EA_LITERAL_DIRECT_ADATA(
+ &ea_gen_hostentry, 0, &head->ad));
+}
+
+
+static void
+rta_apply_hostentry(rta *a, struct hostentry_adata *head)
+{
+ struct hostentry *he = head->he;
+ u32 *labels = head->labels;
+ u32 lnum = (u32 *) (head->ad.data + head->ad.length) - labels;
+
a->dest = he->dest;
ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, he->igp_metric);
@@ -2411,17 +2442,12 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
return;
}
- eattr *mls_ea = ea_find(a->eattrs, &ea_mpls_labels);
-
- if (!mls_ea && he->nexthop_linkable)
+ if (!lnum && he->nexthop_linkable)
{ /* Just link the nexthop chain, no label append happens. */
ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
return;
}
- const struct adata *mls = mls_ea ? mls_ea->u.ptr : NULL;
- uint mls_cnt = mls ? mls->length / sizeof(u32) : 0;
-
eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
@@ -2429,14 +2455,14 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
NEXTHOP_WALK(nh, nhad)
{
- if (nh->labels + mls_cnt > MPLS_MAX_LABEL_STACK)
+ if (nh->labels + lnum > MPLS_MAX_LABEL_STACK)
{
log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)",
- nh->labels, mls_cnt, nh->labels + mls_cnt, MPLS_MAX_LABEL_STACK);
+ nh->labels, lnum, nh->labels + lnum, MPLS_MAX_LABEL_STACK);
continue;
}
- total_size += NEXTHOP_SIZE_CNT(nh->labels + mls_cnt);
+ total_size += NEXTHOP_SIZE_CNT(nh->labels + lnum);
}
if (total_size == OFFSETOF(struct nexthop_adata, nh))
@@ -2453,14 +2479,14 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
NEXTHOP_WALK(nh, nhad)
{
- if (nh->labels + mls_cnt > MPLS_MAX_LABEL_STACK)
+ if (nh->labels + lnum > MPLS_MAX_LABEL_STACK)
continue;
memcpy(dest, nh, NEXTHOP_SIZE(nh));
- if (mls_cnt)
+ if (lnum)
{
- memcpy(&(dest->label[dest->labels]), mls->data, mls->length);
- dest->labels += mls_cnt;
+ memcpy(&(dest->label[dest->labels]), labels, lnum * sizeof labels[0]);
+ dest->labels += lnum;
}
if (ipa_nonzero(nh->gw))
@@ -2482,42 +2508,43 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
&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)
{
- 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);
+ e->attrs = rta_lookup(&a);
rt_lock_source(e->src);
return e;
@@ -3510,7 +3537,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
rta *a = e->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",
@@ -3583,7 +3610,7 @@ rt_update_hostcache(rtable *tab)
tab->hcu_scheduled = 0;
}
-struct hostentry *
+static struct hostentry *
rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
{
struct hostentry *he;