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; - if (sa.sa_code == SA_DEST) + nha.ad = (struct adata) { + .length = sizeof (struct nexthop_adata) - sizeof (struct adata), + }; + + 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))); - - a->originated = 1; - a->fresh = 1; } + + 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; } } 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,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); } 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; - switch (a->dest) + struct nexthop_adata *nhad = (void *) ea->u.ptr; + if (NEXTHOP_IS_REACHABLE(nhad)) + return 1; + + 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); } /*