summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2022-05-15 18:09:30 +0200
committerMaria Matejka <mq@ucw.cz>2022-05-30 14:39:09 +0200
commit950775f6fa3d569a9d7cd05e33538d35e895d688 (patch)
tree81b4b23d5695e209301b252d0d282b05a0d67ac1
parent4fe9881d625f10e44109a649e369a413bd98de71 (diff)
Route destination field merged with nexthop attribute; splitting flowspec validation result out.
As there is either a nexthop or another destination specification (or othing in case of ROAs and Flowspec), it may be merged together. This code is somehow quirky and should be replaced in future by better implementation of nexthop. Also flowspec validation result has its own attribute now as it doesn't have anything to do with route nexthop.
-rw-r--r--filter/f-inst.c79
-rw-r--r--lib/route.h60
-rw-r--r--lib/type.h1
-rw-r--r--nest/config.Y2
-rw-r--r--nest/rt-attr.c24
-rw-r--r--nest/rt-dev.c5
-rw-r--r--nest/rt-show.c5
-rw-r--r--nest/rt-table.c92
-rw-r--r--nest/rt.h1
-rw-r--r--proto/babel/babel.c18
-rw-r--r--proto/bgp/attrs.c17
-rw-r--r--proto/bgp/bgp.h4
-rw-r--r--proto/bgp/packets.c25
-rw-r--r--proto/ospf/rt.c4
-rw-r--r--proto/ospf/topology.c11
-rw-r--r--proto/perf/perf.c4
-rw-r--r--proto/rip/rip.c4
-rw-r--r--proto/rpki/rpki.c4
-rw-r--r--proto/static/static.c6
-rw-r--r--sysdep/linux/netlink.c78
-rw-r--r--sysdep/unix/krt.c9
21 files changed, 245 insertions, 208 deletions
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 8ce78a99..c2abd5aa 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -530,20 +530,24 @@
STATIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
- struct rta *rta = (*fs->rte)->attrs;
switch (sa.sa_code)
{
case SA_NET: RESULT(sa.type, net, (*fs->rte)->net->n.addr); break;
case SA_PROTO: RESULT(sa.type, s, (*fs->rte)->src->proto->name); break;
- case SA_DEST: RESULT(sa.type, i, rta->dest); break;
default:
{
- struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
- struct nexthop *nh = nh_ea ? &((struct nexthop_adata *) nh_ea->u.ptr)->nh : NULL;
+ struct eattr *nhea = ea_find(*fs->eattrs, &ea_gen_nexthop);
+ struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+ struct nexthop *nh = nhad ? &nhad->nh : NULL;
switch (sa.sa_code)
{
+ case SA_DEST:
+ RESULT(sa.type, i, nhad ?
+ (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest)
+ : RTD_NONE);
+ break;
case SA_GW:
RESULT(sa.type, ip, nh ? nh->gw : IPA_NONE);
break;
@@ -576,36 +580,33 @@
f_rta_cow(fs);
{
- struct rta *rta = (*fs->rte)->attrs;
+ union {
+ struct nexthop_adata nha;
+ struct {
+ struct adata ad;
+ struct nexthop nh;
+ u32 label;
+ };
+ } nha;
+
+ nha.ad = (struct adata) {
+ .length = sizeof (struct nexthop_adata) - sizeof (struct adata),
+ };
- if (sa.sa_code == SA_DEST)
+ eattr *a = NULL;
+
+ switch (sa.sa_code)
+ {
+ case SA_DEST:
{
int i = v1.val.i;
if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
- rta->dest = i;
- ea_unset_attr(fs->eattrs, 1, &ea_gen_nexthop);
+ nha.nha.dest = i;
+ nha.ad.length = NEXTHOP_DEST_SIZE;
+ break;
}
- else
- {
- union {
- struct nexthop_adata nha;
- struct {
- struct adata ad;
- struct nexthop nh;
- u32 label;
- };
- } nha;
-
- nha.ad = (struct adata) {
- .length = sizeof (struct nexthop_adata) - sizeof (struct adata),
- };
-
- eattr *a = NULL;
-
- switch (sa.sa_code)
- {
case SA_GW:
{
struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
@@ -618,7 +619,6 @@
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
- rta->dest = RTD_UNICAST;
nha.nh = (struct nexthop) {
.gw = ip,
.iface = n->iface,
@@ -632,7 +632,6 @@
if (!ifa)
runtime( "Invalid iface name" );
- rta->dest = RTD_UNICAST;
nha.nh = (struct nexthop) {
.iface = ifa,
};
@@ -666,15 +665,16 @@
int i = v1.val.i;
if (i < 1 || i > 256)
runtime( "Setting weight value out of bounds" );
- if (rta->dest != RTD_UNICAST)
- runtime( "Setting weight needs regular nexthop " );
struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
if (!nh_ea)
runtime( "No nexthop to set weight on" );
- struct nexthop_adata *nhax = (struct nexthop_adata *)
- tmp_copy_adata(&((struct nexthop_adata *) nh_ea->u.ptr)->ad);
+ struct nexthop_adata *nhad = (struct nexthop_adata *) nh_ea->u.ptr;
+ if (!NEXTHOP_IS_REACHABLE(nhad))
+ runtime( "Setting weight needs regular nexthop " );
+
+ struct nexthop_adata *nhax = (struct nexthop_adata *) tmp_copy_adata(&nhad->ad);
/* Set weight on all next hops */
NEXTHOP_WALK(nh, nhax)
@@ -687,15 +687,14 @@
default:
bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code);
- }
+ }
- if (!a)
- a = ea_set_attr(fs->eattrs,
- EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
+ if (!a)
+ a = ea_set_attr(fs->eattrs,
+ EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
- a->originated = 1;
- a->fresh = 1;
- }
+ a->originated = 1;
+ a->fresh = 1;
}
}
diff --git a/lib/route.h b/lib/route.h
index 3ce8021d..1d8877c8 100644
--- a/lib/route.h
+++ b/lib/route.h
@@ -76,9 +76,17 @@ struct nexthop {
/* For packing one into eattrs */
struct nexthop_adata {
struct adata ad;
- struct nexthop nh;
+ /* There is either a set of nexthops or a special destination (RTD_*) */
+ union {
+ struct nexthop nh;
+ uint dest;
+ };
};
+#define NEXTHOP_DEST_SIZE (OFFSETOF(struct nexthop_adata, dest) + sizeof(uint) - OFFSETOF(struct adata, data))
+#define NEXTHOP_DEST_LITERAL(x) ((struct nexthop_adata) { \
+ .ad.length = NEXTHOP_DEST_SIZE, .dest = (x), })
+
#define RNF_ONLINK 0x1 /* Gateway is onlink regardless of IP ranges */
@@ -88,7 +96,6 @@ typedef struct rta {
u32 hash_key; /* Hash over important fields */
struct ea_list *eattrs; /* Extended Attribute chain */
u16 cached:1; /* Are attributes cached? */
- u16 dest:4; /* Route destination type (RTD_...) */
} rta;
#define RTS_STATIC 1 /* Normal static route */
@@ -109,7 +116,7 @@ typedef struct rta {
#define RTS_MAX 16
#define RTD_NONE 0 /* Undefined next hop */
-#define RTD_UNICAST 1 /* Next hop is neighbor router */
+#define RTD_UNICAST 1 /* A standard next hop */
#define RTD_BLACKHOLE 2 /* Silently drop packets */
#define RTD_UNREACHABLE 3 /* Reject as unreachable */
#define RTD_PROHIBIT 4 /* Administratively prohibited */
@@ -120,10 +127,6 @@ extern const char * rta_dest_names[RTD_MAX];
static inline const char *rta_dest_name(uint n)
{ return (n < RTD_MAX) ? rta_dest_names[n] : "???"; }
-/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
-static inline int rte_is_reachable(rte *r)
-{ return r->attrs->dest == RTD_UNICAST; }
-
/*
* Extended Route Attributes
@@ -331,9 +334,24 @@ extern struct ea_class ea_gen_source;
static inline u32 rt_get_source_attr(rte *rt)
{ return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); }
+/* Flowspec validation result */
+#define FLOWSPEC_UNKNOWN 0
+#define FLOWSPEC_VALID 1
+#define FLOWSPEC_INVALID 2
+
+extern struct ea_class ea_gen_flowspec_valid;
+static inline u32 rt_get_flowspec_valid(rte *rt)
+{ return ea_get_int(rt->attrs->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN); }
+
/* Next hop: For now, stored as adata */
extern struct ea_class ea_gen_nexthop;
+static inline void ea_set_dest(struct ea_list **to, uint flags, uint dest)
+{
+ struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(dest);
+ ea_set_attr_data(to, &ea_gen_nexthop, flags, &nhad.ad.data, nhad.ad.length);
+}
+
/* Next hop structures */
#define NEXTHOP_ALIGNMENT (_Alignof(struct nexthop))
@@ -359,7 +377,35 @@ struct nexthop_adata *nexthop_merge(struct nexthop_adata *x, struct nexthop_adat
struct nexthop_adata *nexthop_sort(struct nexthop_adata *x, linpool *lp);
int nexthop_is_sorted(struct nexthop_adata *x);
+#define NEXTHOP_IS_REACHABLE(nhad) ((nhad)->ad.length > NEXTHOP_DEST_SIZE)
+/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
+static inline int rte_is_reachable(rte *r)
+{
+ eattr *nhea = ea_find(r->attrs->eattrs, &ea_gen_nexthop);
+ if (!nhea)
+ return 0;
+
+ struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+ return NEXTHOP_IS_REACHABLE(nhad);
+}
+
+static inline int nhea_dest(eattr *nhea)
+{
+ if (!nhea)
+ return RTD_NONE;
+
+ struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+ if (NEXTHOP_IS_REACHABLE(nhad))
+ return RTD_UNICAST;
+ else
+ return nhad->dest;
+}
+
+static inline int rte_dest(rte *r)
+{
+ return nhea_dest(ea_find(r->attrs->eattrs, &ea_gen_nexthop));
+}
void rta_init(void);
#define rta_size(...) (sizeof(rta))
diff --git a/lib/type.h b/lib/type.h
index 65a032ec..b54744c1 100644
--- a/lib/type.h
+++ b/lib/type.h
@@ -66,6 +66,7 @@ enum btype {
T_ENUM_BGP_ORIGIN = 0x11, /* BGP Origin enum */
T_ENUM_RA_PREFERENCE = 0x13, /* RA Preference enum */
+ T_ENUM_FLOWSPEC_VALID = 0x15, /* Flowspec validation result */
#define EAF_TYPE__MAX 0x1f
#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */
diff --git a/nest/config.Y b/nest/config.Y
index c144f0f3..6a35cdd2 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -133,7 +133,7 @@ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4,
CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
-CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
+CF_ENUM(T_ENUM_RTD, RTD_, BLACKHOLE, UNREACHABLE, PROHIBIT)
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index cf3ab659..b5be936b 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -166,6 +166,12 @@ const char * rta_dest_names[RTD_MAX] = {
[RTD_PROHIBIT] = "prohibited",
};
+struct ea_class ea_gen_flowspec_valid = {
+ .name = "flowspec_valid",
+ .type = T_ENUM_FLOWSPEC_VALID,
+ .readonly = 1,
+};
+
pool *rta_pool;
static slab *rta_slab;
@@ -1246,20 +1252,13 @@ rta_alloc_hash(void)
static inline uint
rta_hash(rta *a)
{
- u64 h;
- mem_hash_init(&h);
-#define BMIX(f) mem_hash_mix_num(&h, a->f);
- BMIX(dest);
-#undef MIX
-
- return mem_hash_value(&h) ^ ea_hash(a->eattrs);
+ return ea_hash(a->eattrs);
}
static inline int
rta_same(rta *x, rta *y)
{
- return (x->dest == y->dest &&
- ea_same(x->eattrs, y->eattrs));
+ return ea_same(x->eattrs, y->eattrs);
}
static rta *
@@ -1382,10 +1381,8 @@ rta_do_cow(rta *o, linpool *lp)
void
rta_dump(rta *a)
{
- static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
-
- debug("uc=%d %s h=%04x",
- a->uc, rtd[a->dest], a->hash_key);
+ debug("uc=%d h=%04x",
+ a->uc, a->hash_key);
if (!a->cached)
debug(" !CACHED");
if (a->eattrs)
@@ -1449,6 +1446,7 @@ rta_init(void)
ea_register_init(&ea_gen_source);
ea_register_init(&ea_gen_nexthop);
ea_register_init(&ea_gen_hostentry);
+ ea_register_init(&ea_gen_flowspec_valid);
}
/*
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 9953e270..c50e018c 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -82,10 +82,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
/* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(P, ad->iface->index);
- rta a0 = {
- .dest = RTD_UNICAST,
- };
-
+ rta a0 = {};
struct nexthop_adata nhad = {
.nh = { .iface = ad->iface, },
.ad = { .length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data, },
diff --git a/nest/rt-show.c b/nest/rt-show.c
index 32f7aa2d..0ad8f5c6 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -47,6 +47,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
void (*get_route_info)(struct rte *, byte *buf);
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+ int dest = NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest;
tm_format_time(tm, &config->tf_route, e->lastmod);
ip_addr a_from = ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE);
@@ -68,10 +69,10 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
if (d->last_table != d->tab)
rt_show_table(c, d);
- cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
+ cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(dest),
e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
- if (a->dest == RTD_UNICAST)
+ if (dest == RTD_UNICAST)
NEXTHOP_WALK(nh, nhad)
{
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index d98f33e4..539e04d0 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -699,7 +699,7 @@ rte_trace(struct channel *c, rte *e, int dir, char *msg)
{
log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id,
- rta_dest_name(e->attrs->dest));
+ rta_dest_name(rte_dest(e)));
}
static inline void
@@ -1177,26 +1177,17 @@ rte_validate(rte *e)
return 0;
}
- if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
- {
- /* Exception for flowspec that failed validation */
- if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE))
- return 1;
-
- log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
- n->n.addr, e->attrs->dest, e->sender->proto->name);
- return 0;
- }
-
eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
- if ((!nhea) != (e->attrs->dest != RTD_UNICAST))
+ int dest = nhea_dest(nhea);
+
+ if (net_type_match(n->n.addr, NB_DEST) == !dest)
{
- log(L_WARN "Ignoring route %N with destination %d and %snexthop received via %s",
- n->n.addr, e->attrs->dest, (nhea ? "" : "no "), e->sender->proto->name);
+ log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
+ n->n.addr, dest, e->sender->proto->name);
return 0;
}
- if ((e->attrs->dest == RTD_UNICAST) &&
+ if ((dest == RTD_UNICAST) &&
!nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
{
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
@@ -2431,26 +2422,27 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
u32 *labels = head->labels;
u32 lnum = (u32 *) (head->ad.data + head->ad.length) - labels;
- a->dest = he->dest;
-
ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, he->igp_metric);
- if (a->dest != RTD_UNICAST)
+ if (!he->src)
{
- /* No nexthop */
- ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+ ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
return;
}
- if (!lnum && he->nexthop_linkable)
+ eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
+ ASSERT_DIE(he_nh_ea);
+
+ struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
+ int idest = nhea_dest(he_nh_ea);
+
+ if ((idest != RTD_UNICAST) ||
+ !lnum && he->nexthop_linkable)
{ /* Just link the nexthop chain, no label append happens. */
ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
return;
}
- eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
- struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
-
uint total_size = OFFSETOF(struct nexthop_adata, nh);
NEXTHOP_WALK(nh, nhad)
@@ -2467,10 +2459,14 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
if (total_size == OFFSETOF(struct nexthop_adata, nh))
{
- a->dest = RTD_UNREACHABLE;
log(L_WARN "No valid nexthop remaining, setting route unreachable");
- ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+ struct nexthop_adata nha = {
+ .ad.length = NEXTHOP_DEST_SIZE,
+ .dest = RTD_UNREACHABLE,
+ };
+
+ ea_set_attr_data(&a->eattrs, &ea_gen_nexthop, 0, &nha.ad.data, nha.ad.length);
return;
}
@@ -2511,19 +2507,28 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
static inline struct hostentry_adata *
rta_next_hop_outdated(rta *a)
{
+ /* First retrieve the hostentry */
eattr *heea = ea_find(a->eattrs, &ea_gen_hostentry);
if (!heea)
return NULL;
struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr;
+ /* If no nexthop is present, we have to create one */
+ eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
+ if (!a_nh_ea)
+ return head;
+
+ struct nexthop_adata *nhad = (struct nexthop_adata *) a_nh_ea->u.ptr;
+
+ /* Shortcut for unresolvable hostentry */
if (!head->he->src)
- return (a->dest != RTD_UNREACHABLE) ? head : NULL;
+ return NEXTHOP_IS_REACHABLE(nhad) ? head : NULL;
+ /* Comparing our nexthop with the hostentry nexthop */
eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
- eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
- return ((a->dest != head->he->dest) ||
+ return (
(ea_get_int(a->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN) != head->he->igp_metric) ||
(!head->he->nexthop_linkable) ||
(!he_nh_ea != !a_nh_ea) ||
@@ -2682,16 +2687,16 @@ rt_flowspec_update_rte(rtable *tab, rte *r)
const net_addr *n = r->net->n.addr;
struct bgp_proto *p = (void *) r->src->proto;
int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
- int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
-
- if (dest == r->attrs->dest)
+ int old = rt_get_flowspec_valid(r);
+ if (old == valid)
return NULL;
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, r->attrs, rta_size(r->attrs));
- a->dest = dest;
a->cached = 0;
+ ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
+
rte *new = sl_alloc(rte_slab);
memcpy(new, r, sizeof(rte));
new->attrs = rta_lookup(a);
@@ -3524,7 +3529,6 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
/* Reset the hostentry */
he->src = NULL;
- he->dest = RTD_UNREACHABLE;
he->nexthop_linkable = 0;
he->igp_metric = 0;
@@ -3545,16 +3549,12 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
goto done;
}
- if (a->dest == RTD_UNICAST)
- {
- eattr *ea = ea_find(a->eattrs, &ea_gen_nexthop);
- if (!ea)
- {
- log(L_WARN "No nexthop in unicast route");
- goto done;
- }
-
- NEXTHOP_WALK(nh, (struct nexthop_adata *) ea->u.ptr)
+ eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
+ ASSERT_DIE(nhea);
+ struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+
+ if (NEXTHOP_IS_REACHABLE(nhad))
+ NEXTHOP_WALK(nh, nhad)
if (ipa_zero(nh->gw))
{
if (if_local_addr(he->addr, nh->iface))
@@ -3567,10 +3567,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
direct++;
}
- }
he->src = rta_clone(a);
- he->dest = a->dest;
he->nexthop_linkable = !direct;
he->igp_metric = rt_get_igp_metric(e);
}
diff --git a/nest/rt.h b/nest/rt.h
index eb3f8454..6f15fec6 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -144,7 +144,6 @@ struct hostentry {
unsigned hash_key; /* Hash key */
unsigned uc; /* Use count */
struct rta *src; /* Source rta entry */
- byte dest; /* Chosen route destination type (RTD_...) */
byte nexthop_linkable; /* Nexthop list is completely non-device */
u32 igp_metric; /* Chosen route IGP metric */
};
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 9a43f484..b90dcd3f 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -677,10 +677,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
}
};
- rta a0 = {
- .dest = RTD_UNICAST,
- .eattrs = &eattrs.l,
- };
+ rta a0 = { .eattrs = &eattrs.l, };
rta *a = rta_lookup(&a0);
rte *rte = rte_get_temp(a, p->p.main_source);
@@ -691,12 +688,11 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
else if (e->valid && (e->router_id != p->router_id))
{
/* Unreachable */
- rta a0 = {
- .dest = RTD_UNREACHABLE,
- };
+ rta a0 = {};
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1);
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_BABEL);
+ ea_set_dest(&a0.eattrs, 0, RTD_UNREACHABLE);
rta *a = rta_lookup(&a0);
rte *rte = rte_get_temp(a, p->p.main_source);
@@ -2263,9 +2259,13 @@ babel_kick_timer(struct babel_proto *p)
static int
babel_preexport(struct proto *P, struct rte *new)
{
- struct rta *a = new->attrs;
+ if (new->src->proto != P)
+ return 0;
+
/* Reject our own unreachable routes */
- if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
+ eattr *ea = ea_find(new->attrs->eattrs, &ea_gen_nexthop);
+ struct nexthop_adata *nhad = (void *) ea->u.ptr;
+ if (!NEXTHOP_IS_REACHABLE(nhad))
return -1;
return 0;
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 1efc26ce..6a9e4026 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1711,9 +1711,20 @@ bgp_preexport(struct proto *P, rte *e)
if (src == NULL)
return 0;
- /* Reject flowspec that failed validation */
- if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
- return -1;
+ /* Reject flowspec that failed or are pending validation */
+ if (net_is_flow(e->net->n.addr))
+ switch (rt_get_flowspec_valid(e))
+ {
+ case FLOWSPEC_VALID:
+ break;
+ case FLOWSPEC_INVALID:
+ return -1;
+ case FLOWSPEC_UNKNOWN:
+ if ((rt_get_source_attr(e) == RTS_BGP) &&
+ ((struct bgp_channel *) e->sender)->base_table)
+ return -1;
+ break;
+ }
/* IBGP route reflection, RFC 4456 */
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 6abb7870..2f98dc1b 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -519,7 +519,9 @@ struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
static inline int
rte_resolvable(rte *rt)
{
- return rt->attrs->dest != RTD_UNREACHABLE;
+ eattr *nhea = ea_find(rt->attrs->eattrs, &ea_gen_nexthop);
+ struct nexthop_adata *nhad = (void *) nhea->u.ptr;
+ return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE);
}
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index b07320aa..4c46c60e 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -968,7 +968,6 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, c->cf->cost);
- a->dest = RTD_UNICAST;
struct nexthop_adata nhad = {
.nh = {
.gw = nbr->addr,
@@ -1003,8 +1002,7 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 lnum, u32 labels[ln
{
REPORT("Too many MPLS labels ($u)", lnum);
- a->dest = RTD_UNREACHABLE;
- ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
+ ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
return;
}
@@ -1039,15 +1037,21 @@ static void
bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
{
struct bgp_channel *c = s->channel;
- int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
- a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+ uint valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
- /* Invalidate cached rta if dest changes */
- if (s->cached_rta && (s->cached_rta->dest != a->dest))
+ /* Invalidate cached rta */
+ if (s->cached_rta)
{
+ /* Has't changed */
+ if (valid == ea_get_int(s->cached_rta->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN))
+ return;
+
rta_free(s->cached_rta);
s->cached_rta = NULL;
}
+
+ /* Set the value */
+ ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
}
static int
@@ -1107,17 +1111,14 @@ bgp_use_gateway(struct bgp_export_state *s)
if (c->cf->next_hop_self && bgp_match_src(s, c->cf->next_hop_self))
return NULL;
- /* Unreachable */
- if (ra->dest != RTD_UNICAST)
- return NULL;
-
eattr *nhea = ea_find(ra->eattrs, &ea_gen_nexthop);
if (!nhea)
return NULL;
/* We need one valid global gateway */
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
- if (!NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
+ if (!NEXTHOP_IS_REACHABLE(nhad) ||
+ !NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
ipa_is_link_local(nhad->nh.gw))
return NULL;
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 6070fd34..afe4a01f 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1983,8 +1983,7 @@ ort_changed(ort *nf, rta *nr)
if (!or ||
(nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
- (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
- (nr->dest != or->dest))
+ (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid))
return 1;
eattr *nhea_n = ea_find(nr->eattrs, &ea_gen_nexthop);
@@ -2049,7 +2048,6 @@ again1:
if (nf->n.type) /* Add the route */
{
rta a0 = {
- .dest = RTD_UNICAST,
};
struct {
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index ca4620cc..09ec9f28 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1366,16 +1366,9 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0);
ip_addr fwd = IPA_NONE;
- if (a->dest == RTD_UNICAST)
+ eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
+ if (nhea)
{
- eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
- if (!nhea)
- {
- log(L_ERR "%s: Unicast route without nexthop for %N",
- p->p.name, n->n.addr);
- return;
- }
-
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface))
fwd = nhad->nh.gw;
diff --git a/proto/perf/perf.c b/proto/perf/perf.c
index 8642e0a1..d1ff6adf 100644
--- a/proto/perf/perf.c
+++ b/proto/perf/perf.c
@@ -142,9 +142,7 @@ perf_loop(void *data)
*((net_addr_ip4 *) &(p->data[i].net)) = random_net_ip4();
if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
- struct rta a0 = {
- .dest = RTD_UNICAST,
- };
+ struct rta a0 = {};
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_PERF);
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 425a411c..a0f2fdc0 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -151,9 +151,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt)
{
/* Update */
- rta a0 = {
- .dest = RTD_UNICAST,
- };
+ rta a0 = {};
struct {
ea_list l;
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index 56d8add2..4318cbb7 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -120,9 +120,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
{
struct rpki_proto *p = cache->p;
- rta a0 = {
- .dest = RTD_NONE,
- };
+ rta a0 = {};
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference);
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_RPKI);
diff --git a/proto/static/static.c b/proto/static/static.c
index 5102617f..806849c4 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -55,7 +55,6 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
{
rta *a = allocz(RTA_MAX_SIZE);
struct rte_src *src = static_get_source(p, r->index);
- a->dest = r->dest;
ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_STATIC);
@@ -97,7 +96,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
nhad->ad.data, (void *) nh - (void *) nhad->ad.data);
}
- if (r->dest == RTDX_RECURSIVE)
+ else if (r->dest == RTDX_RECURSIVE)
{
rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6;
u32 *labels = r->mls ? (void *) r->mls->data : NULL;
@@ -107,6 +106,9 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
r->via, IPA_NONE, lnum, labels);
}
+ else if (r->dest)
+ ea_set_dest(&a->eattrs, 0, r->dest);
+
/* Already announced */
if (r->state == SRS_CLEAN)
return;
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index fdfd4885..40f6212e 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -1407,11 +1407,16 @@ HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
int
krt_capable(rte *e)
{
- rta *a = e->attrs;
+ eattr *ea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
+ if (!ea)
+ return 0;
+
+ struct nexthop_adata *nhad = (void *) ea->u.ptr;
+ if (NEXTHOP_IS_REACHABLE(nhad))
+ return 1;
- switch (a->dest)
+ switch (nhad->dest)
{
- case RTD_UNICAST:
case RTD_BLACKHOLE:
case RTD_UNREACHABLE:
case RTD_PROHIBIT:
@@ -1591,7 +1596,7 @@ nl_add_rte(struct krt_proto *p, rte *e)
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
- if (krt_ecmp6(p) && nhad && !NEXTHOP_ONE(nhad))
+ if (krt_ecmp6(p) && nhad && NEXTHOP_IS_REACHABLE(nhad) && !NEXTHOP_ONE(nhad))
{
uint cnt = 0;
NEXTHOP_WALK(nh, nhad)
@@ -1616,7 +1621,8 @@ nl_add_rte(struct krt_proto *p, rte *e)
return err;
}
- return nl_send_route(p, e, NL_OP_ADD, a->dest, nhad);
+ return nl_send_route(p, e, NL_OP_ADD,
+ NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
}
static inline int
@@ -1638,7 +1644,8 @@ nl_replace_rte(struct krt_proto *p, rte *e)
rta *a = e->attrs;
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
- return nl_send_route(p, e, NL_OP_REPLACE, a->dest, nhad);
+ return nl_send_route(p, e, NL_OP_REPLACE,
+ NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
}
@@ -1901,8 +1908,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
switch (i->rtm_type)
{
case RTN_UNICAST:
- ra->dest = RTD_UNICAST;
-
if (a[RTA_MULTIPATH])
{
struct nexthop_adata *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
@@ -1953,15 +1958,40 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
}
}
+#ifdef HAVE_MPLS_KERNEL
+ if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
+ nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
+
+ if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
+ {
+ switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
+ {
+ case LWTUNNEL_ENCAP_MPLS:
+ {
+ struct rtattr *enca[BIRD_RTA_MAX];
+ nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
+ nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
+ nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
+ break;
+ }
+ default:
+ SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
+ break;
+ }
+ }
+#endif
+
+ /* Finalize the nexthop */
+ nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
break;
case RTN_BLACKHOLE:
- ra->dest = RTD_BLACKHOLE;
+ nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_BLACKHOLE);
break;
case RTN_UNREACHABLE:
- ra->dest = RTD_UNREACHABLE;
+ nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_UNREACHABLE);
break;
case RTN_PROHIBIT:
- ra->dest = RTD_PROHIBIT;
+ nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_PROHIBIT);
break;
/* FIXME: What about RTN_THROW? */
default:
@@ -1969,32 +1999,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return;
}
-#ifdef HAVE_MPLS_KERNEL
- if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
- nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
-
- if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
- {
- switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
- {
- case LWTUNNEL_ENCAP_MPLS:
- {
- struct rtattr *enca[BIRD_RTA_MAX];
- nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
- nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
- nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
- break;
- }
- default:
- SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
- break;
- }
- }
-#endif
-
- /* Finalize the nexthop */
- nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
-
if (i->rtm_scope != def_scope)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 89e9e97e..a0789936 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -608,17 +608,10 @@ krt_same_dest(rte *k, rte *e)
{
rta *ka = k->attrs, *ea = e->attrs;
- if (ka->dest != ea->dest)
- return 0;
-
- if (ka->dest != RTD_UNICAST)
- return 1;
-
eattr *nhea_k = ea_find(ka->eattrs, &ea_gen_nexthop);
eattr *nhea_e = ea_find(ea->eattrs, &ea_gen_nexthop);
- ASSUME(nhea_k && nhea_e);
- return adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
+ return (!nhea_k == !nhea_e) && adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
}
/*