diff --git a/filter/config.Y b/filter/config.Y
index e6b59cbe99169f54f03a0a4f8446027ad9d00687..8034b790d6e8b4c71b5d0ef3b46d17aa4d11c114 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 d296776d934d3cca124eb92e0ced1db83cbd9b16..45246f9f9576f9e27aec65a07ed2b8b5d123652e 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 7c757e741d795f04549f5ce25a8e0258ff659616..2a837537e2b02269fd7164ff272a05e3155ec132 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 ea4ca6dde2363be00b0605de2f55057f40d947ce..8febb33fa99117a7c411ee9ca151f8a9d74f3580 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 227a5f5e1a3b5987bc926aa57aee776e6c751cbd..aec867e2136b71bb2ce7a7380e38fd4f86d83278 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 c630aa9540b13ef36398e78cf6569276f51eea39..4198b552b006553fd1dda3d915280264faa7877c 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 61f025cea8a28a974e9542dc579db83934f5184e..b8e945cff04d90bf00aa6fbb729ea185be49b076 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 cccd91ab28ddf6beb2a52a172bd3f88319d4c36e..a0c675dedc1cb5a169d600d69f1eee4c2ff1efcb 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 eb306227f5f066233fd347e00ebea8fbb19cd726..0b06be929bd43d44f99994a027d979e1e0a9a91f 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 68cc62f1e1705a004937a576525d9beb612e8bb5..246eea00ebfff87fc3069bcc70d62e1be811f491 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 95d1c337c569bbc63bf79735d3dad418617a808e..3bdc759642cf9638f926bd79aaaaf63b0a2d53ed 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 99b5d5b465ff5b52ac9b54056574925744e05bfa..8d107795500680ee19faf0ce45a2c0856ade020e 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 48e078ed5858100918da0b6a09b427becd61a8fb..4b69e011a6ff2ee25e7291f167f8edf9bc35147a 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 faee49dc0ba3ffda3a1bcf5c37eaaa04fc3314fc..eb2aa3930cf1ae0a66fc4041aa864895057b026e 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 ba401a8a321278e59703c51249eb53b9cc28d005..692be2c0087ce0ed47f70034bc94a463f0cad7d0 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 a50d44a3473cb21d2baf90ce535e28911e691384..a2fc2ddf4e5e1d9df3453b1793dfed088b20111b 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 e1a235a08e86e0ecd89a9ef49457b37ea302db0b..65147a1f37c9fdda41dba48ffcbf9e9be6c7e34f 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 ab0837f30abe76e4f7d7acd6a5f8a94bcdb498f4..fefea4b4ad7a4b31d7a11f28726055029bec84a0 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 2789c1bb454b55c6cccff4f76bb3d1a6bd4cf1ed..2d141c073d984b51726395eed26ae043aad53c7f 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 da61fc9c8ed99976f23fcd9c986ebd34b9be1082..65d8d9684b770efd80b3e9ea4b738bc962a6f350 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;