diff --git a/filter/config.Y b/filter/config.Y index 5cd52e40..6c503dad 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); @@ -751,6 +747,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); } ; term: @@ -776,8 +773,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); } @@ -870,9 +865,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); } @@ -915,7 +907,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 61cdb43e..aec6c4f8 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, } PACKED; /* Static attribute definition (members of struct rta) */ diff --git a/filter/f-inst.c b/filter/f-inst.c index 1378fe4a..a41fcc4f 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; default: bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code); @@ -618,6 +619,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); } @@ -785,20 +790,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 b41bc3f8..f0bea86e 100644 --- a/nest/route.h +++ b/nest/route.h @@ -235,7 +235,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 @@ -480,10 +479,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; @@ -505,11 +505,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 */ @@ -517,8 +512,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 */ @@ -707,7 +700,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 25e39488..94f89701 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -1099,13 +1099,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); @@ -1193,7 +1195,7 @@ rta_lookup(rta *o) rta *r; uint h; - ASSERT(!(o->aflags & RTAF_CACHED)); + ASSERT(!o->cached); if (o->eattrs) ea_normalize(o->eattrs); @@ -1204,7 +1206,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); @@ -1218,7 +1220,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) @@ -1228,7 +1230,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); } @@ -1243,7 +1245,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; } @@ -1263,10 +1265,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 240cc8fc..7a340160 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -78,13 +78,14 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) rta a0 = { /* Use iface ID as local source ID */ .src = rt_get_source(P, ad->iface->index), + .pref = c->preference, .source = RTS_DEVICE, .scope = SCOPE_UNIVERSE, .dest = RTD_UNICAST, .nh.iface = ad->iface, }; rte e0 = { - .attrs = rta_lookup(&a0), + .attrs = &a0, }; rte_update(c, net, &e0); } diff --git a/nest/rt-show.c b/nest/rt-show.c index 7691878d..11eab25b 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 2c2a2000..df971032 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -285,7 +285,7 @@ rte_store(rte *r) { rte *e = sl_alloc(rte_slab); memcpy(e, r, sizeof(rte)); - if (e->attrs->aflags & RTAF_CACHED) + if (e->attrs->cached) e->attrs = rta_clone(r->attrs); else e->attrs = rta_lookup(r->attrs); @@ -504,9 +504,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) { @@ -530,7 +530,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) @@ -1063,7 +1063,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); } @@ -1410,9 +1409,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)) { @@ -1508,6 +1504,12 @@ rte_update(struct channel *c, const net_addr *n, struct rte *new) ASSERT(new->attrs); ASSERT(new->attrs->src); + if (!new->attrs->pref) + { + ASSERT(!new->attrs->cached); + new->attrs->pref = c->preference; + } + rte *e = sl_alloc(rte_slab); *e = *new; @@ -1674,7 +1676,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); @@ -2127,7 +2129,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)); @@ -2490,9 +2492,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 5d4f563b..e51700ae 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -634,6 +634,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, @@ -648,7 +649,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) a0.nh.flags = RNF_ONLINK; rte e0 = { - .attrs = rta_lookup(&a0), + .attrs = &a0, .u.babel = { .seqno = r->seqno, .metric = r->metric, @@ -668,11 +669,11 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) .source = RTS_BABEL, .scope = SCOPE_UNIVERSE, .dest = RTD_UNREACHABLE, + .pref = 1, }; rte e0 = { .attrs = &a0, - .pref = 1, }; e->unreachable = 1; @@ -1857,7 +1858,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 6752cb7f..a79508ee 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -2118,7 +2118,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 @@ -2133,7 +2133,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; @@ -2356,7 +2356,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 55875950..03f5e7dd 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2438,6 +2438,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 ba8c2e2b..09cd898f 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -607,7 +607,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 00d1b237..8448d181 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2052,6 +2052,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 a72023b3..ec2a9014 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 b79ae0b9..a06282ea 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -68,7 +68,7 @@ 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->attrs = rta_lookup(a); @@ -76,7 +76,6 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o /* 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 b67d457f..d47447be 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, @@ -189,7 +190,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) } rte e0 = { - .attrs = rta_lookup(&a0), + .attrs = &a0, .u.rip = { .from = a0.nh.iface, .metric = rt_metric, @@ -1197,7 +1198,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 68550721..9589b7c9 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -122,12 +122,13 @@ 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, }; - rte e0 = { .attrs = rta_lookup(&a0) }; + rte e0 = { .attrs = &a0 }; rte_update(channel, &pfxr->n, &e0); } diff --git a/proto/static/static.c b/proto/static/static.c index e6556f12..ff66589c 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) { @@ -720,9 +721,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 882f276f..1e6fb6be 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -434,6 +434,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 = rte_store(e); old_best = n->routes;