diff options
author | Maria Matejka <mq@ucw.cz> | 2022-06-07 12:18:23 +0200 |
---|---|---|
committer | Maria Matejka <mq@ucw.cz> | 2022-06-07 12:18:25 +0200 |
commit | 8fd3811d9d29d73570e03147eb024a4e5fde199b (patch) | |
tree | 28e0b93138b1c9c5832b377355d2de21cc73b814 | |
parent | ea109ce3e3474dd10d7592c44d2371b794f5c867 (diff) |
Fixing FlowSpec validation for v3 internal API
Validation is called internally from route table at the same place where
nexthop resolution is done. Also accounting for rte->sender semantics
change (not a channel but the import hook instead).
-rw-r--r-- | nest/rt-table.c | 45 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 37 | ||||
-rw-r--r-- | proto/bgp/packets.c | 23 |
3 files changed, 61 insertions, 44 deletions
diff --git a/nest/rt-table.c b/nest/rt-table.c index 8677c177..491ae1d9 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -122,6 +122,7 @@ static void rt_notify_hostcache(rtable *tab, net *net); static void rt_update_hostcache(rtable *tab); static void rt_next_hop_update(rtable *tab); static inline void rt_next_hop_resolve_rte(rte *r); +static inline void rt_flowspec_resolve_rte(rte *r, struct channel *c); static inline void rt_prune_table(rtable *tab); static inline void rt_schedule_notify(rtable *tab); static void rt_flowspec_notify(rtable *tab, net *net); @@ -1570,7 +1571,10 @@ rte_update_direct(struct channel *c, const net_addr *n, rte *new, struct rte_src } if (new) - rt_next_hop_resolve_rte(new); + if (net_is_flow(n)) + rt_flowspec_resolve_rte(new, c); + else + rt_next_hop_resolve_rte(new); if (new && !rte_validate(c, new)) { @@ -2804,7 +2808,7 @@ rt_flowspec_update_rte(rtable *tab, net *n, rte *r) if (rt_get_source_attr(r) != RTS_BGP) return NULL; - struct bgp_channel *bc = (struct bgp_channel *) r->sender; + struct bgp_channel *bc = (struct bgp_channel *) SKIP_BACK(struct channel, in_req, r->sender->req); if (!bc->base_table) return NULL; @@ -2816,7 +2820,7 @@ rt_flowspec_update_rte(rtable *tab, net *n, rte *r) 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; @@ -2830,6 +2834,35 @@ rt_flowspec_update_rte(rtable *tab, net *n, rte *r) #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; + + 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 (dest == r->attrs->dest) + 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; +#endif +} static inline int rt_next_hop_update_net(rtable *tab, net *n) @@ -2861,6 +2894,9 @@ rt_next_hop_update_net(rtable *tab, net *n) ? rt_flowspec_update_rte(tab, n, &e->rte) : rt_next_hop_update_rte(tab, n, &e->rte); + if (!new) + continue; + /* Call a pre-comparison hook */ /* Not really an efficient way to compute this */ if (e->rte.src->proto->rte_recalculate) @@ -2876,7 +2912,8 @@ rt_next_hop_update_net(rtable *tab, net *n) *k = e = new; } - ASSERT_DIE(pos == count); + ASSERT_DIE(pos <= count); + count = pos; /* Find the new best route */ struct rte_storage **new_best = NULL; diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 11b1c728..ccfda4df 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -2390,25 +2390,28 @@ bgp_get_route_info(rte *e, byte *buf) buf += bsprintf(buf, " (%d", rt_get_preference(e)); - if (e->pflags & BGP_REF_SUPPRESSED) - buf += bsprintf(buf, "-"); + if (!net_is_flow(e->net)) + { + if (e->pflags & BGP_REF_SUPPRESSED) + buf += bsprintf(buf, "-"); - if (rte_stale(e)) - buf += bsprintf(buf, "s"); + if (rte_stale(e)) + buf += bsprintf(buf, "s"); - u64 metric = bgp_total_aigp_metric(e); - if (metric < BGP_AIGP_MAX) - { - buf += bsprintf(buf, "/%lu", metric); - } - else if (metric = rt_get_igp_metric(e)) - { - if (!rta_resolvable(e->attrs)) - buf += bsprintf(buf, "/-"); - else if (metric >= IGP_METRIC_UNKNOWN) - buf += bsprintf(buf, "/?"); - else - buf += bsprintf(buf, "/%d", metric); + u64 metric = bgp_total_aigp_metric(e); + if (metric < BGP_AIGP_MAX) + { + buf += bsprintf(buf, "/%lu", metric); + } + else if (metric = rt_get_igp_metric(e)) + { + if (!rta_resolvable(e->attrs)) + buf += bsprintf(buf, "/-"); + else if (metric >= IGP_METRIC_UNKNOWN) + buf += bsprintf(buf, "/?"); + else + buf += bsprintf(buf, "/%d", metric); + } } buf += bsprintf(buf, ") ["); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index ce2848c0..06b563b0 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -1035,21 +1035,6 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 lnum, u32 labels[ln } } -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; - - /* Invalidate cached rta if dest changes */ - if (s->cached_rta && (s->cached_rta->dest != a->dest)) - { - rta_free(s->cached_rta); - s->cached_rta = NULL; - } -} - static int bgp_match_src(struct bgp_export_state *s, int mode) { @@ -1928,10 +1913,6 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a) net_fill_flow4(n, px, pxlen, pos, flen); ADVANCE(pos, len, flen); - /* Apply validation procedure per RFC 8955 (6) */ - if (a && s->channel->cf->validate) - bgp_apply_flow_validation(s, n, a); - bgp_rte_update(s, n, path_id, a); } } @@ -2020,10 +2001,6 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a) net_fill_flow6(n, px, pxlen, pos, flen); ADVANCE(pos, len, flen); - /* Apply validation procedure per RFC 8955 (6) */ - if (a && s->channel->cf->validate) - bgp_apply_flow_validation(s, n, a); - bgp_rte_update(s, n, path_id, a); } } |