For add-path send the Adj-RIB-Out needs to handle multiple paths per
authorclaudio <claudio@openbsd.org>
Fri, 25 Feb 2022 11:36:54 +0000 (11:36 +0000)
committerclaudio <claudio@openbsd.org>
Fri, 25 Feb 2022 11:36:54 +0000 (11:36 +0000)
prefix. For this extend the RB trees of the Adj-RIB-Out to also consider
the path_id. Add functions to lookup a prefix without path_id so that
bgpctl works. Rename functions so that all Adj-RIB-Out specific functions
start with prefix_adjout_

For now the path_id_tx in the Adj-RIB-Out is forced to 0 since
up_generate_updates() is not ready to handle more than one path per prefix.

OK tb@

usr.sbin/bgpd/rde.c
usr.sbin/bgpd/rde.h
usr.sbin/bgpd/rde_rib.c

index 6d2e9a4..6247e0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.535 2022/02/24 14:54:03 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.536 2022/02/25 11:36:54 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -2728,12 +2728,16 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
 
                        do {
                                if (req->prefixlen == hostplen)
-                                       p = prefix_match(peer, &req->prefix);
+                                       p = prefix_adjout_match(peer,
+                                           &req->prefix);
                                else
-                                       p = prefix_lookup(peer, &req->prefix,
-                                           req->prefixlen);
-                               if (p)
+                                       p = prefix_adjout_lookup(peer,
+                                           &req->prefix, req->prefixlen);
+                               /* dump all matching paths */
+                               while (p != NULL) {
                                        rde_dump_adjout_upcall(p, ctx);
+                                       p = prefix_adjout_next(peer, p);
+                               };
                        } while ((peer = peer_match(&req->neighbor,
                            peer->conf.id)));
 
index ebc1f32..ef7b733 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.h,v 1.243 2022/02/06 09:51:19 claudio Exp $ */
+/*     $OpenBSD: rde.h,v 1.244 2022/02/25 11:36:54 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -582,8 +582,13 @@ void                path_put(struct rde_aspath *);
 #define        PREFIX_SIZE(x)  (((x) + 7) / 8 + 1)
 struct prefix  *prefix_get(struct rib *, struct rde_peer *, uint32_t,
                    struct bgpd_addr *, int);
-struct prefix  *prefix_lookup(struct rde_peer *, struct bgpd_addr *, int);
+struct prefix  *prefix_adjout_get(struct rde_peer *, uint32_t,
+                   struct bgpd_addr *, int);
 struct prefix  *prefix_match(struct rde_peer *, struct bgpd_addr *);
+struct prefix  *prefix_adjout_match(struct rde_peer *, struct bgpd_addr *);
+struct prefix  *prefix_adjout_lookup(struct rde_peer *, struct bgpd_addr *,
+                    int);
+struct prefix  *prefix_adjout_next(struct rde_peer *, struct prefix *);
 int             prefix_update(struct rib *, struct rde_peer *, uint32_t,
                     struct filterstate *, struct bgpd_addr *, int, uint8_t);
 int             prefix_withdraw(struct rib *, struct rde_peer *, uint32_t,
index d1ac386..837aef4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde_rib.c,v 1.225 2022/02/06 09:51:19 claudio Exp $ */
+/*     $OpenBSD: rde_rib.c,v 1.226 2022/02/25 11:36:54 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -859,6 +859,21 @@ static struct prefix       *prefix_alloc(void);
 static void             prefix_free(struct prefix *);
 
 /* RB tree comparison function */
+static inline int
+prefix_index_cmp(struct prefix *a, struct prefix *b)
+{
+       int r;
+       r = pt_prefix_cmp(a->pt, b->pt);
+       if (r != 0)
+               return r;
+
+       if (a->path_id_tx > b->path_id_tx)
+               return 1;
+       if (a->path_id_tx < b->path_id_tx)
+               return -1;
+       return 0;
+}
+
 static inline int
 prefix_cmp(struct prefix *a, struct prefix *b)
 {
@@ -876,22 +891,14 @@ prefix_cmp(struct prefix *a, struct prefix *b)
                return (a->nexthop > b->nexthop ? 1 : -1);
        if (a->nhflags != b->nhflags)
                return (a->nhflags > b->nhflags ? 1 : -1);
-       /* XXX path_id ??? */
-       return pt_prefix_cmp(a->pt, b->pt);
-}
-
-static inline int
-prefix_index_cmp(struct prefix *a, struct prefix *b)
-{
-       /* XXX path_id ??? */
-       return pt_prefix_cmp(a->pt, b->pt);
+       return prefix_index_cmp(a, b);
 }
 
 RB_GENERATE(prefix_tree, prefix, entry.tree.update, prefix_cmp)
 RB_GENERATE_STATIC(prefix_index, prefix, entry.tree.index, prefix_index_cmp)
 
 /*
- * search for specified prefix of a peer. Returns NULL if not found.
+ * Search for specified prefix of a peer. Returns NULL if not found.
  */
 struct prefix *
 prefix_get(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
@@ -906,11 +913,12 @@ prefix_get(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
 }
 
 /*
- * lookup prefix in the peer prefix_index. Returns NULL if not found.
+ * Search for specified prefix in the peer prefix_index.
+ * Returns NULL if not found.
  */
 struct prefix *
-prefix_lookup(struct rde_peer *peer, struct bgpd_addr *prefix,
-    int prefixlen)
+prefix_adjout_get(struct rde_peer *peer, uint32_t path_id,
+    struct bgpd_addr *prefix, int prefixlen)
 {
        struct prefix xp;
        struct pt_entry *pte;
@@ -918,12 +926,49 @@ prefix_lookup(struct rde_peer *peer, struct bgpd_addr *prefix,
        memset(&xp, 0, sizeof(xp));
        pte = pt_fill(prefix, prefixlen);
        xp.pt = pte;
+       xp.path_id_tx = path_id;
 
        return RB_FIND(prefix_index, &peer->adj_rib_out, &xp);
 }
 
+/*
+ * Lookup a prefix without considering path_id in the peer prefix_index.
+ * Returns NULL if not found.
+ */
+struct prefix *
+prefix_adjout_lookup(struct rde_peer *peer, struct bgpd_addr *prefix,
+    int prefixlen)
+{
+       struct prefix xp, *np;
+       struct pt_entry *pte;
+
+       memset(&xp, 0, sizeof(xp));
+       pte = pt_fill(prefix, prefixlen);
+       xp.pt = pte;
+
+       np = RB_NFIND(prefix_index, &peer->adj_rib_out, &xp);
+       if (np != NULL && pt_prefix_cmp(np->pt, xp.pt) != 0)
+               return NULL;
+       return np;
+}
+
+struct prefix *
+prefix_adjout_next(struct rde_peer *peer, struct prefix *p)
+{
+       struct prefix *np;
+
+       np = RB_NEXT(prefix_index, &peer->adj_rib_out, p);
+       if (np == NULL || p->pt != np->pt)
+               return NULL;
+       return np;
+}
+
+/*
+ * Lookup addr in the peer prefix_index. Returns first match.
+ * Returns NULL if not found.
+ */
 struct prefix *
-prefix_match(struct rde_peer *peer, struct bgpd_addr *addr)
+prefix_adjout_match(struct rde_peer *peer, struct bgpd_addr *addr)
 {
        struct prefix *p;
        int i;
@@ -932,7 +977,7 @@ prefix_match(struct rde_peer *peer, struct bgpd_addr *addr)
        case AID_INET:
        case AID_VPN_IPv4:
                for (i = 32; i >= 0; i--) {
-                       p = prefix_lookup(peer, addr, i);
+                       p = prefix_adjout_lookup(peer, addr, i);
                        if (p != NULL)
                                return p;
                }
@@ -940,7 +985,7 @@ prefix_match(struct rde_peer *peer, struct bgpd_addr *addr)
        case AID_INET6:
        case AID_VPN_IPv6:
                for (i = 128; i >= 0; i--) {
-                       p = prefix_lookup(peer, addr, i);
+                       p = prefix_adjout_lookup(peer, addr, i);
                        if (p != NULL)
                                return p;
                }
@@ -1143,7 +1188,7 @@ prefix_adjout_update(struct rde_peer *peer, struct filterstate *state,
        struct prefix *p;
        int created = 0;
 
-       if ((p = prefix_lookup(peer, prefix, prefixlen)) != NULL) {
+       if ((p = prefix_adjout_get(peer, 0, prefix, prefixlen)) != NULL) {
                if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
                        fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit",
                            __func__);
@@ -1192,6 +1237,7 @@ prefix_adjout_update(struct rde_peer *peer, struct filterstate *state,
                        p->pt = pt_add(prefix, prefixlen);
                pt_ref(p->pt);
                p->peer = peer;
+               p->path_id_tx = 0 /* XXX force this for now */;
 
                if (RB_INSERT(prefix_index, &peer->adj_rib_out, p) != NULL)
                        fatalx("%s: RB index invariant violated", __func__);
@@ -1235,7 +1281,7 @@ prefix_adjout_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
 {
        struct prefix *p;
 
-       p = prefix_lookup(peer, prefix, prefixlen);
+       p = prefix_adjout_get(peer, 0, prefix, prefixlen);
        if (p == NULL)          /* Got a dummy withdrawn request. */
                return (0);