summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2022-06-08 11:47:49 +0200
committerMaria Matejka <mq@ucw.cz>2022-06-08 11:47:49 +0200
commitcae5979871ee7aa341334f8b1af6bafc60ee9692 (patch)
tree490f68c9c5d856ab560f2194fe350cd68039cccd /nest
parent8fd3811d9d29d73570e03147eb024a4e5fde199b (diff)
parent950775f6fa3d569a9d7cd05e33538d35e895d688 (diff)
Merge commit '950775f6fa3d569a9d7cd05e33538d35e895d688' into haugesund
There were quite a lot of conflicts in flowspec validation code which ultimately led to some code being a bit rewritten, not only adapted from this or that branch, yet it is still in a limit of a merge.
Diffstat (limited to 'nest')
-rw-r--r--nest/config.Y2
-rw-r--r--nest/rt-attr.c30
-rw-r--r--nest/rt-dev.c5
-rw-r--r--nest/rt-show.c12
-rw-r--r--nest/rt-table.c159
-rw-r--r--nest/rt.h4
6 files changed, 115 insertions, 97 deletions
diff --git a/nest/config.Y b/nest/config.Y
index 068a1d30..7c68a09a 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..f548a575 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -166,6 +166,18 @@ 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,
+};
+
+const char * flowspec_valid_names[FLOWSPEC__MAX] = {
+ [FLOWSPEC_UNKNOWN] = "unknown",
+ [FLOWSPEC_VALID] = "",
+ [FLOWSPEC_INVALID] = "invalid",
+};
+
pool *rta_pool;
static slab *rta_slab;
@@ -1246,20 +1258,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 +1387,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 +1452,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 107f67a7..fa224f9a 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -79,10 +79,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 6cfd99fc..cc5a9a10 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -45,8 +45,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
rta *a = e->attrs;
int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0;
void (*get_route_info)(struct rte *, byte *buf);
- eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
+ eattr *nhea = net_type_match(e->net, NB_DEST) ?
+ ea_find(a->eattrs, &ea_gen_nexthop) : NULL;
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
+ int dest = nhad ? (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest) : RTD_NONE;
+ int flowspec_valid = net_is_flow(e->net) ? rt_get_flowspec_valid(e) : FLOWSPEC_UNKNOWN;
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 +71,11 @@ 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),
- e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
+ cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia,
+ net_is_flow(e->net) ? flowspec_valid_name(flowspec_valid) : 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 491ae1d9..946f4021 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -683,7 +683,7 @@ rte_trace(const char *name, const rte *e, int dir, const char *msg)
{
log(L_TRACE "%s %c %s %N %uL %uG %s",
name, dir, msg, e->net, e->src->private_id, e->src->global_id,
- rta_dest_name(e->attrs->dest));
+ rta_dest_name(rte_dest(e)));
}
static inline void
@@ -1226,29 +1226,29 @@ rte_validate(struct channel *ch, rte *e)
return 0;
}
- if (net_type_match(n, NB_DEST) == !e->attrs->dest)
+ if (net_type_match(n, NB_DEST))
{
- /* Exception for flowspec that failed validation */
- if (net_is_flow(n) && (e->attrs->dest == RTD_UNREACHABLE))
- return 1;
+ eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
+ int dest = nhea_dest(nhea);
- log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
- n, e->attrs->dest, ch->proto->name);
- return 0;
- }
+ if (dest == RTD_NONE)
+ {
+ log(L_WARN "Ignoring route %N with no destination received via %s",
+ n, ch->proto->name);
+ return 0;
+ }
- eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
- if ((!nhea) != (e->attrs->dest != RTD_UNICAST))
- {
- log(L_WARN "Ignoring route %N with destination %d and %snexthop received via %s",
- n, e->attrs->dest, (nhea ? "" : "no "), ch->proto->name);
- return 0;
+ if ((dest == RTD_UNICAST) &&
+ !nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
+ {
+ log(L_WARN "Ignoring unsorted multipath route %N received via %s",
+ n, ch->proto->name);
+ return 0;
+ }
}
-
- if ((e->attrs->dest == RTD_UNICAST) &&
- !nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
+ else if (ea_find(e->attrs->eattrs, &ea_gen_nexthop))
{
- log(L_WARN "Ignoring unsorted multipath route %N received via %s",
+ log(L_WARN "Ignoring route %N having a nexthop attribute received via %s",
n, ch->proto->name);
return 0;
}
@@ -2547,26 +2547,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)
@@ -2583,10 +2584,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;
}
@@ -2627,19 +2632,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) ||
@@ -2722,7 +2736,7 @@ rta_get_first_asn(rta *a)
return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0;
}
-int
+static inline enum flowspec_valid
rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior)
{
ASSERT(rt_is_ip(tab_ip));
@@ -2731,11 +2745,11 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
/* RFC 8955 6. a) Flowspec has defined dst prefix */
if (!net_flow_has_dst_prefix(n))
- return 0;
+ return FLOWSPEC_INVALID;
/* RFC 9117 4.1. Accept AS_PATH is empty (fr */
if (interior && rta_as_path_is_empty(a))
- return 1;
+ return FLOWSPEC_VALID;
/* RFC 8955 6. b) Flowspec and its best-match route have the same originator */
@@ -2757,7 +2771,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
/* No best-match BGP route -> no flowspec */
if (!rb || (rt_get_source_attr(rb) != RTS_BGP))
- return 0;
+ return FLOWSPEC_INVALID;
/* Find ORIGINATOR_ID values */
u32 orig_a = ea_get_int(a->eattrs, "bgp_originator_id", 0);
@@ -2768,17 +2782,17 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE),
ea_get_ip(rb->attrs->eattrs, &ea_gen_from, IPA_NONE)
)))
- return 0;
+ return FLOWSPEC_INVALID;
/* Find ASN of the best-match route, for use in next checks */
u32 asn_b = rta_get_first_asn(rb->attrs);
if (!asn_b)
- return 0;
+ return FLOWSPEC_INVALID;
/* RFC 9117 4.2. For EBGP, flowspec and its best-match route are from the same AS */
if (!interior && (rta_get_first_asn(a) != asn_b))
- return 0;
+ return FLOWSPEC_INVALID;
/* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
TRIE_WALK(tab_ip->trie, subnet, &dst)
@@ -2789,14 +2803,14 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
const rte *rc = &nc->routes->rte;
if (rt_get_source_attr(rc) != RTS_BGP)
- return 0;
+ return FLOWSPEC_INVALID;
if (rta_get_first_asn(rc->attrs) != asn_b)
- return 0;
+ return FLOWSPEC_INVALID;
}
TRIE_WALK_END;
- return 1;
+ return FLOWSPEC_VALID;
}
#endif /* CONFIG_BGP */
@@ -2812,18 +2826,20 @@ rt_flowspec_update_rte(rtable *tab, net *n, rte *r)
if (!bc->base_table)
return NULL;
- struct bgp_proto *p = (void *) r->src->proto;
- int valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior);
- int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+ struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, bc->c.proto);
+
+ enum flowspec_valid old = rt_get_flowspec_valid(r),
+ valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior);
- if (dest == r->attrs->dest)
+ if (old == valid)
return NULL;
rta *a = alloca(RTA_MAX_SIZE);
*a = *r->attrs;
- a->dest = dest;
a->cached = 0;
+ ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
+
rte new;
memcpy(&new, r, sizeof(rte));
new.attrs = a;
@@ -2838,18 +2854,23 @@ static inline void
rt_flowspec_resolve_rte(rte *r, struct channel *c)
{
#ifdef CONFIG_BGP
- if (rt_get_source_attr(r) != RTS_BGP)
- return;
-
+ enum flowspec_valid valid, old = rt_get_flowspec_valid(r);
struct bgp_channel *bc = (struct bgp_channel *) c;
- if (!bc->base_table)
- return;
- struct bgp_proto *p = (void *) r->src->proto;
- int valid = rt_flowspec_check(bc->base_table, c->in_req.hook->table, r->net, r->attrs, p->is_interior);
- int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+ if ( (rt_get_source_attr(r) == RTS_BGP)
+ && (c->channel == &channel_bgp)
+ && (bc->base_table))
+ {
+ struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, bc->c.proto);
+ valid = rt_flowspec_check(
+ bc->base_table,
+ c->in_req.hook->table,
+ r->net, r->attrs, p->is_interior);
+ }
+ else
+ valid = FLOWSPEC_UNKNOWN;
- if (dest == r->attrs->dest)
+ if (valid == old)
return;
if (r->attrs->cached)
@@ -2860,7 +2881,10 @@ rt_flowspec_resolve_rte(rte *r, struct channel *c)
r->attrs = a;
}
- r->attrs->dest = dest;
+ if (valid == FLOWSPEC_UNKNOWN)
+ ea_unset_attr(&r->attrs->eattrs, 0, &ea_gen_flowspec_valid);
+ else
+ ea_set_attr_u32(&r->attrs->eattrs, &ea_gen_flowspec_valid, 0, valid);
#endif
}
@@ -3651,7 +3675,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;
@@ -3672,16 +3695,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))
@@ -3694,10 +3713,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->rte);
}
diff --git a/nest/rt.h b/nest/rt.h
index 0ee615b8..eb868aa7 100644
--- a/nest/rt.h
+++ b/nest/rt.h
@@ -148,7 +148,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 */
};
@@ -460,9 +459,6 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr
}
*/
-int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior);
-
-
/*
* Default protocol preferences
*/