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.c116
1 files changed, 77 insertions, 39 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 8c429874..a33b7909 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -708,19 +708,17 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
}
-static struct mpnh *
-mpnh_merge_rta(struct mpnh *nhs, rta *a, linpool *pool, int max)
+static struct nexthop *
+nexthop_merge_rta(struct nexthop *nhs, rta *a, linpool *pool, int max)
{
- struct mpnh nh = { .gw = a->gw, .iface = a->iface };
- struct mpnh *nh2 = (a->dest == RTD_MULTIPATH) ? a->nexthops : &nh;
- return mpnh_merge(nhs, nh2, 1, 0, max, pool);
+ return nexthop_merge(nhs, &(a->nh), 1, 0, max, pool);
}
rte *
rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
{
// struct proto *p = c->proto;
- struct mpnh *nhs = NULL;
+ struct nexthop *nhs = NULL;
rte *best0, *best, *rt0, *rt, *tmp;
best0 = net->routes;
@@ -745,7 +743,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin
continue;
if (rte_is_reachable(rt))
- nhs = mpnh_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
+ nhs = nexthop_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
if (tmp)
rte_free(tmp);
@@ -753,13 +751,12 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, lin
if (nhs)
{
- nhs = mpnh_merge_rta(nhs, best->attrs, pool, c->merge_limit);
+ nhs = nexthop_merge_rta(nhs, best->attrs, pool, c->merge_limit);
if (nhs->next)
{
best = rte_cow_rta(best, pool);
- best->attrs->dest = RTD_MULTIPATH;
- best->attrs->nexthops = nhs;
+ nexthop_link(best->attrs, nhs);
}
}
@@ -922,7 +919,7 @@ rte_validate(rte *e)
return 0;
}
- if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops))
+ if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh)))
{
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
n->n.addr, e->sender->proto->name);
@@ -1763,33 +1760,63 @@ rta_next_hop_outdated(rta *a)
if (!he->src)
return a->dest != RTD_UNREACHABLE;
- return (a->iface != he->src->iface) || !ipa_equal(a->gw, he->gw) ||
- (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
- !mpnh_same(a->nexthops, he->src->nexthops);
+ return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
+ !nexthop_same(&(a->nh), he->nh);
}
static inline void
rta_apply_hostentry(rta *a, struct hostentry *he)
{
a->hostentry = he;
- a->iface = he->src ? he->src->iface : NULL;
- a->gw = he->gw;
a->dest = he->dest;
a->igp_metric = he->igp_metric;
- a->nexthops = he->src ? he->src->nexthops : NULL;
+
+ if (a->nh.labels_append == 0)
+ {
+ a->nh = *(he->nh);
+ a->nh.labels_append = 0;
+ return;
+ }
+
+ int labels_append = a->nh.labels_append;
+ u32 label_stack[MPLS_MAX_LABEL_STACK];
+ memcpy(label_stack, a->nh.label, labels_append * sizeof(u32));
+
+ struct nexthop *nhp = NULL;
+ for (struct nexthop *nh = he->nh; nh; nh = nh->next)
+ {
+ nhp = nhp ? (nhp->next = lp_alloc(rte_update_pool, NEXTHOP_MAX_SIZE)) : &(a->nh);
+ nhp->gw = ipa_nonzero(nh->gw) ? nh->gw : he->link;
+ nhp->iface = nh->iface; /* FIXME: This is at least strange, if not utter nonsense. */
+ nhp->weight = nh->weight;
+ nhp->labels = nh->labels + labels_append;
+ nhp->labels_append = labels_append;
+ if (nhp->labels <= MPLS_MAX_LABEL_STACK)
+ {
+ memcpy(nhp->label, nh->label, nh->labels * sizeof(u32));
+ memcpy(&(nhp->label[nh->labels]), label_stack, labels_append * sizeof(u32));
+ }
+ else
+ {
+ log(L_WARN "Sum of label stack sizes %d + %d = %d exceedes allowed maximum (%d)",
+ nh->labels, labels_append, nhp->labels, MPLS_MAX_LABEL_STACK);
+ a->dest = RTD_UNREACHABLE;
+ break;
+ }
+ }
}
static inline rte *
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
{
- rta a;
- memcpy(&a, old->attrs, sizeof(rta));
- rta_apply_hostentry(&a, old->attrs->hostentry);
- a.aflags = 0;
+ rta *a = alloca(RTA_MAX_SIZE);
+ memcpy(a, old->attrs, rta_size(old->attrs));
+ rta_apply_hostentry(a, old->attrs->hostentry);
+ a->aflags = 0;
rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte));
- e->attrs = rta_lookup(&a);
+ e->attrs = rta_lookup(a);
return e;
}
@@ -2310,8 +2337,7 @@ rt_get_igp_metric(rte *rt)
return rt->u.rip.metric;
#endif
- /* Device routes */
- if ((a->dest != RTD_ROUTER) && (a->dest != RTD_MULTIPATH))
+ if (a->source == RTS_DEVICE)
return 0;
return IGP_METRIC_UNKNOWN;
@@ -2325,7 +2351,6 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
/* Reset the hostentry */
he->src = NULL;
- he->gw = IPA_NONE;
he->dest = RTD_UNREACHABLE;
he->igp_metric = 0;
@@ -2346,24 +2371,25 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
goto done;
}
- if (a->dest == RTD_DEVICE)
+ if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next)
{
- if (if_local_addr(he->addr, a->iface))
+ /* We have singlepath device route */
+ if (if_local_addr(he->addr, a->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, a->iface->name);
+ he->addr, a->nh.iface->name);
goto done;
}
/* The host is directly reachable, use link as a gateway */
- he->gw = he->link;
- he->dest = RTD_ROUTER;
+ he->nh = NULL;
+ he->dest = RTD_UNICAST;
}
else
{
/* The host is reachable through some route entry */
- he->gw = a->gw;
+ he->nh = &(a->nh);
he->dest = a->dest;
}
@@ -2442,16 +2468,14 @@ rt_format_via(rte *e)
rta *a = e->attrs;
/* Max text length w/o IP addr and interface name is 16 */
- static byte via[IPA_MAX_TEXT_LENGTH+sizeof(a->iface->name)+16];
+ static byte via[IPA_MAX_TEXT_LENGTH+sizeof(a->nh.iface->name)+16];
switch (a->dest)
{
- case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break;
- case RTD_DEVICE: bsprintf(via, "dev %s", a->iface->name); break;
+ case RTD_UNICAST: bsprintf(via, "unicast"); break;
case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break;
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
- case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
default: bsprintf(via, "???");
}
return via;
@@ -2466,10 +2490,10 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
int primary = (e->net->routes == e);
int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
- struct mpnh *nh;
+ struct nexthop *nh;
tm_format_datetime(tm, &config->tf_route, e->lastmod);
- if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw))
+ if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
bsprintf(from, " from %I", a->from);
else
from[0] = 0;
@@ -2490,10 +2514,24 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
bsprintf(info, " (%d)", e->pref);
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rt_format_via(e), a->src->proto->name,
tm, from, primary ? (sync_error ? " !" : " *") : "", info);
- for (nh = a->nexthops; nh; nh = nh->next)
- cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1);
+ for (nh = &(a->nh); nh; nh = nh->next)
+ {
+ char ls[MPLS_MAX_LABEL_STACK*8 + 5]; char *lsp = ls;
+ if (nh->labels)
+ {
+ lsp += bsprintf(lsp, " mpls %d", nh->label[0]);
+ for (int i=1;i<nh->labels; i++)
+ lsp += bsprintf(lsp, "/%d", nh->label[i]);
+ *lsp++ = '\0';
+ }
+ if (a->nh.next)
+ cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, (nh->labels ? ls : ""), nh->iface->name, nh->weight + 1);
+ else
+ cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, (nh->labels ? ls : ""), nh->iface->name);
+ }
if (d->verbose)
rta_show(c, a, tmpa);
+
}
static void