diff options
Diffstat (limited to 'nest/rt-table.c')
-rw-r--r-- | nest/rt-table.c | 115 |
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; |