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);
 }
 
 /*

Reply via email to