From: Maria Matejka Date: Wed, 8 Jun 2022 09:47:49 +0000 (+0200) Subject: Merge commit '950775f6fa3d569a9d7cd05e33538d35e895d688' into haugesund X-Git-Tag: v3.0-alpha1~107^2~2^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cae5979871ee7aa341334f8b1af6bafc60ee9692;p=thirdparty%2Fbird.git 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. --- cae5979871ee7aa341334f8b1af6bafc60ee9692 diff --cc filter/f-inst.c index b276387fe,c2abd5aa4..1690c9f64 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@@ -533,14 -533,13 +533,13 @@@ 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_NET: RESULT(sa.type, net, fs->rte->net); 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) { diff --cc lib/route.h index 613df0c38,1d8877c80..283a3760d --- a/lib/route.h +++ b/lib/route.h @@@ -330,9 -331,18 +333,25 @@@ extern struct ea_class ea_gen_from /* Source: An old method to devise the route source protocol and kind. * To be superseded in a near future by something more informative. */ extern struct ea_class ea_gen_source; -static inline u32 rt_get_source_attr(rte *rt) +static inline u32 rt_get_source_attr(const 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 ++enum flowspec_valid { ++ FLOWSPEC_UNKNOWN = 0, ++ FLOWSPEC_VALID = 1, ++ FLOWSPEC_INVALID = 2, ++ FLOWSPEC__MAX, ++}; ++ ++extern const char * flowspec_valid_names[FLOWSPEC__MAX]; ++static inline const char *flowspec_valid_name(enum flowspec_valid v) ++{ return (v < FLOWSPEC__MAX) ? flowspec_valid_names[v] : "???"; } + + extern struct ea_class ea_gen_flowspec_valid; -static inline u32 rt_get_flowspec_valid(rte *rt) ++static inline enum flowspec_valid 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; @@@ -361,7 -377,35 +386,35 @@@ struct nexthop_adata *nexthop_merge(str 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) ++static inline int rte_dest(const rte *r) + { + return nhea_dest(ea_find(r->attrs->eattrs, &ea_gen_nexthop)); + } void rta_init(void); #define rta_size(...) (sizeof(rta)) diff --cc nest/rt-attr.c index cf3ab659d,b5be936ba..f548a575b --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@@ -166,6 -166,12 +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; diff --cc nest/rt-show.c index 6cfd99fcc,0ad8f5c64..cc5a9a101 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@@ -45,8 -45,9 +45,11 @@@ rt_show_rte(struct cli *c, byte *ia, rt 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 = NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest; ++ 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 -69,10 +71,11 @@@ 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); ++ 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 --cc nest/rt-table.c index 491ae1d9b,539e04d01..946f4021c --- a/nest/rt-table.c +++ b/nest/rt-table.c @@@ -679,11 -695,11 +679,11 @@@ rte_mergable(rte *pri, rte *sec } static void -rte_trace(struct channel *c, rte *e, int dir, char *msg) +rte_trace(const char *name, const rte *e, int dir, const 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, + 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,30 -1177,21 +1226,30 @@@ rte_validate(struct channel *ch, rte *e return 0; } - if (net_type_match(n, NB_DEST) == !e->attrs->dest) - eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop); - int dest = nhea_dest(nhea); - - if (net_type_match(n->n.addr, NB_DEST) == !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; - log(L_WARN "Ignoring route %N with invalid dest %d received via %s", - n->n.addr, dest, e->sender->proto->name); - return 0; - } ++ 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)) ++ 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", - n->n.addr, e->sender->proto->name); ++ log(L_WARN "Ignoring route %N having a nexthop attribute received via %s", + n, ch->proto->name); return 0; } @@@ -2722,7 -2594,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 -2603,11 +2745,11 @@@ /* 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 -2629,7 +2771,7 @@@ /* 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 -2640,17 +2782,17 @@@ 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) @@@ -2787,16 -2659,16 +2801,16 @@@ if (!nc) continue; - rte *rc = nc->routes; + 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,57 -2684,29 +2826,67 @@@ rt_flowspec_update_rte(rtable *tab, ne if (!bc->base_table) return NULL; - 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->n.addr, r->attrs, p->is_interior); - int dest = valid ? RTD_NONE : RTD_UNREACHABLE; - int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior); - int old = rt_get_flowspec_valid(r); ++ 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); - memcpy(a, r->attrs, rta_size(r->attrs)); + *a = *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); + rte new; + memcpy(&new, r, sizeof(rte)); + new.attrs = a; - return new; + return rte_store(&new, n, tab); #else return NULL; #endif } +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) + { + rta *a = tmp_alloc(RTA_MAX_SIZE); + *a = *r->attrs; + a->cached = 0; + 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 +} static inline int rt_next_hop_update_net(rtable *tab, net *n) @@@ -3694,12 -3567,10 +3713,10 @@@ rt_update_hostentry(rtable *tab, struc direct++; } - } he->src = rta_clone(a); - he->dest = a->dest; he->nexthop_linkable = !direct; - he->igp_metric = rt_get_igp_metric(e); + he->igp_metric = rt_get_igp_metric(&e->rte); } done: diff --cc nest/rt.h index 0ee615b8a,6f15fec69..eb868aa76 --- a/nest/rt.h +++ b/nest/rt.h @@@ -460,9 -301,9 +459,6 @@@ rta_set_recursive_next_hop(rtable *dep } */ --int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior); -- -- /* * Default protocol preferences */ diff --cc proto/babel/babel.c index f3456369a,b90dcd3f5..65d2567e6 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@@ -677,18 -677,13 +677,15 @@@ babel_announce_rte(struct babel_proto * } }; - 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); + rte e0 = { + .attrs = &a0, + .src = p->p.main_source, + }; e->unreachable = 0; - rte_update2(c, e->n.addr, rte, p->p.main_source); + rte_update(c, e->n.addr, &e0, p->p.main_source); } else if (e->valid && (e->router_id != p->router_id)) { @@@ -699,14 -692,14 +694,15 @@@ 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); - rte->pflags = 0; + rte e0 = { + .attrs = &a0, + .src = p->p.main_source, + }; e->unreachable = 1; - rte_update2(c, e->n.addr, rte, p->p.main_source); + rte_update(c, e->n.addr, &e0, p->p.main_source); } else { @@@ -2264,11 -2257,15 +2260,15 @@@ babel_kick_timer(struct babel_proto *p static int -babel_preexport(struct proto *P, struct rte *new) +babel_preexport(struct channel *c, struct rte *new) { - struct rta *a = new->attrs; - if (new->src->proto != P) ++ if (new->src->proto != c->proto) + return 0; + /* Reject our own unreachable routes */ - if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto)) + 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 --cc proto/bgp/attrs.c index ccfda4df9,6a9e4026c..0b715eaa6 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@@ -1714,9 -1711,20 +1714,21 @@@ bgp_preexport(struct channel *c, rte *e if (src == NULL) return 0; - /* Reject flowspec that failed or are pending validation */ - if (net_is_flow(e->net->n.addr)) + /* Reject flowspec that failed validation */ - if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net)) - return -1; ++ if (net_is_flow(e->net)) + 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; ++ ASSUME((rt_get_source_attr(e) != RTS_BGP) || ++ !((struct bgp_channel *) SKIP_BACK(struct channel, in_req, e->sender->req))->base_table); + break; ++ case FLOWSPEC__MAX: ++ bug("This never happens."); + } /* IBGP route reflection, RFC 4456 */ if (p->is_internal && src->is_internal && (p->local_as == src->local_as)) diff --cc proto/bgp/bgp.h index 8e3ed70e8,2f98dc1b5..662d9d48a --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@@ -517,9 -517,11 +517,11 @@@ struct rte_source *bgp_find_source(stru struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id); static inline int -rte_resolvable(rte *rt) +rta_resolvable(rta *a) { - return a->dest != RTD_UNREACHABLE; - eattr *nhea = ea_find(rt->attrs->eattrs, &ea_gen_nexthop); ++ eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop); + struct nexthop_adata *nhad = (void *) nhea->u.ptr; + return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE); } diff --cc proto/ospf/topology.c index c2b12cfc4,09ec9f282..6ff6a7457 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@@ -1366,20 -1366,13 +1366,11 @@@ ospf_rt_notify(struct proto *P, struct 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) - { - log(L_ERR "%s: Unicast route without nexthop for %N", - p->p.name, n); - return; - } - - struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr; + eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop); - if (nhea) - { - struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr; ++ struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr; ++ if (NEXTHOP_IS_REACHABLE(nhad)) if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface)) fwd = nhad->nh.gw; -- } /* NSSA-LSA with P-bit set must have non-zero forwarding address */ if (oa && ipa_zero(fwd)) diff --cc sysdep/linux/netlink.c index e63fe9382,40f6212ec..a4172a6d4 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@@ -1900,11 -1908,9 +1907,9 @@@ nl_parse_route(struct nl_parse_state *s 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); + struct nexthop_adata *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src); if (!nh) SKIP("strange RTA_MULTIPATH\n");