default value for new routes is <cf/SCOPE_UNIVERSE/.
<tag><label id="rta-preference"><m/int/ preference</tag>
- Preference of the route. Valid values are 0-65535. (See the chapter
- about routing tables.)
+ Preference of the route.
<tag><label id="rta-from"><m/ip/ from</tag>
The router which the route has originated from.
IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
- PREFERENCE,
ROA_CHECK, ASN, SRC, DST,
IS_V4, IS_V6,
LEN, MAXLEN,
| 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); }
;
SA_IFNAME,
SA_IFINDEX,
SA_WEIGHT,
- SA_PREF,
SA_GW_MPLS,
} PACKED;
case SA_IFNAME: RESULT(sa.type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
case SA_IFINDEX: RESULT(sa.type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
case SA_WEIGHT: RESULT(sa.type, i, rta->nh.weight + 1); break;
- case SA_PREF: RESULT(sa.type, i, rta->pref); break;
case SA_GW_MPLS: RESULT(sa.type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
default:
}
break;
- case SA_PREF:
- rta->pref = v1.val.i;
- break;
-
default:
bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code);
}
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;
struct ea_class *class;
};
-#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other
- protocol-specific metric is availabe */
-extern struct ea_class ea_gen_igp_metric;
-
void ea_register_init(struct ea_class *);
struct ea_class_ref *ea_register_alloc(pool *, struct ea_class);
ea_set_attr_data(ea_list **to, const struct ea_class *def, uint flags, void *data, uint len)
{ ea_set_attr(to, EA_LITERAL_STORE_ADATA(def, flags, data, len)); }
+/*
+ * Common route attributes
+ */
+
+/* Preference: first-order comparison */
+extern struct ea_class ea_gen_preference;
+static inline u32 rt_get_preference(rte *rt)
+{ return ea_get_int(rt->attrs->eattrs, &ea_gen_preference, 0); }
+
+/* IGP metric: second-order comparison */
+extern struct ea_class ea_gen_igp_metric;
+u32 rt_get_igp_metric(rte *rt);
+#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other
+ protocol-specific metric is availabe */
+
+
+/* Next hop structures */
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
void rta_dump_all(void);
void rta_show(struct cli *, rta *);
-u32 rt_get_igp_metric(rte *rt);
-
#endif
.type = T_INT,
};
+struct ea_class ea_gen_preference = {
+ .name = "preference",
+ .type = T_INT,
+};
+
const char * const rta_src_names[RTS_MAX] = {
[RTS_STATIC] = "static",
[RTS_INHERIT] = "inherit",
BMIX(source);
BMIX(scope);
BMIX(dest);
- MIX(pref);
#undef MIX
return mem_hash_value(&h) ^ nexthop_hash(&(a->nh)) ^ ea_hash(a->eattrs);
"RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
- debug("pref=%d uc=%d %s %s%s h=%04x",
- a->pref, a->uc, rts[a->source], ip_scope_text(a->scope),
+ debug("uc=%d %s %s%s h=%04x",
+ a->uc, rts[a->source], ip_scope_text(a->scope),
rtd[a->dest], a->hash_key);
if (!a->cached)
debug(" !CACHED");
rte_src_init();
ea_class_init();
+ ea_register_init(&ea_gen_preference);
ea_register_init(&ea_gen_igp_metric);
}
struct rte_src *src = rt_get_source(P, ad->iface->index);
rta a0 = {
- .pref = c->preference,
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh.iface = ad->iface,
};
+ ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, c->preference);
+
a = rta_lookup(&a0);
e = rte_get_temp(a, src);
e->pflags = 0;
if (get_route_info)
get_route_info(e, info);
else
- bsprintf(info, " (%d)", a->pref);
+ bsprintf(info, " (%d)", rt_get_preference(e));
if (d->last_table != d->tab)
rt_show_table(c, d);
if (!rte_is_valid(new))
return 0;
- if (new->attrs->pref > old->attrs->pref)
+ u32 np = rt_get_preference(new);
+ u32 op = rt_get_preference(old);
+
+ if (np > op)
return 1;
- if (new->attrs->pref < old->attrs->pref)
+ if (np < op)
return 0;
if (new->src->proto->proto != old->src->proto->proto)
{
if (!rte_is_valid(pri) || !rte_is_valid(sec))
return 0;
- if (pri->attrs->pref != sec->attrs->pref)
+ if (rt_get_preference(pri) != rt_get_preference(sec))
return 0;
if (pri->src->proto->proto != sec->src->proto->proto)
#define DEF_PREF_BGP 100 /* BGP */
#define DEF_PREF_RPKI 100 /* RPKI */
#define DEF_PREF_INHERITED 10 /* Routes inherited from other routing daemons */
+#define DEF_PREF_UNKNOWN 0 /* Routes with no preference set */
/*
* Route Origin Authorization
{
struct {
ea_list l;
- eattr a[3];
+ eattr a[4];
} eattrs = {
- .l.count = 3,
+ .l.count = ARRAY_SIZE(eattrs.a),
.a = {
+ EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, c->preference),
EA_LITERAL_EMBEDDED(&ea_babel_metric, 0, r->metric),
EA_LITERAL_STORE_ADATA(&ea_babel_router_id, 0, &r->router_id, sizeof(r->router_id)),
EA_LITERAL_EMBEDDED(&ea_babel_seqno, 0, r->seqno),
.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,
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNREACHABLE,
- .pref = 1,
};
+ ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1);
+
rta *a = rta_lookup(&a0);
rte *rte = rte_get_temp(a, p->p.main_source);
rte->pflags = 0;
if (e)
memcpy(&rid, e->u.ptr->data, sizeof(u64));
- buf += bsprintf(buf, " (%d/%d) [%lR]", rte->attrs->pref,
+ buf += bsprintf(buf, " (%d/%d) [%lR]",
+ rt_get_preference(rte),
ea_get_int(rte->attrs->eattrs, &ea_babel_metric, BABEL_INFINITY), rid);
}
static inline int
same_group(rte *r, u32 lpref, u32 lasn)
{
- return (r->attrs->pref == lpref) && (bgp_get_neighbor(r) == lasn);
+ return (rt_get_preference(r) == lpref) && (bgp_get_neighbor(r) == lasn);
}
static inline int
{
rte *r, *s;
rte *key = new ? new : old;
- u32 lpref = key->attrs->pref;
+ u32 lpref = rt_get_preference(key);
u32 lasn = bgp_get_neighbor(key);
int old_suppressed = old ? !!(old->pflags & BGP_REF_SUPPRESSED) : 0;
eattr *o = ea_find(e->attrs->eattrs, BGP_EA_ID(BA_ORIGIN));
u32 origas;
- buf += bsprintf(buf, " (%d", e->attrs->pref);
+ buf += bsprintf(buf, " (%d", rt_get_preference(e));
if (e->pflags & BGP_REF_SUPPRESSED)
buf += bsprintf(buf, "-");
a->scope = SCOPE_UNIVERSE;
a->from = s->proto->remote_ip;
a->eattrs = ea;
- a->pref = c->c.preference;
+ ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, c->c.preference);
c->desc->decode_next_hop(s, nh, nh_len, a);
bgp_finish_attrs(s, a);
}
buf += bsprintf(buf, " %s", type);
- buf += bsprintf(buf, " (%d/%d", rte->attrs->pref, ea_get_int(rte->attrs->eattrs, &ea_ospf_metric1, LSINFINITY));
+ buf += bsprintf(buf, " (%d/%d", rt_get_preference(rte), ea_get_int(rte->attrs->eattrs, &ea_ospf_metric1, LSINFINITY));
if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, &ea_ospf_metric2, LSINFINITY));
buf += bsprintf(buf, ")");
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh = *(nf->n.nhs),
- .pref = p->p.main_channel->preference,
};
if (reload || ort_changed(nf, &a0))
struct {
ea_list l;
- eattr a[4];
+ eattr a[5];
} eattrs;
eattrs.l = (ea_list) {};
+ eattrs.a[eattrs.l.count++] =
+ EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference);
+
eattrs.a[eattrs.l.count++] =
EA_LITERAL_EMBEDDED(&ea_ospf_metric1, 0, nf->n.metric1);
.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,
};
+ ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
+
p->data[i].a = rta_lookup(&a0);
}
else
{
/* Update */
rta a0 = {
- .pref = p->p.main_channel->preference,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
struct {
ea_list l;
- eattr a[3];
+ eattr a[4];
struct rip_iface_adata riad;
} ea_block = {
- .l.count = 3,
+ .l.count = ARRAY_SIZE(ea_block.a),
.a = {
+ EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference),
EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt_metric),
EA_LITERAL_EMBEDDED(&ea_rip_tag, 0, rt_tag),
EA_LITERAL_DIRECT_ADATA(&ea_rip_from, 0, &ea_block.riad.ad),
u32 rt_metric = ea_get_int(rte->attrs->eattrs, &ea_rip_metric, p->infinity);
u32 rt_tag = ea_get_int(rte->attrs->eattrs, &ea_rip_tag, 0);
- buf += bsprintf(buf, " (%d/%d)", rte->attrs->pref, rt_metric);
+ buf += bsprintf(buf, " (%d/%d)", rt_get_preference(rte), rt_metric);
if (rt_tag)
bsprintf(buf, " [%04x]", rt_tag);
struct rpki_proto *p = cache->p;
rta a0 = {
- .pref = channel->preference,
.source = RTS_RPKI,
.scope = SCOPE_UNIVERSE,
.dest = RTD_NONE,
};
+ ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference);
+
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a, p->p.main_source);
a->source = RTS_STATIC;
a->scope = SCOPE_UNIVERSE;
a->dest = r->dest;
- a->pref = p->p.main_channel->preference;
+ ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
if (r->dest == RTD_UNICAST)
{
static_get_route_info(rte *rte, byte *buf)
{
eattr *a = ea_find(rte->attrs->eattrs, &ea_gen_igp_metric);
+ u32 pref = rt_get_preference(rte);
if (a)
- buf += bsprintf(buf, " (%d/%u)", rte->attrs->pref, a->u.data);
+ buf += bsprintf(buf, " (%d/%u)", pref, a->u.data);
else
- buf += bsprintf(buf, " (%d)", rte->attrs->pref);
+ buf += bsprintf(buf, " (%d)", pref);
}
static void
rte *g, **gg, *best, **bestp, *old_best;
ASSERT(!e->attrs->cached);
- e->attrs->pref = p->p.main_channel->preference;
+ ea_set_attr_u32(&e->attrs->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
e->attrs = rta_lookup(e->attrs);