summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}
/*