From dd2a9ed2eb56190eca8c323c177ef4d3b11f60bd Mon Sep 17 00:00:00 2001 From: claudio Date: Wed, 19 Apr 2023 13:23:33 +0000 Subject: [PATCH] Implement a way to announce flowspec rules without hitting Adj-RIB-In and Loc-RIB. Flowspec objects are collected in a single flowrib RIB and then directly distributed into the various Adj-RIB-Outs. For this to work add a bypass in the filter logic (flowspec AFI/SAFI are currently accepted without any rule). The filter language lacks a way to allow prefixes based on AFI/SAFI which is the minimum needed. OK tb@ --- usr.sbin/bgpd/rde.c | 38 ++++++++++++++-- usr.sbin/bgpd/rde.h | 13 +++++- usr.sbin/bgpd/rde_filter.c | 5 ++- usr.sbin/bgpd/rde_peer.c | 5 ++- usr.sbin/bgpd/rde_rib.c | 88 +++++++++++++++++++++++++++++++++++++- 5 files changed, 142 insertions(+), 7 deletions(-) diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 343126e66da..f71218a4042 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.602 2023/04/19 07:12:22 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.603 2023/04/19 13:23:33 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -859,7 +859,13 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH | F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED; - flowspec_add(curflow, &state, &parent_set); + if (flowspec_valid(curflow->data, curflow->len, + curflow->aid == AID_FLOWSPECv6) == -1) + log_warnx("invalid flowspec update received " + "from parent"); + else + flowspec_add(curflow, &state, &parent_set); + rde_filterstate_clean(&state); filterset_free(&parent_set); free(curflow); @@ -887,7 +893,12 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) log_warnx("rde_dispatch: wrong flowspec len"); break; } - flowspec_delete(curflow); + if (flowspec_valid(curflow->data, curflow->len, + curflow->aid == AID_FLOWSPECv6) == -1) + log_warnx("invalid flowspec withdraw received " + "from parent"); + else + flowspec_delete(curflow); free(curflow); curflow = NULL; break; @@ -4570,11 +4581,32 @@ void flowspec_add(struct flowspec *f, struct filterstate *state, struct filter_set_head *attrset) { + struct pt_entry *pte; + uint32_t path_id_tx; + + rde_apply_set(attrset, peerself, peerself, state, f->aid); + rde_filterstate_set_vstate(state, ROA_NOTFOUND, ASPA_NEVER_KNOWN); + path_id_tx = peerself->path_id_tx; /* XXX should use pathid_assign() */ + + pte = pt_get_flow(f); + if (pte == NULL) + pte = pt_add_flow(f); + + if (prefix_flowspec_update(peerself, state, pte, path_id_tx) == 1) + peerself->stats.prefix_cnt++; } void flowspec_delete(struct flowspec *f) { + struct pt_entry *pte; + + pte = pt_get_flow(f); + if (pte == NULL) + return; + + if (prefix_flowspec_withdraw(peerself, pte) == 1) + peerself->stats.prefix_cnt--; } /* clean up */ diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 7660312d275..1ed3e15d276 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.292 2023/04/19 07:09:47 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.293 2023/04/19 13:23:33 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -567,9 +567,14 @@ int rib_dump_subtree(uint16_t, struct bgpd_addr *, uint8_t, int (*)(void *)); void rib_dump_terminate(void *); +extern struct rib flowrib; + static inline struct rib * re_rib(struct rib_entry *re) { + if (re->prefix->aid == AID_FLOWSPECv4 || + re->prefix->aid == AID_FLOWSPECv6) + return &flowrib; return rib_byid(re->rib_id); } @@ -596,6 +601,12 @@ int prefix_update(struct rib *, struct rde_peer *, uint32_t, uint32_t, struct filterstate *, struct bgpd_addr *, int); int prefix_withdraw(struct rib *, struct rde_peer *, uint32_t, struct bgpd_addr *, int); +int prefix_flowspec_update(struct rde_peer *, struct filterstate *, + struct pt_entry *, uint32_t); +int prefix_flowspec_withdraw(struct rde_peer *, struct pt_entry *); +void prefix_flowspec_dump(uint8_t, void *, + void (*)(struct rib_entry *, void *), + void (*)(void *, uint8_t)); void prefix_add_eor(struct rde_peer *, uint8_t); void prefix_adjout_update(struct prefix *, struct rde_peer *, struct filterstate *, struct pt_entry *, uint32_t); diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c index e8871b8bd37..4c0b570079d 100644 --- a/usr.sbin/bgpd/rde_filter.c +++ b/usr.sbin/bgpd/rde_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_filter.c,v 1.134 2023/03/10 07:57:15 claudio Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.135 2023/04/19 13:23:33 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -834,6 +834,9 @@ rde_filter(struct filter_head *rules, struct rde_peer *peer, if (rules == NULL) return (action); + if (prefix->aid == AID_FLOWSPECv4 || prefix->aid == AID_FLOWSPECv6) + return (ACTION_ALLOW); + f = TAILQ_FIRST(rules); while (f != NULL) { RDE_FILTER_TEST_ATTRIB( diff --git a/usr.sbin/bgpd/rde_peer.c b/usr.sbin/bgpd/rde_peer.c index 9248851c1d6..bbf0a9e0ec9 100644 --- a/usr.sbin/bgpd/rde_peer.c +++ b/usr.sbin/bgpd/rde_peer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_peer.c,v 1.31 2023/03/10 07:57:16 claudio Exp $ */ +/* $OpenBSD: rde_peer.c,v 1.32 2023/04/19 13:23:33 claudio Exp $ */ /* * Copyright (c) 2019 Claudio Jeker @@ -562,6 +562,9 @@ peer_dump(struct rde_peer *peer, uint8_t aid) } else if (peer->export_type == EXPORT_DEFAULT_ROUTE) { up_generate_default(peer, aid); rde_up_dump_done(peer, aid); + } else if (aid == AID_FLOWSPECv4 || aid == AID_FLOWSPECv6) { + prefix_flowspec_dump(aid, peer, rde_up_dump_upcall, + rde_up_dump_done); } else { if (rib_dump_new(peer->loc_rib_id, aid, RDE_RUNNER_ROUNDS, peer, rde_up_dump_upcall, rde_up_dump_done, NULL) == -1) diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index 3aa355bfc23..f04c2519647 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.258 2023/04/07 13:49:03 claudio Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.259 2023/04/19 13:23:33 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -37,6 +37,7 @@ */ uint16_t rib_size; struct rib **ribs; +struct rib flowrib = { .id = 1, .tree = RB_INITIALIZER(&flowrib.tree) }; struct rib_entry *rib_add(struct rib *, struct pt_entry *); static inline int rib_compare(const struct rib_entry *, @@ -1117,6 +1118,91 @@ prefix_withdraw(struct rib *rib, struct rde_peer *peer, uint32_t path_id, return (1); } +/* + * Special functions for flowspec until full integration is available. + * This just directly feeds the prefixes into the Adj-RIB-Out bypassing + * Adj-RIB-In and Loc-RIB for now. + */ +int +prefix_flowspec_update(struct rde_peer *peer, struct filterstate *state, + struct pt_entry *pte, uint32_t path_id_tx) +{ + struct rde_aspath *asp, *nasp; + struct rde_community *comm, *ncomm; + struct rib_entry *re; + struct prefix *new, *old; + + re = rib_get(&flowrib, pte); + if (re == NULL) + re = rib_add(&flowrib, pte); + + old = prefix_bypeer(re, peer, 0); + new = prefix_alloc(); + + nasp = &state->aspath; + ncomm = &state->communities; + if ((asp = path_lookup(nasp)) == NULL) { + /* Path not available, create and link a new one. */ + asp = path_copy(path_get(), nasp); + path_link(asp); + } + if ((comm = communities_lookup(ncomm)) == NULL) { + /* Communities not available, create and link a new one. */ + comm = communities_link(ncomm); + } + + prefix_link(new, re, re->prefix, peer, 0, path_id_tx, asp, comm, + NULL, 0, 0); + TAILQ_INSERT_HEAD(&re->prefix_h, new, entry.list.rib); + + rde_generate_updates(re, new, old, EVAL_DEFAULT); + + if (old != NULL) { + TAILQ_REMOVE(&re->prefix_h, old, entry.list.rib); + prefix_unlink(old); + prefix_free(old); + return 0; + } + return 1; +} + +/* + * Remove a possible flowspec prefix from all Adj-RIB-Outs. + */ +int +prefix_flowspec_withdraw(struct rde_peer *peer, struct pt_entry *pte) +{ + struct rib_entry *re; + struct prefix *p; + + re = rib_get(&flowrib, pte); + if (re == NULL) + return 0; + p = prefix_bypeer(re, peer, 0); + if (p == NULL) + return 0; + rde_generate_updates(re, NULL, p, EVAL_DEFAULT); + TAILQ_REMOVE(&re->prefix_h, p, entry.list.rib); + prefix_unlink(p); + prefix_free(p); + return 1; +} + +/* + * Push all flowspec rules into a newly available Adj-RIB-Out. + */ +void +prefix_flowspec_dump(uint8_t aid, void *arg, + void (*call)(struct rib_entry *, void *), void (*done)(void *, uint8_t)) +{ + struct rib_entry *re, *next; + + RB_FOREACH_SAFE(re, rib_tree, rib_tree(&flowrib), next) + call(re, arg); + if (done != NULL) + done(arg, aid); +} + /* * Insert an End-of-RIB marker into the update queue. */ -- 2.20.1