summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/config.Y11
-rw-r--r--filter/data.h1
-rw-r--r--filter/f-inst.c19
-rw-r--r--lib/hash.h6
-rw-r--r--nest/route.h19
-rw-r--r--nest/rt-attr.c24
-rw-r--r--nest/rt-dev.c1
-rw-r--r--nest/rt-show.c2
-rw-r--r--nest/rt-table.c18
-rw-r--r--proto/babel/babel.c5
-rw-r--r--proto/bgp/attrs.c6
-rw-r--r--proto/bgp/packets.c1
-rw-r--r--proto/ospf/ospf.c2
-rw-r--r--proto/ospf/rt.c1
-rw-r--r--proto/perf/perf.c1
-rw-r--r--proto/pipe/pipe.c3
-rw-r--r--proto/rip/rip.c3
-rw-r--r--proto/rpki/rpki.c1
-rw-r--r--proto/static/static.c5
-rw-r--r--sysdep/unix/krt.c3
20 files changed, 59 insertions, 73 deletions
diff --git a/filter/config.Y b/filter/config.Y
index e6b59cbe..8034b790 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -248,10 +248,6 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const
setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
getter = f_new_inst(FI_VAR_GET, lval->sym);
break;
- case F_LVAL_PREFERENCE:
- setter = f_new_inst(FI_PREF_SET, expr);
- getter = f_new_inst(FI_PREF_GET);
- break;
case F_LVAL_SA:
setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
getter = f_new_inst(FI_RTA_GET, lval->sa);
@@ -757,6 +753,7 @@ static_attr:
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
| WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
+ | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); }
| GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
;
@@ -783,8 +780,6 @@ term:
| constant { $$ = $1; }
| constructor { $$ = $1; }
- | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
-
| static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
| dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
@@ -877,9 +872,6 @@ cmd:
cf_error( "This static attribute is read-only.");
$$ = f_new_inst(FI_RTA_SET, $3, $1);
}
- | PREFERENCE '=' term ';' {
- $$ = f_new_inst(FI_PREF_SET, $3);
- }
| UNSET '(' dynamic_attr ')' ';' {
$$ = f_new_inst(FI_EA_UNSET, $3);
}
@@ -922,7 +914,6 @@ get_cf_position:
lvalue:
CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
- | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
| static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
| dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
diff --git a/filter/data.h b/filter/data.h
index d296776d..45246f9f 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -100,6 +100,7 @@ enum f_sa_code {
SA_IFNAME,
SA_IFINDEX,
SA_WEIGHT,
+ SA_PREF,
SA_GW_MPLS,
} PACKED;
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 7c757e74..2a837537 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -533,6 +533,7 @@
case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break;
+ case SA_PREF: RESULT(sa.f_type, i, rta->pref); break;
case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
default:
@@ -637,6 +638,10 @@
}
break;
+ case SA_PREF:
+ rta->pref = v1.val.i;
+ break;
+
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
@@ -804,20 +809,6 @@
}
}
- INST(FI_PREF_GET, 0, 1) {
- ACCESS_RTE;
- RESULT(T_INT, i, (*fs->rte)->pref);
- }
-
- INST(FI_PREF_SET, 1, 0) {
- ACCESS_RTE;
- ARG(1,T_INT);
- if (v1.val.i > 0xFFFF)
- runtime( "Setting preference value out of bounds" );
- f_rte_cow(fs);
- (*fs->rte)->pref = v1.val.i;
- }
-
INST(FI_LENGTH, 1, 1) { /* Get length of */
ARG_ANY(1);
switch(v1.type) {
diff --git a/lib/hash.h b/lib/hash.h
index ea4ca6dd..8febb33f 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -215,6 +215,12 @@ mem_hash_mix(u64 *h, const void *p, uint s)
*h = *h * multiplier + pp[i];
}
+static inline void
+mem_hash_mix_num(u64 *h, u64 val)
+{
+ mem_hash_mix(h, &val, sizeof(val));
+}
+
static inline uint
mem_hash_value(u64 *h)
{
diff --git a/nest/route.h b/nest/route.h
index 227a5f5e..aec867e2 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -241,7 +241,6 @@ typedef struct rte {
u32 id; /* Table specific route id */
byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */
- word pref; /* Route preference */
btime lastmod; /* Last modified */
union { /* Protocol-dependent data (metrics etc.) */
#ifdef CONFIG_RIP
@@ -446,10 +445,11 @@ typedef struct rta {
struct hostentry *hostentry; /* Hostentry for recursive next-hops */
ip_addr from; /* Advertising router */
u32 igp_metric; /* IGP metric to next hop (for iBGP routes) */
- u8 source; /* Route source (RTS_...) */
- u8 scope; /* Route scope (SCOPE_... -- see ip.h) */
- u8 dest; /* Route destination type (RTD_...) */
- u8 aflags;
+ u16 cached:1; /* Are attributes cached? */
+ u16 source:7; /* Route source (RTS_...) */
+ u16 scope:4; /* Route scope (SCOPE_... -- see ip.h) */
+ u16 dest:4; /* Route destination type (RTD_...) */
+ word pref;
struct nexthop nh; /* Next hop */
} rta;
@@ -471,11 +471,6 @@ typedef struct rta {
#define RTS_PERF 15 /* Perf checker */
#define RTS_MAX 16
-#define RTC_UNICAST 0
-#define RTC_BROADCAST 1
-#define RTC_MULTICAST 2
-#define RTC_ANYCAST 3 /* IPv6 Anycast */
-
#define RTD_NONE 0 /* Undefined next hop */
#define RTD_UNICAST 1 /* Next hop is neighbor router */
#define RTD_BLACKHOLE 2 /* Silently drop packets */
@@ -483,8 +478,6 @@ typedef struct rta {
#define RTD_PROHIBIT 4 /* Administratively prohibited */
#define RTD_MAX 5
-#define RTAF_CACHED 1 /* This is a cached rta */
-
#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other
protocol-specific metric is availabe */
@@ -673,7 +666,7 @@ void rta_init(void);
static inline size_t rta_size(const rta *a) { return sizeof(rta) + sizeof(u32)*a->nh.labels; }
#define RTA_MAX_SIZE (sizeof(rta) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
-static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
+static inline int rta_is_cached(rta *r) { return r->cached; }
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index c630aa95..4198b552 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -1104,13 +1104,15 @@ rta_hash(rta *a)
u64 h;
mem_hash_init(&h);
#define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f));
+#define BMIX(f) mem_hash_mix_num(&h, a->f);
MIX(src);
MIX(hostentry);
MIX(from);
MIX(igp_metric);
- MIX(source);
- MIX(scope);
- MIX(dest);
+ BMIX(source);
+ BMIX(scope);
+ BMIX(dest);
+ MIX(pref);
#undef MIX
return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
@@ -1198,7 +1200,7 @@ rta_lookup(rta *o)
rta *r;
uint h;
- ASSERT(!(o->aflags & RTAF_CACHED));
+ ASSERT(!o->cached);
if (o->eattrs)
ea_normalize(o->eattrs);
@@ -1209,7 +1211,7 @@ rta_lookup(rta *o)
r = rta_copy(o);
r->hash_key = h;
- r->aflags = RTAF_CACHED;
+ r->cached = 1;
rt_lock_source(r->src);
rt_lock_hostentry(r->hostentry);
rta_insert(r);
@@ -1223,7 +1225,7 @@ rta_lookup(rta *o)
void
rta__free(rta *a)
{
- ASSERT(rta_cache_count && (a->aflags & RTAF_CACHED));
+ ASSERT(rta_cache_count && a->cached);
rta_cache_count--;
*a->pprev = a->next;
if (a->next)
@@ -1233,7 +1235,7 @@ rta__free(rta *a)
if (a->nh.next)
nexthop_free(a->nh.next);
ea_free(a->eattrs);
- a->aflags = 0; /* Poison the entry */
+ a->cached = 0;
sl_free(rta_slab(a), a);
}
@@ -1248,7 +1250,7 @@ rta_do_cow(rta *o, linpool *lp)
memcpy(*nhn, nho, nexthop_size(nho));
nhn = &((*nhn)->next);
}
- r->aflags = 0;
+ r->cached = 0;
r->uc = 0;
return r;
}
@@ -1268,10 +1270,10 @@ rta_dump(rta *a)
"RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
- debug("p=%s uc=%d %s %s%s h=%04x",
- a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope),
+ debug("p=%s pref=%d uc=%d %s %s%s h=%04x",
+ a->src->proto->name, a->pref, a->uc, rts[a->source], ip_scope_text(a->scope),
rtd[a->dest], a->hash_key);
- if (!(a->aflags & RTAF_CACHED))
+ if (!a->cached)
debug(" !CACHED");
debug(" <-%I", a->from);
if (a->dest == RTD_UNICAST)
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 61f025ce..b8e945cf 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -84,6 +84,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
rta a0 = {
.src = src,
+ .pref = c->preference,
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
diff --git a/nest/rt-show.c b/nest/rt-show.c
index cccd91ab..a0c675de 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -60,7 +60,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
if (get_route_info)
get_route_info(e, info);
else
- bsprintf(info, " (%d)", e->pref);
+ bsprintf(info, " (%d)", a->pref);
if (d->last_table != d->tab)
rt_show_table(c, d);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index eb306227..0b06be92 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -286,7 +286,6 @@ rte_get_temp(rta *a)
e->attrs = a;
e->id = 0;
e->flags = 0;
- e->pref = 0;
return e;
}
@@ -533,9 +532,9 @@ rte_better(rte *new, rte *old)
if (!rte_is_valid(new))
return 0;
- if (new->pref > old->pref)
+ if (new->attrs->pref > old->attrs->pref)
return 1;
- if (new->pref < old->pref)
+ if (new->attrs->pref < old->attrs->pref)
return 0;
if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
{
@@ -559,7 +558,7 @@ rte_mergable(rte *pri, rte *sec)
if (!rte_is_valid(pri) || !rte_is_valid(sec))
return 0;
- if (pri->pref != sec->pref)
+ if (pri->attrs->pref != sec->attrs->pref)
return 0;
if (pri->attrs->src->proto->proto != sec->attrs->src->proto->proto)
@@ -1080,7 +1079,6 @@ rte_same(rte *x, rte *y)
return
x->attrs == y->attrs &&
x->pflags == y->pflags &&
- x->pref == y->pref &&
(!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)) &&
rte_is_filtered(x) == rte_is_filtered(y);
}
@@ -1469,9 +1467,6 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
new->net = nn;
new->sender = c;
- if (!new->pref)
- new->pref = c->preference;
-
stats->imp_updates_received++;
if (!rte_validate(new))
{
@@ -1710,7 +1705,7 @@ rte_dump(rte *e)
{
net *n = e->net;
debug("%-1N ", n->n.addr);
- debug("PF=%02x pref=%d ", e->pflags, e->pref);
+ debug("PF=%02x ", e->pflags);
rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e);
@@ -2222,7 +2217,7 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
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;
+ a->cached = 0;
rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte));
@@ -2576,9 +2571,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
{
net = net_get(tab, n);
- if (!new->pref)
- new->pref = c->preference;
-
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
}
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 68cc62f1..246eea00 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -645,6 +645,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
+ .pref = c->preference,
.from = r->neigh->addr,
.nh.gw = r->next_hop,
.nh.iface = r->neigh->ifa->iface,
@@ -676,13 +677,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNREACHABLE,
+ .pref = 1,
};
rta *a = rta_lookup(&a0);
rte *rte = rte_get_temp(a);
memset(&rte->u.babel, 0, sizeof(rte->u.babel));
rte->pflags = 0;
- rte->pref = 1;
e->unreachable = 1;
rte_update2(c, e->n.addr, rte, p->p.main_source);
@@ -2010,7 +2011,7 @@ babel_dump(struct proto *P)
static void
babel_get_route_info(rte *rte, byte *buf)
{
- buf += bsprintf(buf, " (%d/%d) [%lR]", rte->pref, rte->u.babel.metric, rte->u.babel.router_id);
+ buf += bsprintf(buf, " (%d/%d) [%lR]", rte->attrs->pref, rte->u.babel.metric, rte->u.babel.router_id);
}
static int
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 95d1c337..3bdc7596 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -2117,7 +2117,7 @@ bgp_rte_mergable(rte *pri, rte *sec)
static inline int
same_group(rte *r, u32 lpref, u32 lasn)
{
- return (r->pref == lpref) && (bgp_get_neighbor(r) == lasn);
+ return (r->attrs->pref == lpref) && (bgp_get_neighbor(r) == lasn);
}
static inline int
@@ -2132,7 +2132,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
{
rte *r, *s;
rte *key = new ? new : old;
- u32 lpref = key->pref;
+ u32 lpref = key->attrs->pref;
u32 lasn = bgp_get_neighbor(key);
int old_suppressed = old ? old->u.bgp.suppressed : 0;
@@ -2355,7 +2355,7 @@ bgp_get_route_info(rte *e, byte *buf)
eattr *o = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
u32 origas;
- buf += bsprintf(buf, " (%d", e->pref);
+ buf += bsprintf(buf, " (%d", e->attrs->pref);
if (e->u.bgp.suppressed)
buf += bsprintf(buf, "-");
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 99b5d5b4..8d107795 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -2440,6 +2440,7 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
a->scope = SCOPE_UNIVERSE;
a->from = s->proto->remote_ip;
a->eattrs = ea;
+ a->pref = c->c.preference;
c->desc->decode_next_hop(s, nh, nh_len, a);
bgp_finish_attrs(s, a);
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 48e078ed..4b69e011 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -609,7 +609,7 @@ ospf_get_route_info(rte * rte, byte * buf)
}
buf += bsprintf(buf, " %s", type);
- buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1);
+ buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, rte->u.ospf.metric1);
if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
buf += bsprintf(buf, ")");
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index faee49dc..eb2aa393 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -2058,6 +2058,7 @@ again1:
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh = *(nf->n.nhs),
+ .pref = p->p.main_channel->preference,
};
if (reload || ort_changed(nf, &a0))
diff --git a/proto/perf/perf.c b/proto/perf/perf.c
index ba401a8a..692be2c0 100644
--- a/proto/perf/perf.c
+++ b/proto/perf/perf.c
@@ -147,6 +147,7 @@ perf_loop(void *data)
.source = RTS_PERF,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
+ .pref = p->p.main_channel->preference,
.nh.iface = p->ifa->iface,
.nh.gw = gw,
.nh.weight = 1,
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index a50d44a3..a2fc2ddf 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -68,14 +68,13 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
a = alloca(rta_size(new->attrs));
memcpy(a, new->attrs, rta_size(new->attrs));
- a->aflags = 0;
+ a->cached = 0;
a->hostentry = NULL;
e = rte_get_temp(a);
e->pflags = 0;
/* Copy protocol specific embedded attributes. */
memcpy(&(e->u), &(new->u), sizeof(e->u));
- e->pref = new->pref;
e->pflags = new->pflags;
#ifdef CONFIG_BGP
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index e1a235a0..65147a1f 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -146,6 +146,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
/* Update */
rta a0 = {
.src = p->p.main_source,
+ .pref = p->p.main_channel->preference,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
@@ -1198,7 +1199,7 @@ rip_reconfigure(struct proto *P, struct proto_config *CF)
static void
rip_get_route_info(rte *rte, byte *buf)
{
- buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
+ buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rte->u.rip.metric);
if (rte->u.rip.tag)
bsprintf(buf, " [%04x]", rte->u.rip.tag);
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index ab0837f3..fefea4b4 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -122,6 +122,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
rta a0 = {
.src = p->p.main_source,
+ .pref = channel->preference,
.source = RTS_RPKI,
.scope = SCOPE_UNIVERSE,
.dest = RTD_NONE,
diff --git a/proto/static/static.c b/proto/static/static.c
index 2789c1bb..2d141c07 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -60,6 +60,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
a->source = RTS_STATIC;
a->scope = SCOPE_UNIVERSE;
a->dest = r->dest;
+ a->pref = p->p.main_channel->preference;
if (r->dest == RTD_UNICAST)
{
@@ -721,9 +722,9 @@ static_get_route_info(rte *rte, byte *buf)
{
eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC);
if (a)
- buf += bsprintf(buf, " (%d/%u)", rte->pref, a->u.data);
+ buf += bsprintf(buf, " (%d/%u)", rte->attrs->pref, a->u.data);
else
- buf += bsprintf(buf, " (%d)", rte->pref);
+ buf += bsprintf(buf, " (%d)", rte->attrs->pref);
}
static void
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index da61fc9c..65d8d968 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -433,6 +433,9 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
net *n = net_get(p->krt_table, n0->n.addr);
rte *g, **gg, *best, **bestp, *old_best;
+ ASSERT(!e->attrs->cached);
+ e->attrs->pref = p->p.main_channel->preference;
+
e->attrs = rta_lookup(e->attrs);
old_best = n->routes;