1
0
mirror of https://gitlab.labs.nic.cz/labs/bird.git synced 2024-05-11 16:54:54 +00:00

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.
This commit is contained in:
Maria Matejka
2022-05-15 18:09:30 +02:00
parent 4fe9881d62
commit 950775f6fa
21 changed files with 250 additions and 213 deletions

View File

@@ -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)

View File

@@ -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);
}
/*

View File

@@ -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, },

View File

@@ -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;

View File

@@ -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,25 +2422,26 @@ 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);
return;
}
if (!lnum && he->nexthop_linkable)
{ /* Just link the nexthop chain, no label append happens. */
ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
return;
}
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;
}
uint total_size = OFFSETOF(struct nexthop_adata, nh);
@@ -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 (!head->he->src)
return (a->dest != RTD_UNREACHABLE) ? head : NULL;
eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
/* 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;
return ((a->dest != head->he->dest) ||
struct nexthop_adata *nhad = (struct nexthop_adata *) a_nh_ea->u.ptr;
/* Shortcut for unresolvable hostentry */
if (!head->he->src)
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);
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);
}

View File

@@ -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 */
};