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.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 9e9d4c7a..eb9dc3a5 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -50,7 +50,7 @@ static linpool *rte_update_pool;
static list routing_tables;
-static void rt_format_via(rte *e, byte *via);
+static byte *rt_format_via(rte *e);
static void rt_free_hostcache(rtable *tab);
static void rt_notify_hostcache(rtable *tab, net *net);
static void rt_update_hostcache(rtable *tab);
@@ -346,10 +346,7 @@ rte_mergable(rte *pri, rte *sec)
static void
rte_trace(struct proto *p, rte *e, int dir, char *msg)
{
- byte via[IPA_MAX_TEXT_LENGTH+32];
-
- rt_format_via(e, via);
- log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, via);
+ log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rt_format_via(e));
}
static inline void
@@ -367,7 +364,7 @@ rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
}
static rte *
-export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
+export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpool *pool, int silent)
{
struct proto *p = c->proto;
struct filter *filter = c->out_filter;
@@ -382,9 +379,9 @@ export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int si
if (!tmpa)
tmpa = &tmpb;
- *tmpa = make_tmp_attrs(rt, rte_update_pool);
+ *tmpa = make_tmp_attrs(rt, pool);
- v = p->import_control ? p->import_control(p, &rt, tmpa, rte_update_pool) : 0;
+ v = p->import_control ? p->import_control(p, &rt, tmpa, pool) : 0;
if (v < 0)
{
if (silent)
@@ -403,7 +400,7 @@ export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int si
}
v = filter && ((filter == FILTER_REJECT) ||
- (f_run(filter, &rt, tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT));
+ (f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT));
if (v)
{
if (silent)
@@ -426,6 +423,12 @@ export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int si
return NULL;
}
+static inline rte *
+export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
+{
+ return export_filter_(c, rt0, rt_free, tmpa, rte_update_pool, silent);
+}
+
static void
do_rt_notify(struct channel *c, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
{
@@ -706,7 +709,7 @@ 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, int max)
+mpnh_merge_rta(struct mpnh *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;
@@ -714,7 +717,7 @@ mpnh_merge_rta(struct mpnh *nhs, rta *a, int max)
}
rte *
-rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, int silent)
+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;
@@ -726,7 +729,7 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, int
if (!rte_is_valid(best0))
return NULL;
- best = export_filter(c, best0, rt_free, tmpa, silent);
+ best = export_filter_(c, best0, rt_free, tmpa, pool, silent);
if (!best || !rte_is_reachable(best))
return best;
@@ -736,13 +739,13 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, int
if (!rte_mergable(best0, rt0))
continue;
- rt = export_filter(c, rt0, &tmp, NULL, 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, c->merge_limit);
+ nhs = mpnh_merge_rta(nhs, rt->attrs, pool, c->merge_limit);
if (tmp)
rte_free(tmp);
@@ -750,11 +753,11 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, int
if (nhs)
{
- nhs = mpnh_merge_rta(nhs, best->attrs, c->merge_limit);
+ nhs = mpnh_merge_rta(nhs, best->attrs, pool, c->merge_limit);
if (nhs->next)
{
- best = rte_cow_rta(best, rte_update_pool);
+ best = rte_cow_rta(best, pool);
best->attrs->dest = RTD_MULTIPATH;
best->attrs->nexthops = nhs;
}
@@ -805,7 +808,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
/* Prepare new merged route */
if (new_best)
- new_best = rt_export_merged(c, net, &new_best_free, &tmpa, 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() */
@@ -919,6 +922,13 @@ rte_validate(rte *e)
return 0;
}
+ if ((e->attrs->dest == RTD_MULTIPATH) && !mpnh_is_sorted(e->attrs->nexthops))
+ {
+ log(L_WARN "Ignoring unsorted multipath route %N received via %s",
+ n->n.addr, e->sender->proto->name);
+ return 0;
+ }
+
return 1;
}
@@ -1848,7 +1858,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* FIXME: Better announcement of merged routes */
rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
- if (free_old_best)
+ if (free_old_best)
rte_free_quick(old_best);
return count;
@@ -2426,11 +2436,14 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_add
* CLI commands
*/
-static void
-rt_format_via(rte *e, byte *via)
+static byte *
+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];
+
switch (a->dest)
{
case RTD_ROUTER: bsprintf(via, "via %I on %s", a->gw, a->iface->name); break;
@@ -2441,12 +2454,12 @@ rt_format_via(rte *e, byte *via)
case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
default: bsprintf(via, "???");
}
+ return via;
}
static void
rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tmpa)
{
- byte via[IPA_MAX_TEXT_LENGTH+32];
byte from[IPA_MAX_TEXT_LENGTH+8];
byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
rta *a = e->attrs;
@@ -2455,7 +2468,6 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
struct mpnh *nh;
- rt_format_via(e, via);
tm_format_datetime(tm, &config->tf_route, e->lastmod);
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->gw))
bsprintf(from, " from %I", a->from);
@@ -2476,7 +2488,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
get_route_info(e, info, tmpa);
else
bsprintf(info, " (%d)", e->pref);
- cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->src->proto->name,
+ 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);
@@ -2517,7 +2529,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
{
rte *rt_free;
- e = rt_export_merged(ec, n, &rt_free, &tmpa, 1);
+ e = rt_export_merged(ec, n, &rt_free, &tmpa, rte_update_pool, 1);
pass = 1;
if (!e)