With this diffs all the bits I committed before are connected and allow for flowspec to be announced to other systems.
I first thought I will put the flowspec_valid() inside flowspec_add() but I changed my mind now and moved it into the imsg handler. flowspec_add() and flowspec_delete() are built a bit like network_add/_delete but use their own special prefix functions. This is because I did not want to implement all of Adj-RIB-In and Loc-RIB handling just yet. All flowspec prefixes are stored in a static RIB tree (flowrib) and this is used to push them into Adj-RIB-Out. This is for sure a hack but is right now the smallest way to move forward without rebuilding a lot of code on the input side. The introduction of flowrib requries a change in one of the regress tests. I have a diff for that ready. -- :wq Claudio Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.602 diff -u -p -r1.602 rde.c --- rde.c 19 Apr 2023 07:12:22 -0000 1.602 +++ rde.c 19 Apr 2023 10:23:56 -0000 @@ -859,7 +859,13 @@ rde_dispatch_imsg_parent(struct imsgbuf 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 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 */ Index: rde.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v retrieving revision 1.292 diff -u -p -r1.292 rde.h --- rde.h 19 Apr 2023 07:09:47 -0000 1.292 +++ rde.h 19 Apr 2023 10:16:23 -0000 @@ -567,9 +567,14 @@ int rib_dump_subtree(uint16_t, struct 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 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); Index: rde_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v retrieving revision 1.134 diff -u -p -r1.134 rde_filter.c --- rde_filter.c 10 Mar 2023 07:57:15 -0000 1.134 +++ rde_filter.c 19 Apr 2023 10:16:23 -0000 @@ -834,6 +834,9 @@ rde_filter(struct filter_head *rules, st 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( Index: rde_peer.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v retrieving revision 1.31 diff -u -p -r1.31 rde_peer.c --- rde_peer.c 10 Mar 2023 07:57:16 -0000 1.31 +++ rde_peer.c 19 Apr 2023 10:16:23 -0000 @@ -562,6 +562,9 @@ peer_dump(struct rde_peer *peer, uint8_t } 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) Index: rde_rib.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v retrieving revision 1.258 diff -u -p -r1.258 rde_rib.c --- rde_rib.c 7 Apr 2023 13:49:03 -0000 1.258 +++ rde_rib.c 19 Apr 2023 10:16:23 -0000 @@ -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 *, @@ -1115,6 +1116,91 @@ prefix_withdraw(struct rib *rib, struct prefix_destroy(p); 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); } /*