}
static inline void
-rta_apply_hostentry(rta *a, struct hostentry *he)
+rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls)
{
a->hostentry = he;
a->dest = he->dest;
a->igp_metric = he->igp_metric;
- if ((a->nh.labels_orig == 0) && (!a->nh.next) && he->nexthop_linkable)
+ if (a->dest != RTD_UNICAST)
{
- a->nh = he->src->nh;
+ /* No nexthop */
+no_nexthop:
+ a->nh = (struct nexthop) {};
+ if (mls)
+ { /* Store the label stack for later changes */
+ a->nh.labels_orig = a->nh.labels = mls->len;
+ memcpy(a->nh.label, mls->stack, mls->len * sizeof(u32));
+ }
return;
}
- struct nexthop *nhp = alloca(NEXTHOP_MAX_SIZE);
+ if (((!mls) || (!mls->len)) && he->nexthop_linkable)
+ { /* Just link the nexthop chain, no label append happens. */
+ memcpy(&(a->nh), &(he->src->nh), nexthop_size(&(he->src->nh)));
+ return;
+ }
+
+ struct nexthop *nhp = NULL, *nhr = NULL;
+ int skip_nexthop = 0;
- for (struct nexthop *nhe = &(a->nh); nhe; nhe = nhe->next)
+ for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next)
{
- int labels_orig = nhe->labels_orig; /* Number of labels (at the bottom of stack) */
- u32 label_stack[MPLS_MAX_LABEL_STACK];
- memcpy(label_stack, nhe->label, labels_orig * sizeof(u32));
+ if (skip_nexthop)
+ skip_nexthop--;
+ else
+ {
+ nhr = nhp;
+ nhp = (nhp ? (nhp->next = lp_allocz(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh));
+ }
- for (struct nexthop *nh = &(he->src->nh); nh; nh = nh->next)
+ nhp->iface = nh->iface;
+ nhp->weight = nh->weight;
+ if (mls)
{
- nhp->iface = nh->iface;
- nhp->weight = nh->weight; /* FIXME: Ignoring the recursive nexthop's weight */
- nhp->labels = nh->labels + labels_orig;
- nhp->labels_orig = labels_orig;
+ nhp->labels = nh->labels + mls->len;
+ nhp->labels_orig = mls->len;
if (nhp->labels <= MPLS_MAX_LABEL_STACK)
{
memcpy(nhp->label, nh->label, nh->labels * sizeof(u32)); /* First the hostentry labels */
- memcpy(&(nhp->label[nh->labels]), label_stack, labels_orig * sizeof(u32)); /* Then the bottom labels */
+ memcpy(&(nhp->label[nh->labels]), mls->stack, mls->len * sizeof(u32)); /* Then the bottom labels */
}
else
{
log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)",
- nh->labels, labels_orig, nhp->labels, MPLS_MAX_LABEL_STACK);
+ nh->labels, mls->len, nhp->labels, MPLS_MAX_LABEL_STACK);
+ skip_nexthop++;
continue;
}
- if (ipa_nonzero(nh->gw))
- nhp->gw = nh->gw; /* Router nexthop */
- else if (ipa_nonzero(he->link))
- nhp->gw = he->link; /* Device nexthop with link-local address known */
- else
- nhp->gw = he->addr; /* Device nexthop with link-local address unknown */
-
- nhp = (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE));
}
+ if (ipa_nonzero(nh->gw))
+ nhp->gw = nh->gw; /* Router nexthop */
+ else if (ipa_nonzero(he->link))
+ nhp->gw = he->link; /* Device nexthop with link-local address known */
+ else
+ nhp->gw = he->addr; /* Device nexthop with link-local address unknown */
}
- memcpy(&(a->nh), nhp, nexthop_size(nhp));
+ if (skip_nexthop)
+ if (nhr)
+ nhr->next = NULL;
+ else
+ {
+ a->dest = RTD_UNREACHABLE;
+ log(L_WARN "No valid nexthop remaining, setting route unreachable");
+ goto no_nexthop;
+ }
}
static inline rte *
{
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, old->attrs, rta_size(old->attrs));
- rta_apply_hostentry(a, old->attrs->hostentry);
+
+ mpls_label_stack mls = { .len = a->nh.labels_orig };
+ memcpy(mls.stack, &a->nh.label[a->nh.labels - mls.len], mls.len * sizeof(u32));
+
+ rta_apply_hostentry(a, old->attrs->hostentry, &mls);
a->aflags = 0;
rte *e = sl_alloc(rte_slab);
goto done;
}
+ he->dest = a->dest;
he->nexthop_linkable = 1;
- for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
- if (ipa_zero(nh->gw))
- {
- he->nexthop_linkable = 0;
- break;
- }
+ if (he->dest == RTD_UNICAST)
+ {
+ for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
+ if (ipa_zero(nh->gw))
+ {
+ if (if_local_addr(he->addr, nh->iface))
+ {
+ /* The host address is a local address, this is not valid */
+ log(L_WARN "Next hop address %I is a local address of iface %s",
+ he->addr, nh->iface->name);
+ goto done;
+ }
+
+ he->nexthop_linkable = 0;
+ break;
+ }
+ }
he->src = rta_clone(a);
he->igp_metric = rt_get_igp_metric(e);
}
void
-rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll)
+rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr ll, mpls_label_stack *mls)
{
- rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ipa_zero(ll) ? gw : ll, dep));
+ rta_apply_hostentry(a, rt_get_hostentry(tab, gw, ipa_zero(ll) ? gw : ll, dep), mls);
}
nh->gw = r2->via;
nh->iface = r2->neigh->iface;
nh->weight = r2->weight;
- nh->labels = r2->label_count;
- memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32));
+ if (r2->mls)
+ {
+ nh->labels = r2->mls->len;
+ memcpy(nh->label, r2->mls->stack, r2->mls->len * sizeof(u32));
+ }
nexthop_insert(&nhs, nh);
}
}
if (r->dest == RTDX_RECURSIVE)
- {
- a->nh.labels_orig = a->nh.labels = r->label_count;
- memcpy(a->nh.label, r->label_stack, r->label_count * sizeof(u32));
- rta_set_recursive_next_hop(p->p.main_channel->table, a, p_igp_table(p), r->via, IPA_NONE);
- }
+ rta_set_recursive_next_hop(p->p.main_channel->table, a, p_igp_table(p), r->via, IPA_NONE, r->mls);
/* Already announced */
if (r->state == SRS_CLEAN)
(x->iface != y->iface) ||
(x->use_bfd != y->use_bfd) ||
(x->weight != y->weight) ||
- (x->label_count != y->label_count))
+ (!x->mls != !y->mls) ||
+ ((x->mls) && (y->mls) && (x->mls->len != y->mls->len)))
return 0;
- for (int i = 0; i < x->label_count; i++)
- if (x->label_stack[i] != y->label_stack[i])
+ if (!x->mls)
+ continue;
+
+ for (uint i = 0; i < x->mls->len; i++)
+ if (x->mls->stack[i] != y->mls->stack[i])
return 0;
}
return !x && !y;
case RTDX_RECURSIVE:
- return ipa_equal(x->via, y->via);
+ if (!ipa_equal(x->via, y->via) ||
+ (!x->mls != !y->mls) ||
+ ((x->mls) && (y->mls) && (x->mls->len != y->mls->len)))
+ return 0;
+
+ if (!x->mls)
+ return 1;
+
+ for (uint i = 0; i < x->mls->len; i++)
+ if (x->mls->stack[i] != y->mls->stack[i])
+ return 0;
+
+ return 1;
default:
return 1;